From 49c8efdc6dc827e28ed004923d67b645b6f0dd8e Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 4 May 2015 17:38:34 -0500 Subject: [PATCH 1/7] XexGetProcedureAddress by name implemented. --- src/xenia/kernel/objects/xkernel_module.cc | 5 ++ src/xenia/kernel/objects/xkernel_module.h | 1 + src/xenia/kernel/objects/xmodule.h | 1 + src/xenia/kernel/objects/xuser_module.cc | 11 ++++ src/xenia/kernel/objects/xuser_module.h | 1 + src/xenia/kernel/util/xex2.cc | 59 ++++++++++++++++++++++ src/xenia/kernel/util/xex2.h | 10 ++++ src/xenia/kernel/util/xex2_info.h | 14 ++++- 8 files changed, 101 insertions(+), 1 deletion(-) diff --git a/src/xenia/kernel/objects/xkernel_module.cc b/src/xenia/kernel/objects/xkernel_module.cc index 91d8470fb..e46e88e16 100644 --- a/src/xenia/kernel/objects/xkernel_module.cc +++ b/src/xenia/kernel/objects/xkernel_module.cc @@ -34,5 +34,10 @@ void* XKernelModule::GetProcAddressByOrdinal(uint16_t ordinal) { return NULL; } +void* XKernelModule::GetProcAddressByName(const char* name) { + XELOGE("GetProcAddressByName not implemented"); + return NULL; +} + } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/objects/xkernel_module.h b/src/xenia/kernel/objects/xkernel_module.h index 98691f41d..a4117032c 100644 --- a/src/xenia/kernel/objects/xkernel_module.h +++ b/src/xenia/kernel/objects/xkernel_module.h @@ -24,6 +24,7 @@ class XKernelModule : public XModule { virtual ~XKernelModule(); virtual void* GetProcAddressByOrdinal(uint16_t ordinal); + virtual void* GetProcAddressByName(const char* name); protected: Emulator* emulator_; diff --git a/src/xenia/kernel/objects/xmodule.h b/src/xenia/kernel/objects/xmodule.h index 0abe66931..225a80987 100644 --- a/src/xenia/kernel/objects/xmodule.h +++ b/src/xenia/kernel/objects/xmodule.h @@ -27,6 +27,7 @@ class XModule : public XObject { const std::string& name() const { return name_; } virtual void* GetProcAddressByOrdinal(uint16_t ordinal) = 0; + virtual void* GetProcAddressByName(const char *name) = 0; virtual X_STATUS GetSection(const char* name, uint32_t* out_section_data, uint32_t* out_section_size); diff --git a/src/xenia/kernel/objects/xuser_module.cc b/src/xenia/kernel/objects/xuser_module.cc index dc7dc0c1e..86ecb025a 100644 --- a/src/xenia/kernel/objects/xuser_module.cc +++ b/src/xenia/kernel/objects/xuser_module.cc @@ -148,6 +148,17 @@ void* XUserModule::GetProcAddressByOrdinal(uint16_t ordinal) { return NULL; } +void* XUserModule::GetProcAddressByName(const char* name) { + PEExport export; + int ret = xe_xex2_lookup_export(xex_, name, export); + + // Failure. + if (ret) + return NULL; + + return (void *)export.addr; +} + X_STATUS XUserModule::GetSection(const char* name, uint32_t* out_section_data, uint32_t* out_section_size) { auto header = xe_xex2_get_header(xex_); diff --git a/src/xenia/kernel/objects/xuser_module.h b/src/xenia/kernel/objects/xuser_module.h index 590a0a5b4..19edc0c3b 100644 --- a/src/xenia/kernel/objects/xuser_module.h +++ b/src/xenia/kernel/objects/xuser_module.h @@ -33,6 +33,7 @@ class XUserModule : public XModule { X_STATUS LoadFromMemory(const void* addr, const size_t length); virtual void* GetProcAddressByOrdinal(uint16_t ordinal); + virtual void* GetProcAddressByName(const char* name); virtual X_STATUS GetSection(const char* name, uint32_t* out_section_data, uint32_t* out_section_size); diff --git a/src/xenia/kernel/util/xex2.cc b/src/xenia/kernel/util/xex2.cc index c2dfcb40b..d645e6adb 100644 --- a/src/xenia/kernel/util/xex2.cc +++ b/src/xenia/kernel/util/xex2.cc @@ -49,6 +49,8 @@ typedef struct xe_xex2 { size_t count; xe_xex2_import_info_t *infos; } library_imports[16]; + + xe_xex2_export_table *export_table; } xe_xex2_t; int xe_xex2_read_header(const uint8_t *addr, const size_t length, @@ -237,6 +239,11 @@ int xe_xex2_read_header(const uint8_t *addr, const size_t length, case XEX_HEADER_DEFAULT_HEAP_SIZE: header->exe_heap_size = opt_header->value; break; + case XEX_HEADER_EXPORTS_BY_NAME: { + // IMAGE_DATA_DIRECTORY (w/ offset from PE file base) + header->export_table_offset = xe::load_and_swap(pp); + // size = xe::load_and_swap(pp + 0x04); + } break; case XEX_HEADER_IMPORT_LIBRARIES: { const size_t max_count = xe::countof(header->import_libraries); size_t count = xe::load_and_swap(pp + 0x08); @@ -869,6 +876,20 @@ int xe_xex2_load_pe(xe_xex2_ref xex) { xex->sections->push_back(section); } + if (header->export_table_offset) { + // This table is located inside of the PE (for some reason) + xe_xex2_export_table *table = (xe_xex2_export_table *)xex->memory->TranslateVirtual(xex->header.loader_info.export_table); + xex->export_table = table; + // cmp magic... + + table->base = xe::load_and_swap(&table->base); + table->imagebaseaddr = xe::load_and_swap(&table->imagebaseaddr); + table->count = xe::load_and_swap(&table->count); + for (int i = 0; i < table->count; i++) { + table->ordOffset[i] = xe::load_and_swap(&table->ordOffset[i]); + } + } + // DumpTLSDirectory(pImageBase, pNTHeader, (PIMAGE_TLS_DIRECTORY32)0); // DumpExportsSection(pImageBase, pNTHeader); return 0; @@ -982,3 +1003,41 @@ int xe_xex2_get_import_infos(xe_xex2_ref xex, *out_import_infos = xex->library_imports[library_index].infos; return 0; } + +int xe_xex2_lookup_export(xe_xex2_ref xex, const char *name, + PEExport &peexport) { + auto header = xe_xex2_get_header(xex); + + // no exports :( + if (!header->export_table_offset) { + return 1; + } + + uint64_t loadaddr = (uint64_t)xex->memory->TranslateVirtual(header->loader_info.load_address); + IMAGE_EXPORT_DIRECTORY *e = (PIMAGE_EXPORT_DIRECTORY)(loadaddr + header->export_table_offset); + + // e->AddressOfX RVAs are relative to the IMAGE_EXPORT_DIRECTORY! + uint32_t* function_table = (uint32_t*)((uint64_t)e + e->AddressOfFunctions); // Functions relative to base + uint32_t* name_table = (uint32_t*)((uint64_t)e + e->AddressOfNames); // Names relative to directory + uint16_t* ordinal_table = (uint16_t*)((uint64_t)e + e->AddressOfNameOrdinals); // Table of ordinals + + const char* mod_name = (const char*)((uint64_t)e + e->Name); + + for (int i = 0; i < e->NumberOfNames; i++) { + const char *fn_name = (const char *)((uint64_t)e + name_table[i]); + uint16_t ordinal = ordinal_table[i]; + uint64_t addr = (uint64_t)(loadaddr + function_table[ordinal]); + + if (!strcmp(name, fn_name)) { + // We have a match! + peexport.name = fn_name; + peexport.addr = addr; + peexport.ordinal = ordinal; + + return 0; + } + } + + // No match + return 1; +} \ No newline at end of file diff --git a/src/xenia/kernel/util/xex2.h b/src/xenia/kernel/util/xex2.h index 212badb7c..dbea70cf5 100644 --- a/src/xenia/kernel/util/xex2.h +++ b/src/xenia/kernel/util/xex2.h @@ -43,6 +43,13 @@ class PESection { uint32_t flags; // kXEPESection* }; +struct PEExport { + const char *name; + uint32_t ordinal; + + uint64_t addr; // Function address +}; + xe_xex2_ref xe_xex2_load(xe::Memory* memory, const void* addr, const size_t length, xe_xex2_options_t options); void xe_xex2_dealloc(xe_xex2_ref xex); @@ -55,4 +62,7 @@ int xe_xex2_get_import_infos(xe_xex2_ref xex, xe_xex2_import_info_t** out_import_infos, size_t* out_import_info_count); +int xe_xex2_lookup_export(xe_xex2_ref xex, const char *name, + PEExport &peexport); + #endif // XENIA_KERNEL_UTIL_XEX2_H_ diff --git a/src/xenia/kernel/util/xex2_info.h b/src/xenia/kernel/util/xex2_info.h index 5256fa5cd..6109bd963 100644 --- a/src/xenia/kernel/util/xex2_info.h +++ b/src/xenia/kernel/util/xex2_info.h @@ -295,6 +295,17 @@ typedef struct { xe_xex2_approval_type approval; } xe_xex2_static_library_t; +// credits: some obscure pastebin (http://pastebin.com/ZRvr3Sgj) +typedef struct { + uint32_t magic[3]; + uint32_t modulenumber[2]; + uint32_t version[3]; + uint32_t imagebaseaddr; // must be <<16 to be accurate + uint32_t count; + uint32_t base; + uint32_t ordOffset[1]; // ordOffset[0] + (imagebaseaddr << 16) = function offset of ordinal 1 +} xe_xex2_export_table; + typedef enum { XEX_ENCRYPTION_NONE = 0, XEX_ENCRYPTION_NORMAL = 1, @@ -397,7 +408,7 @@ typedef struct { uint8_t import_table_digest[20]; uint8_t media_id[16]; uint8_t file_key[16]; - uint32_t export_table; + uint32_t export_table; // address of the export table uint8_t header_digest[20]; xe_xex2_region_flags game_regions; xe_xex2_media_flags media_flags; @@ -434,6 +445,7 @@ typedef struct { xe_xex2_tls_info_t tls_info; size_t import_library_count; xe_xex2_import_library_t import_libraries[32]; + size_t export_table_offset; // PE Export Directory size_t static_library_count; xe_xex2_static_library_t static_libraries[32]; xe_xex2_file_format_info_t file_format_info; From be3d7298313839ada4fe46944364243531a99416 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 4 May 2015 17:40:37 -0500 Subject: [PATCH 2/7] Implemented this too (XexGetProcedureAddress) --- src/xenia/kernel/xboxkrnl_modules.cc | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/xenia/kernel/xboxkrnl_modules.cc b/src/xenia/kernel/xboxkrnl_modules.cc index ff9b9a530..08f73a57e 100644 --- a/src/xenia/kernel/xboxkrnl_modules.cc +++ b/src/xenia/kernel/xboxkrnl_modules.cc @@ -246,10 +246,15 @@ SHIM_CALL XexGetProcedureAddress_shim(PPCContext* ppc_state, KernelState* state) { uint32_t module_handle = SHIM_GET_ARG_32(0); uint32_t ordinal = SHIM_GET_ARG_32(1); + const char *name = (const char *)SHIM_MEM_ADDR(ordinal); uint32_t out_function_ptr = SHIM_GET_ARG_32(2); - XELOGD("XexGetProcedureAddress(%.8X, %.8X, %.8X)", module_handle, ordinal, - out_function_ptr); + if (ordinal < 0x10000) + XELOGD("XexGetProcedureAddress(%.8X, %.8X, %.8X)", module_handle, ordinal, + out_function_ptr); + else + XELOGD("XexGetProcedureAddress(%.8X, %.8X(%s), %.8X)", module_handle, ordinal, + name, out_function_ptr); X_STATUS result = X_STATUS_INVALID_HANDLE; SHIM_SET_MEM_32(out_function_ptr, 0xDEADF00D); @@ -265,9 +270,24 @@ SHIM_CALL XexGetProcedureAddress_shim(PPCContext* ppc_state, if (XSUCCEEDED(result)) { // TODO(benvanik): implement. May need to create stub functions on the fly. - // module->GetProcAddressByOrdinal(ordinal); - result = X_STATUS_NOT_IMPLEMENTED; + if (ordinal < 0x10000) { + uint64_t ptr = (uint64_t)module->GetProcAddressByOrdinal(ordinal); + SHIM_SET_MEM_32(out_function_ptr, ptr); + result = X_STATUS_NOT_IMPLEMENTED; + } else { + // It's a name pointer instead. + uint64_t ptr = (uint64_t)module->GetProcAddressByName(name); + + // FYI: We don't need to generate this function now. It'll + // be done automatically by xenia when it gets called + + if (ptr) { + SHIM_SET_MEM_32(out_function_ptr, ptr); + result = X_STATUS_SUCCESS; + } + } } + if (module) { module->Release(); } From 211cd0760a04170908a0ae3874b939227f6c036e Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 4 May 2015 18:11:07 -0500 Subject: [PATCH 3/7] Use header->exe_address instead (in-case the module is relocated) --- src/xenia/kernel/util/xex2.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xenia/kernel/util/xex2.cc b/src/xenia/kernel/util/xex2.cc index d645e6adb..19104c445 100644 --- a/src/xenia/kernel/util/xex2.cc +++ b/src/xenia/kernel/util/xex2.cc @@ -1013,8 +1013,8 @@ int xe_xex2_lookup_export(xe_xex2_ref xex, const char *name, return 1; } - uint64_t loadaddr = (uint64_t)xex->memory->TranslateVirtual(header->loader_info.load_address); - IMAGE_EXPORT_DIRECTORY *e = (PIMAGE_EXPORT_DIRECTORY)(loadaddr + header->export_table_offset); + uint64_t baseaddr = (uint64_t)xex->memory->TranslateVirtual(header->exe_address); + IMAGE_EXPORT_DIRECTORY *e = (PIMAGE_EXPORT_DIRECTORY)(baseaddr + header->export_table_offset); // e->AddressOfX RVAs are relative to the IMAGE_EXPORT_DIRECTORY! uint32_t* function_table = (uint32_t*)((uint64_t)e + e->AddressOfFunctions); // Functions relative to base @@ -1026,7 +1026,7 @@ int xe_xex2_lookup_export(xe_xex2_ref xex, const char *name, for (int i = 0; i < e->NumberOfNames; i++) { const char *fn_name = (const char *)((uint64_t)e + name_table[i]); uint16_t ordinal = ordinal_table[i]; - uint64_t addr = (uint64_t)(loadaddr + function_table[ordinal]); + uint64_t addr = (uint64_t)(baseaddr + function_table[ordinal]); if (!strcmp(name, fn_name)) { // We have a match! From 6a602affedb4760206a0a4d74b16afc371ed9e42 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 4 May 2015 18:15:57 -0500 Subject: [PATCH 4/7] Don't parse loader export table for now (since it's referenced to with an exact address) --- src/xenia/kernel/util/xex2.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/xenia/kernel/util/xex2.cc b/src/xenia/kernel/util/xex2.cc index 19104c445..416b24286 100644 --- a/src/xenia/kernel/util/xex2.cc +++ b/src/xenia/kernel/util/xex2.cc @@ -876,6 +876,7 @@ int xe_xex2_load_pe(xe_xex2_ref xex) { xex->sections->push_back(section); } + /* if (header->export_table_offset) { // This table is located inside of the PE (for some reason) xe_xex2_export_table *table = (xe_xex2_export_table *)xex->memory->TranslateVirtual(xex->header.loader_info.export_table); @@ -889,6 +890,7 @@ int xe_xex2_load_pe(xe_xex2_ref xex) { table->ordOffset[i] = xe::load_and_swap(&table->ordOffset[i]); } } + */ // DumpTLSDirectory(pImageBase, pNTHeader, (PIMAGE_TLS_DIRECTORY32)0); // DumpExportsSection(pImageBase, pNTHeader); From e90475a31bd8596095409352ed52806d4b985658 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 4 May 2015 20:26:18 -0500 Subject: [PATCH 5/7] kill the TODO --- src/xenia/kernel/xboxkrnl_modules.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/xenia/kernel/xboxkrnl_modules.cc b/src/xenia/kernel/xboxkrnl_modules.cc index 08f73a57e..938e65415 100644 --- a/src/xenia/kernel/xboxkrnl_modules.cc +++ b/src/xenia/kernel/xboxkrnl_modules.cc @@ -269,11 +269,13 @@ SHIM_CALL XexGetProcedureAddress_shim(PPCContext* ppc_state, } if (XSUCCEEDED(result)) { - // TODO(benvanik): implement. May need to create stub functions on the fly. if (ordinal < 0x10000) { + // Ordinal. uint64_t ptr = (uint64_t)module->GetProcAddressByOrdinal(ordinal); - SHIM_SET_MEM_32(out_function_ptr, ptr); - result = X_STATUS_NOT_IMPLEMENTED; + if (ptr) { + SHIM_SET_MEM_32(out_function_ptr, ptr); + result = X_STATUS_SUCCESS; + } } else { // It's a name pointer instead. uint64_t ptr = (uint64_t)module->GetProcAddressByName(name); From 1571c51a5621fa249073305f26e5a94a7e84c3b5 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 4 May 2015 20:33:04 -0500 Subject: [PATCH 6/7] Kill some unused code --- src/xenia/kernel/util/xex2.cc | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/xenia/kernel/util/xex2.cc b/src/xenia/kernel/util/xex2.cc index 416b24286..4c6eefbd1 100644 --- a/src/xenia/kernel/util/xex2.cc +++ b/src/xenia/kernel/util/xex2.cc @@ -49,8 +49,6 @@ typedef struct xe_xex2 { size_t count; xe_xex2_import_info_t *infos; } library_imports[16]; - - xe_xex2_export_table *export_table; } xe_xex2_t; int xe_xex2_read_header(const uint8_t *addr, const size_t length, @@ -876,22 +874,6 @@ int xe_xex2_load_pe(xe_xex2_ref xex) { xex->sections->push_back(section); } - /* - if (header->export_table_offset) { - // This table is located inside of the PE (for some reason) - xe_xex2_export_table *table = (xe_xex2_export_table *)xex->memory->TranslateVirtual(xex->header.loader_info.export_table); - xex->export_table = table; - // cmp magic... - - table->base = xe::load_and_swap(&table->base); - table->imagebaseaddr = xe::load_and_swap(&table->imagebaseaddr); - table->count = xe::load_and_swap(&table->count); - for (int i = 0; i < table->count; i++) { - table->ordOffset[i] = xe::load_and_swap(&table->ordOffset[i]); - } - } - */ - // DumpTLSDirectory(pImageBase, pNTHeader, (PIMAGE_TLS_DIRECTORY32)0); // DumpExportsSection(pImageBase, pNTHeader); return 0; From 9603a0a68354b440341cf49c00fad2f45e5ad2ef Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 4 May 2015 20:58:30 -0500 Subject: [PATCH 7/7] Formatting --- src/xenia/kernel/xboxkrnl_modules.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/xenia/kernel/xboxkrnl_modules.cc b/src/xenia/kernel/xboxkrnl_modules.cc index 938e65415..b7be63e9e 100644 --- a/src/xenia/kernel/xboxkrnl_modules.cc +++ b/src/xenia/kernel/xboxkrnl_modules.cc @@ -249,12 +249,13 @@ SHIM_CALL XexGetProcedureAddress_shim(PPCContext* ppc_state, const char *name = (const char *)SHIM_MEM_ADDR(ordinal); uint32_t out_function_ptr = SHIM_GET_ARG_32(2); - if (ordinal < 0x10000) + if (ordinal < 0x10000) { XELOGD("XexGetProcedureAddress(%.8X, %.8X, %.8X)", module_handle, ordinal, out_function_ptr); - else + } else { XELOGD("XexGetProcedureAddress(%.8X, %.8X(%s), %.8X)", module_handle, ordinal, name, out_function_ptr); + } X_STATUS result = X_STATUS_INVALID_HANDLE; SHIM_SET_MEM_32(out_function_ptr, 0xDEADF00D); @@ -268,6 +269,8 @@ SHIM_CALL XexGetProcedureAddress_shim(PPCContext* ppc_state, state->object_table()->GetObject(module_handle, (XObject**)&module); } + result = X_STATUS_UNSUCCESSFUL; + if (XSUCCEEDED(result)) { if (ordinal < 0x10000) { // Ordinal. @@ -281,8 +284,7 @@ SHIM_CALL XexGetProcedureAddress_shim(PPCContext* ppc_state, uint64_t ptr = (uint64_t)module->GetProcAddressByName(name); // FYI: We don't need to generate this function now. It'll - // be done automatically by xenia when it gets called - + // be done automatically by xenia when it gets called. if (ptr) { SHIM_SET_MEM_32(out_function_ptr, ptr); result = X_STATUS_SUCCESS;