Merge pull request #300 from DrChat/hmodule_fix
Swap to using HMODULE instead of handles for xex modules.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,17 @@ 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 +92,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
|
||||
|
||||
@@ -22,14 +22,9 @@ namespace kernel {
|
||||
using namespace xe::cpu;
|
||||
|
||||
XUserModule::XUserModule(KernelState* kernel_state, const char* path)
|
||||
: XModule(kernel_state, ModuleType::kUserModule, path),
|
||||
xex_(nullptr),
|
||||
execution_info_ptr_(0) {}
|
||||
: XModule(kernel_state, ModuleType::kUserModule, path), xex_(nullptr) {}
|
||||
|
||||
XUserModule::~XUserModule() {
|
||||
kernel_state()->memory()->SystemHeapFree(execution_info_ptr_);
|
||||
xe_xex2_dealloc(xex_);
|
||||
}
|
||||
XUserModule::~XUserModule() { xe_xex2_dealloc(xex_); }
|
||||
|
||||
xe_xex2_ref XUserModule::xex() { return xex_; }
|
||||
|
||||
@@ -94,20 +89,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.
|
||||
@@ -148,6 +144,24 @@ X_STATUS XUserModule::GetSection(const char* name, uint32_t* out_section_data,
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
X_STATUS XUserModule::GetOptHeader(xe_xex2_header_keys key,
|
||||
uint32_t* out_header_guest_ptr) {
|
||||
assert_not_null(out_header_guest_ptr);
|
||||
|
||||
auto header = memory()->TranslateVirtual<xex2_header*>(xex_header_);
|
||||
if (!header) {
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
auto ptr = xex2_get_opt_header(header, key);
|
||||
if (!ptr) {
|
||||
return X_STATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
*out_header_guest_ptr = (uint32_t)(ptr - memory()->virtual_membase());
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS XUserModule::Launch(uint32_t flags) {
|
||||
const xe_xex2_header_t* header = xex_header();
|
||||
|
||||
|
||||
@@ -28,8 +28,6 @@ class XUserModule : public XModule {
|
||||
xe_xex2_ref xex();
|
||||
const xe_xex2_header_t* xex_header();
|
||||
|
||||
uint32_t execution_info_ptr() const { return execution_info_ptr_; }
|
||||
|
||||
X_STATUS LoadFromFile(std::string path);
|
||||
X_STATUS LoadFromMemory(const void* addr, const size_t length);
|
||||
|
||||
@@ -37,6 +35,8 @@ class XUserModule : public XModule {
|
||||
uint32_t GetProcAddressByName(const char* name) override;
|
||||
X_STATUS GetSection(const char* name, uint32_t* out_section_data,
|
||||
uint32_t* out_section_size) override;
|
||||
X_STATUS GetOptHeader(xe_xex2_header_keys key,
|
||||
uint32_t* out_header_guest_ptr);
|
||||
|
||||
X_STATUS Launch(uint32_t flags);
|
||||
|
||||
@@ -44,7 +44,7 @@ class XUserModule : public XModule {
|
||||
|
||||
private:
|
||||
xe_xex2_ref xex_;
|
||||
uint32_t execution_info_ptr_;
|
||||
uint32_t xex_header_;
|
||||
};
|
||||
|
||||
} // namespace kernel
|
||||
|
||||
Reference in New Issue
Block a user