Use HMODULE instead of handles for xex modules

This commit is contained in:
Dr. Chat 2015-06-27 22:00:58 -05:00
parent 1289e7ad22
commit 7372dd4d8d
5 changed files with 126 additions and 41 deletions

View File

@ -20,7 +20,8 @@ XModule::XModule(KernelState* kernel_state, ModuleType module_type,
: XObject(kernel_state, kTypeModule),
module_type_(module_type),
path_(path),
processor_module_(nullptr) {
processor_module_(nullptr),
hmodule_ptr_(0) {
auto last_slash = path.find_last_of('/');
if (last_slash == path.npos) {
last_slash = path.find_last_of('\\');
@ -34,9 +35,22 @@ XModule::XModule(KernelState* kernel_state, ModuleType module_type,
if (dot != name_.npos) {
name_ = name_.substr(0, dot);
}
// Loader data (HMODULE)
hmodule_ptr_ = memory()->SystemHeapAlloc(sizeof(X_LDR_DATA_TABLE_ENTRY));
// Hijack the checksum field to store our kernel object handle.
auto ldr_data =
memory()->TranslateVirtual<X_LDR_DATA_TABLE_ENTRY*>(hmodule_ptr_);
ldr_data->checksum = handle();
}
XModule::~XModule() { kernel_state_->UnregisterModule(this); }
XModule::~XModule() {
kernel_state_->UnregisterModule(this);
// Destroy the loader data.
memory()->SystemHeapFree(hmodule_ptr_);
}
bool XModule::Matches(const std::string& name) const {
if (strcasecmp(xe::find_name_from_path(path_).c_str(), name.c_str()) == 0) {
@ -58,5 +72,17 @@ X_STATUS XModule::GetSection(const char* name, uint32_t* out_section_data,
return X_STATUS_UNSUCCESSFUL;
}
object_ref<XModule> XModule::GetFromHModule(KernelState* kernel_state,
void* hmodule) {
// Grab the object from our stashed kernel handle
return kernel_state->object_table()->LookupObject<XModule>(
GetHandleFromHModule(hmodule));
}
uint32_t XModule::GetHandleFromHModule(void* hmodule) {
auto ldr_data = reinterpret_cast<X_LDR_DATA_TABLE_ENTRY*>(hmodule);
return ldr_data->checksum;
}
} // namespace kernel
} // namespace xe

View File

@ -19,6 +19,42 @@
namespace xe {
namespace kernel {
// http://www.nirsoft.net/kernel_struct/vista/LDR_DATA_TABLE_ENTRY.html
// HMODULE points to this struct!
struct X_LDR_DATA_TABLE_ENTRY {
X_LIST_ENTRY in_load_order_links; // 0x0
X_LIST_ENTRY in_memory_order_links; // 0x8
X_LIST_ENTRY in_initialization_order_links; // 0x10
xe::be<uint32_t> dll_base; // 0x18
xe::be<uint32_t> image_base; // 0x1C
xe::be<uint32_t> image_size; // 0x20
X_UNICODE_STRING full_dll_name; // 0x24
X_UNICODE_STRING base_dll_name; // 0x2C
xe::be<uint32_t> flags; // 0x34
xe::be<uint32_t> full_image_size; // 0x38
xe::be<uint32_t> entry_point; // 0x3C
xe::be<uint16_t> load_count; // 0x40
xe::be<uint16_t> module_index; // 0x42
xe::be<uint32_t> dll_base_original; // 0x44
xe::be<uint32_t> checksum; // 0x48 hijacked to hold kernel handle
xe::be<uint32_t> load_flags; // 0x4C
xe::be<uint32_t> time_date_stamp; // 0x50
xe::be<uint32_t> loaded_imports; // 0x54
xe::be<uint32_t> xex_header_base; // 0x58
union {
X_ANSI_STRING load_file_name; // 0x5C
struct {
xe::be<uint32_t> closure_root; // 0x5C
xe::be<uint32_t> traversal_parent; // 0x60
};
};
};
class XModule : public XObject {
public:
enum class ModuleType {
@ -37,12 +73,16 @@ class XModule : public XObject {
bool Matches(const std::string& name) const;
xe::cpu::Module* processor_module() const { return processor_module_; }
uint32_t hmodule_ptr() const { return hmodule_ptr_; }
virtual uint32_t GetProcAddressByOrdinal(uint16_t ordinal) = 0;
virtual uint32_t GetProcAddressByName(const char* name) = 0;
virtual X_STATUS GetSection(const char* name, uint32_t* out_section_data,
uint32_t* out_section_size);
static object_ref<XModule> GetFromHModule(KernelState* kernel_state, void* hmodule);
static uint32_t GetHandleFromHModule(void* hmodule);
protected:
void OnLoad();
@ -51,6 +91,8 @@ class XModule : public XObject {
std::string path_;
xe::cpu::Module* processor_module_;
uint32_t hmodule_ptr_; // This points to LDR_DATA_TABLE_ENTRY.
};
} // namespace kernel

View File

@ -101,20 +101,21 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) {
return X_STATUS_UNSUCCESSFUL;
}
// Store execution info for later use.
// TODO(benvanik): just put entire xex header in memory somewhere?
execution_info_ptr_ = memory()->SystemHeapAlloc(24);
auto eip = memory()->TranslateVirtual(execution_info_ptr_);
const auto& ex = xe_xex2_get_header(xex_)->execution_info;
xe::store_and_swap<uint32_t>(eip + 0x00, ex.media_id);
xe::store_and_swap<uint32_t>(eip + 0x04, ex.version.value);
xe::store_and_swap<uint32_t>(eip + 0x08, ex.base_version.value);
xe::store_and_swap<uint32_t>(eip + 0x0C, ex.title_id);
xe::store_and_swap<uint8_t>(eip + 0x10, ex.platform);
xe::store_and_swap<uint8_t>(eip + 0x11, ex.executable_table);
xe::store_and_swap<uint8_t>(eip + 0x12, ex.disc_number);
xe::store_and_swap<uint8_t>(eip + 0x13, ex.disc_count);
xe::store_and_swap<uint32_t>(eip + 0x14, ex.savegame_id);
// Copy the xex2 header into guest memory
const xex2_header* header = reinterpret_cast<const xex2_header*>(addr);
uint32_t header_size = xex2_get_header_size(header);
xex_header_ = memory()->SystemHeapAlloc(header_size);
uint8_t* xex_header_ptr = memory()->TranslateVirtual(xex_header_);
std::memcpy(xex_header_ptr, header, header_size);
// Setup the loader data entry
auto ldr_data =
memory()->TranslateVirtual<X_LDR_DATA_TABLE_ENTRY*>(hmodule_ptr_);
ldr_data->dll_base = 0; // GetProcAddress will read this.
ldr_data->xex_header_base = xex_header_;
// Prepare the module for execution.
// Runtime takes ownership.

View File

@ -44,6 +44,7 @@ class XUserModule : public XModule {
private:
xe_xex2_ref xex_;
uint32_t xex_header_;
uint32_t execution_info_ptr_;
};

View File

@ -153,9 +153,9 @@ SHIM_CALL XexGetModuleHandle_shim(PPCContext* ppc_context,
KernelState* kernel_state) {
uint32_t module_name_ptr = SHIM_GET_ARG_32(0);
const char* module_name = (const char*)SHIM_MEM_ADDR(module_name_ptr);
uint32_t module_handle_ptr = SHIM_GET_ARG_32(1);
uint32_t hmodule_ptr = SHIM_GET_ARG_32(1);
XELOGD("XexGetModuleHandle(%s, %.8X)", module_name, module_handle_ptr);
XELOGD("XexGetModuleHandle(%s, %.8X)", module_name, hmodule_ptr);
object_ref<XModule> module;
if (!module_name) {
@ -164,31 +164,31 @@ SHIM_CALL XexGetModuleHandle_shim(PPCContext* ppc_context,
module = kernel_state->GetModule(module_name);
}
if (!module) {
SHIM_SET_MEM_32(module_handle_ptr, 0);
SHIM_SET_MEM_32(hmodule_ptr, 0);
SHIM_SET_RETURN_32(X_ERROR_NOT_FOUND);
return;
}
// NOTE: we don't retain the handle for return.
SHIM_SET_MEM_32(module_handle_ptr, module->handle());
SHIM_SET_MEM_32(hmodule_ptr, module->hmodule_ptr());
SHIM_SET_RETURN_32(X_ERROR_SUCCESS);
}
SHIM_CALL XexGetModuleSection_shim(PPCContext* ppc_context,
KernelState* kernel_state) {
uint32_t handle = SHIM_GET_ARG_32(0);
uint32_t hmodule = SHIM_GET_ARG_32(0);
uint32_t name_ptr = SHIM_GET_ARG_32(1);
const char* name = (const char*)SHIM_MEM_ADDR(name_ptr);
uint32_t data_ptr = SHIM_GET_ARG_32(2);
uint32_t size_ptr = SHIM_GET_ARG_32(3);
XELOGD("XexGetModuleSection(%.8X, %s, %.8X, %.8X)", handle, name, data_ptr,
XELOGD("XexGetModuleSection(%.8X, %s, %.8X, %.8X)", hmodule, name, data_ptr,
size_ptr);
X_STATUS result = X_STATUS_SUCCESS;
auto module = kernel_state->object_table()->LookupObject<XModule>(handle);
auto module = XModule::GetFromHModule(kernel_state, SHIM_MEM_ADDR(hmodule));
if (module) {
uint32_t section_data = 0;
uint32_t section_size = 0;
@ -210,49 +210,64 @@ SHIM_CALL XexLoadImage_shim(PPCContext* ppc_context,
const char* module_name = (const char*)SHIM_MEM_ADDR(module_name_ptr);
uint32_t module_flags = SHIM_GET_ARG_32(1);
uint32_t min_version = SHIM_GET_ARG_32(2);
uint32_t handle_ptr = SHIM_GET_ARG_32(3);
uint32_t hmodule_ptr = SHIM_GET_ARG_32(3);
XELOGD("XexLoadImage(%s, %.8X, %.8X, %.8X)", module_name, module_flags,
min_version, handle_ptr);
min_version, hmodule_ptr);
X_STATUS result = X_STATUS_NO_SUCH_FILE;
X_HANDLE module_handle = X_INVALID_HANDLE_VALUE;
uint32_t hmodule = 0;
auto module = kernel_state->GetModule(module_name);
if (module) {
// Existing module found, just add a reference and obtain a handle.
result =
kernel_state->object_table()->AddHandle(module.get(), &module_handle);
// Existing module found.
hmodule = module->hmodule_ptr();
} else {
// Not found; attempt to load as a user module.
auto user_module = kernel_state->LoadUserModule(module_name);
if (user_module) {
user_module->RetainHandle();
module_handle = user_module->handle();
hmodule = user_module->hmodule_ptr();
result = X_STATUS_SUCCESS;
}
}
SHIM_SET_MEM_32(handle_ptr, module_handle);
// Increment the module's load count.
auto ldr_data =
kernel_memory()->TranslateVirtual<X_LDR_DATA_TABLE_ENTRY*>(hmodule);
ldr_data->load_count++;
SHIM_SET_MEM_32(hmodule_ptr, hmodule);
SHIM_SET_RETURN_32(result);
}
SHIM_CALL XexUnloadImage_shim(PPCContext* ppc_context,
KernelState* kernel_state) {
uint32_t module_handle = SHIM_GET_ARG_32(0);
uint32_t hmodule = SHIM_GET_ARG_32(0);
XELOGD("XexUnloadImage(%.8X)", module_handle);
XELOGD("XexUnloadImage(%.8X)", hmodule);
X_STATUS result = X_STATUS_INVALID_HANDLE;
auto module = XModule::GetFromHModule(kernel_state, SHIM_MEM_ADDR(hmodule));
if (!module) {
SHIM_SET_RETURN_32(X_STATUS_INVALID_HANDLE);
return;
}
result = kernel_state->object_table()->RemoveHandle(module_handle);
auto ldr_data =
kernel_state->memory()->TranslateVirtual<X_LDR_DATA_TABLE_ENTRY*>(
hmodule);
if (ldr_data->load_count-- <= 0) {
// No more references, free it.
kernel_state->object_table()->RemoveHandle(module->handle());
}
SHIM_SET_RETURN_32(result);
SHIM_SET_RETURN_32(X_STATUS_SUCCESS);
}
SHIM_CALL XexGetProcedureAddress_shim(PPCContext* ppc_context,
KernelState* kernel_state) {
uint32_t module_handle = SHIM_GET_ARG_32(0);
uint32_t hmodule = SHIM_GET_ARG_32(0);
uint32_t ordinal = SHIM_GET_ARG_32(1);
uint32_t out_function_ptr = SHIM_GET_ARG_32(2);
@ -263,20 +278,20 @@ SHIM_CALL XexGetProcedureAddress_shim(PPCContext* ppc_context,
auto string_name = reinterpret_cast<const char*>(SHIM_MEM_ADDR(ordinal));
if (is_string_name) {
XELOGD("XexGetProcedureAddress(%.8X, %.8X(%s), %.8X)", module_handle,
XELOGD("XexGetProcedureAddress(%.8X, %.8X(%s), %.8X)", hmodule,
ordinal, string_name, out_function_ptr);
} else {
XELOGD("XexGetProcedureAddress(%.8X, %.8X, %.8X)", module_handle, ordinal,
XELOGD("XexGetProcedureAddress(%.8X, %.8X, %.8X)", hmodule, ordinal,
out_function_ptr);
}
X_STATUS result = X_STATUS_INVALID_HANDLE;
object_ref<XModule> module;
if (!module_handle) {
if (!hmodule) {
module = kernel_state->GetExecutableModule();
} else {
module = kernel_state->object_table()->LookupObject<XModule>(module_handle);
module = XModule::GetFromHModule(kernel_state, SHIM_MEM_ADDR(hmodule));
}
if (module) {
uint32_t ptr;