From fe87c0842442c6db784686127507d200a840e1c7 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 29 Jun 2015 00:48:24 -0500 Subject: [PATCH] Shuffle some code around. --- src/xenia/cpu/xex_module.cc | 70 ++++++++++++++++++++++++ src/xenia/cpu/xex_module.h | 12 ++++ src/xenia/kernel/objects/xuser_module.cc | 42 ++++++-------- src/xenia/kernel/objects/xuser_module.h | 10 +++- src/xenia/kernel/util/xex2_info.h | 65 +++++++++++++++++++--- 5 files changed, 162 insertions(+), 37 deletions(-) diff --git a/src/xenia/cpu/xex_module.cc b/src/xenia/cpu/xex_module.cc index ebfee1c5f..1a6a8e733 100644 --- a/src/xenia/cpu/xex_module.cc +++ b/src/xenia/cpu/xex_module.cc @@ -21,6 +21,8 @@ #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/objects/xmodule.h" +#include "third_party/crypto/rijndael-alg-fst.h" + namespace xe { namespace cpu { @@ -45,6 +47,74 @@ XexModule::XexModule(Processor* processor, KernelState* kernel_state) XexModule::~XexModule() { xe_xex2_dealloc(xex_); } +bool XexModule::GetOptHeader(const xex2_header* header, xe_xex2_header_keys key, + void** out_ptr) { + assert_not_null(header); + assert_not_null(out_ptr); + + for (uint32_t i = 0; i < header->header_count; i++) { + const xex2_opt_header& opt_header = header->headers[i]; + if (opt_header.key == key) { + // Match! + switch (key & 0xFF) { + case 0x00: { + // We just return the value of the optional header. + *out_ptr = (void*)((uint64_t)opt_header.value); + } break; + case 0x01: { + // Pointer to the value on the optional header. + *out_ptr = (void*)&opt_header.value; + } break; + default: { + // Pointer to the header. + *out_ptr = (void*)((uint8_t*)header + opt_header.offset); + } break; + } + + return true; + } + } + + return false; +} + +bool XexModule::ApplyPatch(XexModule* module) { + auto header = reinterpret_cast(module->xex_header()); + if (!(header->module_flags & + (XEX_MODULE_MODULE_PATCH | XEX_MODULE_PATCH_DELTA | + XEX_MODULE_PATCH_FULL))) { + // This isn't a XEX2 patch. + return false; + } + + // Grab the delta descriptor and get to work. + xex2_opt_delta_patch_descriptor* patch_header = nullptr; + GetOptHeader(header, XEX_HEADER_DELTA_PATCH_DESCRIPTOR, + (void**)&patch_header); + assert_not_null(patch_header); + + // TODO! + + return true; +} + +bool XexModule::Load(const std::string& name, const std::string& path, + const void* xex_addr, size_t xex_length) { + // TODO: Move loading code here + xex_ = xe_xex2_load(memory(), xex_addr, xex_length, {0}); + if (!xex_) { + return false; + } + + // Make a copy of the xex header. + auto src_header = reinterpret_cast(xex_addr); + xex_header_ = (xex2_header*)new char[src_header->header_size]; + + std::memcpy(xex_header_, src_header, src_header->header_size); + + return Load(name, path, xex_); +} + bool XexModule::Load(const std::string& name, const std::string& path, xe_xex2_ref xex) { xex_ = xex; diff --git a/src/xenia/cpu/xex_module.h b/src/xenia/cpu/xex_module.h index f61799e93..54e23d41e 100644 --- a/src/xenia/cpu/xex_module.h +++ b/src/xenia/cpu/xex_module.h @@ -14,6 +14,7 @@ #include "xenia/cpu/module.h" #include "xenia/kernel/util/xex2.h" +#include "xenia/kernel/util/xex2_info.h" namespace xe { @@ -32,7 +33,17 @@ class XexModule : public xe::cpu::Module { virtual ~XexModule(); xe_xex2_ref xex() const { return xex_; } + const xex2_header* xex_header() const { return xex_header_; } + // Gets an optional header. Returns NULL if not found. + // Special case: if key & 0xFF == 0x00, this function will return the value, + // not a pointer! + static bool GetOptHeader(const xex2_header* header, xe_xex2_header_keys key, + void** out_ptr); + + bool ApplyPatch(XexModule* module); + bool Load(const std::string& name, const std::string& path, + const void* xex_addr, size_t xex_length); bool Load(const std::string& name, const std::string& path, xe_xex2_ref xex); const std::string& name() const override { return name_; } @@ -50,6 +61,7 @@ class XexModule : public xe::cpu::Module { std::string name_; std::string path_; xe_xex2_ref xex_; + xex2_header* xex_header_; uint32_t base_address_; uint32_t low_address_; diff --git a/src/xenia/kernel/objects/xuser_module.cc b/src/xenia/kernel/objects/xuser_module.cc index 504a2ab1a..6da97cd48 100644 --- a/src/xenia/kernel/objects/xuser_module.cc +++ b/src/xenia/kernel/objects/xuser_module.cc @@ -26,8 +26,6 @@ XUserModule::XUserModule(KernelState* kernel_state, const char* path) XUserModule::~XUserModule() { xe_xex2_dealloc(xex_); } -xe_xex2_ref XUserModule::xex() { return xex_; } - const xe_xex2_header_t* XUserModule::xex_header() { return xe_xex2_get_header(xex_); } @@ -82,39 +80,31 @@ X_STATUS XUserModule::LoadFromFile(std::string path) { X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) { Processor* processor = kernel_state()->processor(); - // Load the XEX into memory and decrypt. - xe_xex2_options_t xex_options = {0}; - xex_ = xe_xex2_load(memory(), addr, length, xex_options); - if (!xex_) { + // Prepare the module for execution. + // Runtime takes ownership. + auto xex_module = std::make_unique(processor, kernel_state()); + if (!xex_module->Load(name_, path_, addr, length)) { + return X_STATUS_UNSUCCESSFUL; + } + xex_ = xex_module->xex(); + processor_module_ = xex_module.get(); + if (!processor->AddModule(std::move(xex_module))) { return X_STATUS_UNSUCCESSFUL; } - // Copy the xex2 header into guest memory - const xex2_header* header = reinterpret_cast(addr); - uint32_t header_size = xex2_get_header_size(header); + // Copy the xex2 header into guest memory. + const xex2_header* header = this->xex_module()->xex_header(); + guest_xex_header_ = memory()->SystemHeapAlloc(header->header_size); - xex_header_ = memory()->SystemHeapAlloc(header_size); - - uint8_t* xex_header_ptr = memory()->TranslateVirtual(xex_header_); - std::memcpy(xex_header_ptr, header, header_size); + uint8_t* xex_header_ptr = memory()->TranslateVirtual(guest_xex_header_); + std::memcpy(xex_header_ptr, header, header->header_size); // Setup the loader data entry auto ldr_data = memory()->TranslateVirtual(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. - auto xex_module = std::make_unique(processor, kernel_state()); - if (!xex_module->Load(name_, path_, xex_)) { - return X_STATUS_UNSUCCESSFUL; - } - processor_module_ = xex_module.get(); - if (!processor->AddModule(std::move(xex_module))) { - return X_STATUS_UNSUCCESSFUL; - } + ldr_data->xex_header_base = guest_xex_header_; OnLoad(); @@ -146,7 +136,7 @@ X_STATUS XUserModule::GetSection(const char* name, uint32_t* out_section_data, X_STATUS XUserModule::GetOptHeader(xe_xex2_header_keys key, uint32_t* out_header_guest_ptr) { - auto header = memory()->TranslateVirtual(xex_header_); + auto header = xex_module()->xex_header(); if (!header) { return X_STATUS_UNSUCCESSFUL; } diff --git a/src/xenia/kernel/objects/xuser_module.h b/src/xenia/kernel/objects/xuser_module.h index 18e2156ea..54ed496fe 100644 --- a/src/xenia/kernel/objects/xuser_module.h +++ b/src/xenia/kernel/objects/xuser_module.h @@ -18,6 +18,10 @@ #include "xenia/xbox.h" namespace xe { +namespace cpu { +class XexModule; +} // namespace cpu + namespace kernel { class XUserModule : public XModule { @@ -25,8 +29,10 @@ class XUserModule : public XModule { XUserModule(KernelState* kernel_state, const char* path); ~XUserModule() override; - xe_xex2_ref xex(); const xe_xex2_header_t* xex_header(); + const xe::cpu::XexModule* xex_module() const { + return reinterpret_cast(processor_module_); + } X_STATUS LoadFromFile(std::string path); X_STATUS LoadFromMemory(const void* addr, const size_t length); @@ -48,7 +54,7 @@ class XUserModule : public XModule { private: xe_xex2_ref xex_; - uint32_t xex_header_; + uint32_t guest_xex_header_; }; } // namespace kernel diff --git a/src/xenia/kernel/util/xex2_info.h b/src/xenia/kernel/util/xex2_info.h index 4d0a5409f..7a3ecd0b1 100644 --- a/src/xenia/kernel/util/xex2_info.h +++ b/src/xenia/kernel/util/xex2_info.h @@ -470,9 +470,8 @@ typedef struct { } xe_xex2_header_t; namespace xe { -namespace kernel { union xex2_version { - uint32_t value; + xe::be value; struct { uint32_t major : 4; uint32_t minor : 4; @@ -481,6 +480,22 @@ union xex2_version { }; }; +struct xex2_opt_delta_patch_descriptor { + xe::be size; // 0x0 + xex2_version target_version; // 0x4 + xex2_version source_version; // 0x8 + char digest_source[0x14]; // 0xC + char image_key_source[0x10]; // 0x20 + xe::be size_of_target_headers; // 0x30 + xe::be delta_headers_source_offset; // 0x34 + xe::be delta_headers_source_size; // 0x38 + xe::be delta_headers_target_offset; // 0x3C + xe::be delta_image_source_offset; // 0x40 + xe::be delta_image_source_size; // 0x44 + xe::be delta_image_target_offset; // 0x48 +}; +static_assert_size(xex2_opt_delta_patch_descriptor, 0x4C); + struct xex2_opt_execution_info { xe::be media_id; // 0x0 xe::be version; // 0x4 @@ -492,32 +507,64 @@ struct xex2_opt_execution_info { uint8_t disc_count; // 0x13 xe::be savegame_id; // 0x14 }; +static_assert_size(xex2_opt_execution_info, 0x18); + +struct xex2_opt_import_libraries { + xe::be section_size; // 0x0 + xe::be string_table_size; // 0x4 + xe::be library_count; // 0x8 + char string_table[1]; // 0xC string_table_size bytes +}; + +struct xex2_import_library { + xe::be size; // 0x0 + char next_import_digest[0x14]; // 0x4 + xe::be id; // 0x18 + xex2_version version; // 0x1C + xex2_version version_min; // 0x20 + xe::be name_index; // 0x24 + xe::be count; // 0x26 + xe::be import_table[1]; // 0x28 +}; struct xex2_opt_header { xe::be key; // 0x0 union { xe::be value; // 0x4 - xe::be offset; // 0x8 + xe::be offset; // 0x4 }; }; struct xex2_header { xe::be magic; // 0x0 'XEX2' xe::be module_flags; // 0x4 - xe::be exe_offset; // 0x8 + xe::be header_size; // 0x8 xe::be reserved; // 0xC - xe::be certificate_offset; // 0x10 + xe::be security_offset; // 0x10 xe::be header_count; // 0x14 xex2_opt_header headers[1]; // 0x18 }; -struct xex2_loader_info { - xe::be header_size; - xe::be image_size; +struct xex2_security_info { + xe::be header_size; // 0x0 + xe::be image_size; // 0x4 + char rsa_signature[0x100]; // 0x8 + xe::be unk_108; // 0x108 unk length + xe::be image_flags; // 0x10C + xe::be load_address; // 0x110 + char section_digest[0x14]; // 0x114 + xe::be import_table_count; // 0x128 + char import_table_digest[0x14]; // 0x12C + char xgd2_media_id[0x10]; // 0x140 + char aes_key[0x10]; // 0x150 + xe::be export_table; // 0x160 + char header_digest[0x14]; // 0x164 + xe::be region; // 0x178 + xe::be allowed_media_types; // 0x17C }; -} // namespace kernel +static_assert_size(xex2_security_info, 0x180); } // namespace xe #endif // XENIA_KERNEL_XEX2_INFO_H_