[CPU] Move XEX2 code into XexModule class, autodetect XEX key

Code is mainly just copy/pasted from kernel/util/xex2.cc, I've tried fixing it up to work better in a class, but there's probably some things I missed.

Also includes some minor improvements to the XEX loader, like being able to try both XEX keys (retail/devkit) automatically, and some fixes to how the base address is determined.

(Previously there was code that would get base address from optional header, code that'd get it from xex_security_info, code that'd use a stored base address value...
Now everything reads it from a single stored value instead, which is set either from the xex_security_info, or if it exists from the optional header instead.
Maybe this can help improve compatibility with any weird XEX's that don't have a base address optional header?)

Compressed XEX loader also has some extra checks to make sure the compressed data hash matches what's expected.
Might increase loading times by a fraction, but could save reports from people unknowingly using corrupt XEXs.
(still no checks for non-compressed data though, maybe need to compare data with xex_security_info->ImageHash?)
This commit is contained in:
emoose
2018-10-20 04:18:18 +01:00
parent 2fa7607547
commit 0b7f7e1657
13 changed files with 939 additions and 1579 deletions

View File

@@ -14,7 +14,6 @@
#include <vector>
#include "xenia/cpu/module.h"
#include "xenia/kernel/util/xex2.h"
#include "xenia/kernel/util/xex2_info.h"
namespace xe {
@@ -30,40 +29,73 @@ class Runtime;
class XexModule : public xe::cpu::Module {
public:
struct ImportLibraryFn {
public:
uint32_t Ordinal;
uint32_t ValueAddress;
uint32_t ThunkAddress;
};
struct ImportLibrary {
public:
std::string Name;
uint32_t ID;
xe_xex2_version_t Version;
xe_xex2_version_t MinVersion;
std::vector<ImportLibraryFn> Imports;
};
XexModule(Processor* processor, kernel::KernelState* kernel_state);
virtual ~XexModule();
xe_xex2_ref xex() const { return xex_; }
bool loaded() const { return loaded_; }
const xex2_header* xex_header() const {
return reinterpret_cast<const xex2_header*>(xex_header_mem_.data());
}
const xex2_security_info* xex_security_info() const {
return GetSecurityInfo(xex_header());
return reinterpret_cast<const xex2_security_info*>(
uintptr_t(xex_header()) + xex_header()->security_offset);
}
const std::vector<ImportLibrary>* import_libraries() const {
return &import_libs_;
}
const xex2_opt_execution_info* opt_execution_info() const {
xex2_opt_execution_info* retval = nullptr;
GetOptHeader(XEX_HEADER_EXECUTION_INFO, &retval);
return retval;
}
const xex2_opt_file_format_info* opt_file_format_info() const {
xex2_opt_file_format_info* retval = nullptr;
GetOptHeader(XEX_HEADER_FILE_FORMAT_INFO, &retval);
return retval;
}
const uint32_t base_address() const { return base_address_; }
// Gets an optional header. Returns NULL if not found.
// Special case: if key & 0xFF == 0x00, this function will return the value,
// not a pointer! This assumes out_ptr points to uint32_t.
static bool GetOptHeader(const xex2_header* header, xe_xex2_header_keys key,
static bool GetOptHeader(const xex2_header* header, xex2_header_keys key,
void** out_ptr);
bool GetOptHeader(xe_xex2_header_keys key, void** out_ptr) const;
bool GetOptHeader(xex2_header_keys key, void** out_ptr) const;
// Ultra-cool templated version
// Special case: if key & 0xFF == 0x00, this function will return the value,
// not a pointer! This assumes out_ptr points to uint32_t.
template <typename T>
static bool GetOptHeader(const xex2_header* header, xe_xex2_header_keys key,
static bool GetOptHeader(const xex2_header* header, xex2_header_keys key,
T* out_ptr) {
return GetOptHeader(header, key, reinterpret_cast<void**>(out_ptr));
}
template <typename T>
bool GetOptHeader(xe_xex2_header_keys key, T* out_ptr) const {
bool GetOptHeader(xex2_header_keys key, T* out_ptr) const {
return GetOptHeader(key, reinterpret_cast<void**>(out_ptr));
}
static const xex2_security_info* GetSecurityInfo(const xex2_header* header);
const PESection* GetPESection(const char* name);
uint32_t GetProcAddress(uint16_t ordinal) const;
uint32_t GetProcAddress(const char* name) const;
@@ -71,7 +103,6 @@ class XexModule : public xe::cpu::Module {
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);
bool Unload();
const std::string& name() const override { return name_; }
@@ -81,10 +112,31 @@ class XexModule : public xe::cpu::Module {
bool ContainsAddress(uint32_t address) override;
static void DecryptBuffer(const uint8_t* session_key,
const uint8_t* input_buffer,
const size_t input_size, uint8_t* output_buffer,
const size_t output_size);
uint8_t* HostData() {
if (base_address_)
return memory()->TranslateVirtual(base_address_);
else
return nullptr;
}
protected:
std::unique_ptr<Function> CreateFunction(uint32_t address) override;
private:
void DecryptSessionKey(bool useDevkit = false);
int ReadImage(const void* xex_addr, size_t xex_length);
int ReadImageUncompressed(const void* xex_addr, size_t xex_length);
int ReadImageBasicCompressed(const void* xex_addr, size_t xex_length);
int ReadImageCompressed(const void* xex_addr, size_t xex_length);
int ReadPEHeaders();
bool SetupLibraryImports(const char* name,
const xex2_import_library* library);
bool FindSaveRest();
@@ -93,13 +145,23 @@ class XexModule : public xe::cpu::Module {
kernel::KernelState* kernel_state_ = nullptr;
std::string name_;
std::string path_;
xe_xex2_ref xex_ = nullptr;
std::vector<uint8_t> xex_header_mem_; // Holds the xex header
bool loaded_ = false; // Loaded into memory?
// various optional headers
std::vector<ImportLibrary>
import_libs_; // pre-loaded import libraries for ease of use
std::vector<PESection> pe_sections_;
uint8_t session_key_[0x10];
bool loaded_ = false; // Loaded into memory?
uint32_t base_address_ = 0;
uint32_t low_address_ = 0;
uint32_t high_address_ = 0;
bool is_dev_kit_ = false;
};
} // namespace cpu