[Kernel] Fix running import library entrypoints via new XThread param
This is fixed by adding a new startup_type parameter to XThread, which lets us create an XThread that can run DllMain with correct arguments. LaunchModule is then modified to use that param when launching a DLL module that has an entrypoint. UserModule::LoadXexContinue also has code added to call SetExecutableModule prior to loading any import libraries
This commit is contained in:
parent
7df678d2c5
commit
5b7c67fe71
|
@ -486,8 +486,6 @@ int XexModule::ReadImage(const void* xex_addr, size_t xex_length,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
memory()->LookupHeap(base_address_)->Reset();
|
|
||||||
|
|
||||||
aes_decrypt_buffer(
|
aes_decrypt_buffer(
|
||||||
use_dev_key ? xe_xex2_devkit_key : xe_xex2_retail_key,
|
use_dev_key ? xe_xex2_devkit_key : xe_xex2_retail_key,
|
||||||
reinterpret_cast<const uint8_t*>(xex_security_info()->aes_key), 16,
|
reinterpret_cast<const uint8_t*>(xex_security_info()->aes_key), 16,
|
||||||
|
|
|
@ -239,29 +239,43 @@ object_ref<XThread> KernelState::LaunchModule(object_ref<UserModule> module) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetExecutableModule(module);
|
XELOGI("KernelState: Launching module %s...", module->path().c_str());
|
||||||
XELOGI("KernelState: Launching module...");
|
|
||||||
|
|
||||||
// Create a thread to run in.
|
// Create a thread to run in.
|
||||||
// We start suspended so we can run the debugger prep.
|
// We start suspended so we can run the debugger prep.
|
||||||
auto thread = object_ref<XThread>(
|
xe::kernel::object_ref<XThread> thread = nullptr;
|
||||||
new XThread(kernel_state(), module->stack_size(), 0,
|
|
||||||
module->entry_point(), 0, X_CREATE_SUSPENDED, true, true));
|
|
||||||
|
|
||||||
// We know this is the 'main thread'.
|
if (!module->is_dll_module()) {
|
||||||
|
// Not a DLL module, run entrypoint as normal
|
||||||
|
thread = object_ref<XThread>(new XThread(
|
||||||
|
kernel_state(), module->stack_size(), XThread::StartupType::Normal, 0,
|
||||||
|
module->entry_point(), 0, X_CREATE_SUSPENDED, true, true));
|
||||||
|
} else {
|
||||||
|
// Run entrypoint as DllMain, using module handle as start context
|
||||||
|
thread = object_ref<XThread>(
|
||||||
|
new XThread(kernel_state(), module->stack_size(),
|
||||||
|
XThread::StartupType::DllMain, 0, module->entry_point(),
|
||||||
|
module->handle(), X_CREATE_SUSPENDED, true, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We know this is the 'main thread', or '<dllname> thread'
|
||||||
char thread_name[32];
|
char thread_name[32];
|
||||||
std::snprintf(thread_name, xe::countof(thread_name), "Main XThread%08X",
|
std::snprintf(thread_name, xe::countof(thread_name), "%s XThread%08X",
|
||||||
|
module->is_dll_module() ? module->name().c_str() : "Main",
|
||||||
thread->handle());
|
thread->handle());
|
||||||
thread->set_name(thread_name);
|
thread->set_name(thread_name);
|
||||||
|
|
||||||
X_STATUS result = thread->Create();
|
X_STATUS result = thread->Create();
|
||||||
if (XFAILED(result)) {
|
if (XFAILED(result)) {
|
||||||
XELOGE("Could not create launch thread: %.8X", result);
|
XELOGE("Could not create launch thread for %s: %.8X",
|
||||||
|
module->path().c_str(), result);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Waits for a debugger client, if desired.
|
// Waits for a debugger client, if desired.
|
||||||
emulator()->processor()->PreLaunch();
|
if (!module->is_dll_module()) {
|
||||||
|
emulator()->processor()->PreLaunch();
|
||||||
|
}
|
||||||
|
|
||||||
// Resume the thread now.
|
// Resume the thread now.
|
||||||
// If the debugger has requested a suspend this will just decrement the
|
// If the debugger has requested a suspend this will just decrement the
|
||||||
|
@ -380,23 +394,8 @@ object_ref<UserModule> KernelState::LoadUserModule(const char* raw_name,
|
||||||
|
|
||||||
// Module wasn't loaded, so load it.
|
// Module wasn't loaded, so load it.
|
||||||
module = object_ref<UserModule>(new UserModule(this));
|
module = object_ref<UserModule>(new UserModule(this));
|
||||||
if (!executable_module_) {
|
|
||||||
// If there isn't already an executable_module then this must be the one
|
|
||||||
// Set it before loading so that extra modules loaded during this
|
|
||||||
// module load (import libs..) can access it
|
|
||||||
|
|
||||||
// (we don't use SetExecutableModule because that sets up a lot of other
|
|
||||||
// things, we can call that after the load via LaunchModule instead)
|
|
||||||
|
|
||||||
executable_module_ = module;
|
|
||||||
}
|
|
||||||
|
|
||||||
X_STATUS status = module->LoadFromFile(path);
|
X_STATUS status = module->LoadFromFile(path);
|
||||||
if (XFAILED(status)) {
|
if (XFAILED(status)) {
|
||||||
if (executable_module_.get() == module.get()) {
|
|
||||||
executable_module_.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
object_table()->RemoveHandle(module->handle());
|
object_table()->RemoveHandle(module->handle());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -411,16 +410,7 @@ object_ref<UserModule> KernelState::LoadUserModule(const char* raw_name,
|
||||||
module->Dump();
|
module->Dump();
|
||||||
|
|
||||||
if (module->is_dll_module() && module->entry_point() && call_entry) {
|
if (module->is_dll_module() && module->entry_point() && call_entry) {
|
||||||
// Call DllMain(DLL_PROCESS_ATTACH):
|
LaunchModule(module);
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx
|
|
||||||
uint64_t args[] = {
|
|
||||||
module->handle(),
|
|
||||||
1, // DLL_PROCESS_ATTACH
|
|
||||||
0, // 0 because always dynamic
|
|
||||||
};
|
|
||||||
auto thread_state = XThread::GetCurrentThread()->thread_state();
|
|
||||||
processor()->Execute(thread_state, module->entry_point(), args,
|
|
||||||
xe::countof(args));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return module;
|
return module;
|
||||||
|
|
|
@ -205,6 +205,11 @@ X_STATUS UserModule::LoadXexContinue() {
|
||||||
return X_STATUS_SUCCESS;
|
return X_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Notify kernel that we have an executable if we haven't got one already
|
||||||
|
if (!kernel_state_->GetExecutableModule()) {
|
||||||
|
kernel_state_->SetExecutableModule(object_ref<UserModule>(this));
|
||||||
|
}
|
||||||
|
|
||||||
// Finish XexModule load (PE sections/imports/symbols...)
|
// Finish XexModule load (PE sections/imports/symbols...)
|
||||||
if (!xex_module()->LoadContinue()) {
|
if (!xex_module()->LoadContinue()) {
|
||||||
return X_STATUS_UNSUCCESSFUL;
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
|
|
@ -120,9 +120,11 @@ dword_result_t ExCreateThread(lpdword_t handle_ptr, dword_t stack_size,
|
||||||
std::max((uint32_t)0x4000, ((actual_stack_size + 0xFFF) & 0xFFFFF000));
|
std::max((uint32_t)0x4000, ((actual_stack_size + 0xFFF) & 0xFFFFF000));
|
||||||
|
|
||||||
auto thread = object_ref<XThread>(
|
auto thread = object_ref<XThread>(
|
||||||
new XThread(kernel_state(), actual_stack_size, xapi_thread_startup,
|
new XThread(kernel_state(), actual_stack_size,
|
||||||
start_address.guest_address(), start_context.guest_address(),
|
xapi_thread_startup ? XThread::StartupType::XapiThreadStartup
|
||||||
creation_flags, true));
|
: XThread::StartupType::Normal,
|
||||||
|
xapi_thread_startup, start_address.guest_address(),
|
||||||
|
start_context.guest_address(), creation_flags, true));
|
||||||
|
|
||||||
X_STATUS result = thread->Create();
|
X_STATUS result = thread->Create();
|
||||||
if (XFAILED(result)) {
|
if (XFAILED(result)) {
|
||||||
|
|
|
@ -48,15 +48,16 @@ XThread::XThread(KernelState* kernel_state)
|
||||||
: XObject(kernel_state, kTypeThread), guest_thread_(true) {}
|
: XObject(kernel_state, kTypeThread), guest_thread_(true) {}
|
||||||
|
|
||||||
XThread::XThread(KernelState* kernel_state, uint32_t stack_size,
|
XThread::XThread(KernelState* kernel_state, uint32_t stack_size,
|
||||||
uint32_t xapi_thread_startup, uint32_t start_address,
|
StartupType startup_type, uint32_t xapi_thread_startup,
|
||||||
uint32_t start_context, uint32_t creation_flags,
|
uint32_t start_address, uint32_t start_context,
|
||||||
bool guest_thread, bool main_thread)
|
uint32_t creation_flags, bool guest_thread, bool main_thread)
|
||||||
: XObject(kernel_state, kTypeThread),
|
: XObject(kernel_state, kTypeThread),
|
||||||
thread_id_(++next_xthread_id_),
|
thread_id_(++next_xthread_id_),
|
||||||
guest_thread_(guest_thread),
|
guest_thread_(guest_thread),
|
||||||
main_thread_(main_thread),
|
main_thread_(main_thread),
|
||||||
apc_list_(kernel_state->memory()) {
|
apc_list_(kernel_state->memory()) {
|
||||||
creation_params_.stack_size = stack_size;
|
creation_params_.stack_size = stack_size;
|
||||||
|
creation_params_.startup_type = startup_type;
|
||||||
creation_params_.xapi_thread_startup = xapi_thread_startup;
|
creation_params_.xapi_thread_startup = xapi_thread_startup;
|
||||||
creation_params_.start_address = start_address;
|
creation_params_.start_address = start_address;
|
||||||
creation_params_.start_context = start_context;
|
creation_params_.start_context = start_context;
|
||||||
|
@ -497,12 +498,23 @@ void XThread::Execute() {
|
||||||
|
|
||||||
// If a XapiThreadStartup value is present, we use that as a trampoline.
|
// If a XapiThreadStartup value is present, we use that as a trampoline.
|
||||||
// Otherwise, we are a raw thread.
|
// Otherwise, we are a raw thread.
|
||||||
if (creation_params_.xapi_thread_startup) {
|
|
||||||
|
if (creation_params_.startup_type == StartupType::XapiThreadStartup) {
|
||||||
uint64_t args[] = {creation_params_.start_address,
|
uint64_t args[] = {creation_params_.start_address,
|
||||||
creation_params_.start_context};
|
creation_params_.start_context};
|
||||||
kernel_state()->processor()->Execute(thread_state_,
|
kernel_state()->processor()->Execute(thread_state_,
|
||||||
creation_params_.xapi_thread_startup,
|
creation_params_.xapi_thread_startup,
|
||||||
args, xe::countof(args));
|
args, xe::countof(args));
|
||||||
|
} else if (creation_params_.startup_type == StartupType::DllMain) {
|
||||||
|
// Call DllMain(DLL_PROCESS_ATTACH):
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx
|
||||||
|
uint64_t args[] = {
|
||||||
|
creation_params_.start_context,
|
||||||
|
1, // DLL_PROCESS_ATTACH
|
||||||
|
0, // 0 because always dynamic
|
||||||
|
};
|
||||||
|
kernel_state()->processor()->Execute(
|
||||||
|
thread_state_, creation_params_.start_address, args, xe::countof(args));
|
||||||
} else {
|
} else {
|
||||||
// Run user code.
|
// Run user code.
|
||||||
uint64_t args[] = {creation_params_.start_context};
|
uint64_t args[] = {creation_params_.start_context};
|
||||||
|
@ -1030,7 +1042,8 @@ object_ref<XThread> XThread::Restore(KernelState* kernel_state,
|
||||||
|
|
||||||
XHostThread::XHostThread(KernelState* kernel_state, uint32_t stack_size,
|
XHostThread::XHostThread(KernelState* kernel_state, uint32_t stack_size,
|
||||||
uint32_t creation_flags, std::function<int()> host_fn)
|
uint32_t creation_flags, std::function<int()> host_fn)
|
||||||
: XThread(kernel_state, stack_size, 0, 0, 0, creation_flags, false),
|
: XThread(kernel_state, stack_size, XThread::StartupType::Normal, 0, 0, 0,
|
||||||
|
creation_flags, false),
|
||||||
host_fn_(host_fn) {
|
host_fn_(host_fn) {
|
||||||
// By default host threads are not debugger suspendable. If the thread runs
|
// By default host threads are not debugger suspendable. If the thread runs
|
||||||
// any guest code this must be overridden.
|
// any guest code this must be overridden.
|
||||||
|
|
|
@ -107,8 +107,11 @@ class XThread : public XObject, public cpu::Thread {
|
||||||
public:
|
public:
|
||||||
static const Type kType = kTypeThread;
|
static const Type kType = kTypeThread;
|
||||||
|
|
||||||
|
enum StartupType { Normal, XapiThreadStartup, DllMain };
|
||||||
|
|
||||||
struct CreationParams {
|
struct CreationParams {
|
||||||
uint32_t stack_size;
|
uint32_t stack_size;
|
||||||
|
StartupType startup_type;
|
||||||
uint32_t xapi_thread_startup;
|
uint32_t xapi_thread_startup;
|
||||||
uint32_t start_address;
|
uint32_t start_address;
|
||||||
uint32_t start_context;
|
uint32_t start_context;
|
||||||
|
@ -117,9 +120,9 @@ class XThread : public XObject, public cpu::Thread {
|
||||||
|
|
||||||
XThread(KernelState* kernel_state);
|
XThread(KernelState* kernel_state);
|
||||||
XThread(KernelState* kernel_state, uint32_t stack_size,
|
XThread(KernelState* kernel_state, uint32_t stack_size,
|
||||||
uint32_t xapi_thread_startup, uint32_t start_address,
|
StartupType startup_type, uint32_t xapi_thread_startup,
|
||||||
uint32_t start_context, uint32_t creation_flags, bool guest_thread,
|
uint32_t start_address, uint32_t start_context,
|
||||||
bool main_thread = false);
|
uint32_t creation_flags, bool guest_thread, bool main_thread = false);
|
||||||
~XThread() override;
|
~XThread() override;
|
||||||
|
|
||||||
static bool IsInThread(XThread* other);
|
static bool IsInThread(XThread* other);
|
||||||
|
|
Loading…
Reference in New Issue