Moving all kernel files around just to fuck with whoever's keeping track ;)
This commit is contained in:
69
src/xenia/kernel/util/shim_utils.h
Normal file
69
src/xenia/kernel/util/shim_utils.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_UTIL_SHIM_UTILS_H_
|
||||
#define XENIA_KERNEL_UTIL_SHIM_UTILS_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
#include <xenia/core.h>
|
||||
|
||||
#include <alloy/frontend/ppc/ppc_context.h>
|
||||
#include <xenia/export_resolver.h>
|
||||
#include <xenia/kernel/kernel_module.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
using PPCContext = alloy::frontend::ppc::PPCContext;
|
||||
|
||||
|
||||
#define SHIM_CALL void _cdecl
|
||||
#define SHIM_SET_MAPPING(library_name, export_name, shim_data) \
|
||||
export_resolver->SetFunctionMapping( \
|
||||
library_name, ordinals::##export_name, \
|
||||
shim_data, \
|
||||
(xe_kernel_export_shim_fn)export_name##_shim, \
|
||||
NULL);
|
||||
|
||||
#define SHIM_MEM_BASE ppc_state->membase
|
||||
#define SHIM_MEM_ADDR(a) (a ? (ppc_state->membase + a) : NULL)
|
||||
|
||||
#define SHIM_MEM_16(a) (uint16_t)XEGETUINT16BE(SHIM_MEM_ADDR(a))
|
||||
#define SHIM_MEM_32(a) (uint32_t)XEGETUINT32BE(SHIM_MEM_ADDR(a))
|
||||
#define SHIM_MEM_64(a) (uint64_t)XEGETUINT64BE(SHIM_MEM_ADDR(a))
|
||||
#define SHIM_SET_MEM_16(a, v) (*(uint16_t*)SHIM_MEM_ADDR(a)) = XESWAP16(v)
|
||||
#define SHIM_SET_MEM_32(a, v) (*(uint32_t*)SHIM_MEM_ADDR(a)) = XESWAP32(v)
|
||||
#define SHIM_SET_MEM_64(a, v) (*(uint64_t*)SHIM_MEM_ADDR(a)) = XESWAP64(v)
|
||||
|
||||
#define SHIM_GPR_16(n) (uint16_t)(ppc_state->r[n])
|
||||
#define SHIM_GPR_32(n) (uint32_t)(ppc_state->r[n])
|
||||
#define SHIM_SET_GPR_32(n, v) ppc_state->r[n] = (uint64_t)((v) & UINT32_MAX)
|
||||
#define SHIM_GPR_64(n) ppc_state->r[n]
|
||||
#define SHIM_SET_GPR_64(n, v) ppc_state->r[n] = (uint64_t)(v)
|
||||
|
||||
#define SHIM_GET_ARG_16(n) SHIM_GPR_16(3 + n)
|
||||
#define SHIM_GET_ARG_32(n) SHIM_GPR_32(3 + n)
|
||||
#define SHIM_GET_ARG_64(n) SHIM_GPR_64(3 + n)
|
||||
#define SHIM_SET_RETURN(v) SHIM_SET_GPR_64(3, v)
|
||||
|
||||
|
||||
#define IMPL_MEM_ADDR(a) (a ? state->memory()->Translate(a) : NULL)
|
||||
|
||||
#define IMPL_MEM_16(a) (uint16_t)XEGETUINT16BE(IMPL_MEM_ADDR(a))
|
||||
#define IMPL_MEM_32(a) (uint32_t)XEGETUINT32BE(IMPL_MEM_ADDR(a))
|
||||
#define IMPL_SET_MEM_16(a, v) (*(uint16_t*)IMPL_MEM_ADDR(a)) = XESWAP16(v)
|
||||
#define IMPL_SET_MEM_32(a, v) (*(uint32_t*)IMPL_MEM_ADDR(a)) = XESWAP32(v)
|
||||
|
||||
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_UTIL_SHIM_UTILS_H_
|
||||
@@ -5,5 +5,9 @@
|
||||
'export_table_pre.inc',
|
||||
'ordinal_table_post.inc',
|
||||
'ordinal_table_pre.inc',
|
||||
'shim_utils.h',
|
||||
'xex2.cc',
|
||||
'xex2.h',
|
||||
'xex2_info.h',
|
||||
],
|
||||
}
|
||||
|
||||
977
src/xenia/kernel/util/xex2.cc
Normal file
977
src/xenia/kernel/util/xex2.cc
Normal file
@@ -0,0 +1,977 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <xenia/kernel/util/xex2.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <third_party/crypto/rijndael-alg-fst.h>
|
||||
#include <third_party/crypto/rijndael-alg-fst.c>
|
||||
#include <third_party/mspack/lzx.h>
|
||||
#include <third_party/mspack/lzxd.c>
|
||||
#include <third_party/mspack/mspack.h>
|
||||
#include <third_party/pe/pe_image.h>
|
||||
|
||||
using namespace alloy;
|
||||
|
||||
|
||||
typedef struct xe_xex2 {
|
||||
xe_ref_t ref;
|
||||
|
||||
Memory* memory;
|
||||
|
||||
xe_xex2_header_t header;
|
||||
|
||||
std::vector<PESection*>* sections;
|
||||
} xe_xex2_t;
|
||||
|
||||
|
||||
int xe_xex2_read_header(const uint8_t *addr, const size_t length,
|
||||
xe_xex2_header_t *header);
|
||||
int xe_xex2_decrypt_key(xe_xex2_header_t *header);
|
||||
int xe_xex2_read_image(xe_xex2_ref xex,
|
||||
const uint8_t *xex_addr, const size_t xex_length,
|
||||
Memory* memory);
|
||||
int xe_xex2_load_pe(xe_xex2_ref xex);
|
||||
|
||||
|
||||
xe_xex2_ref xe_xex2_load(Memory* memory,
|
||||
const void* addr, const size_t length,
|
||||
xe_xex2_options_t options) {
|
||||
xe_xex2_ref xex = (xe_xex2_ref)xe_calloc(sizeof(xe_xex2));
|
||||
xe_ref_init((xe_ref)xex);
|
||||
|
||||
xex->memory = memory;
|
||||
xex->sections = new std::vector<PESection*>();
|
||||
|
||||
XEEXPECTZERO(xe_xex2_read_header((const uint8_t*)addr, length, &xex->header));
|
||||
|
||||
XEEXPECTZERO(xe_xex2_decrypt_key(&xex->header));
|
||||
|
||||
XEEXPECTZERO(xe_xex2_read_image(xex, (const uint8_t*)addr, length, memory));
|
||||
|
||||
XEEXPECTZERO(xe_xex2_load_pe(xex));
|
||||
|
||||
return xex;
|
||||
|
||||
XECLEANUP:
|
||||
xe_xex2_release(xex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void xe_xex2_dealloc(xe_xex2_ref xex) {
|
||||
for (std::vector<PESection*>::iterator it = xex->sections->begin();
|
||||
it != xex->sections->end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
|
||||
xe_xex2_header_t *header = &xex->header;
|
||||
xe_free(header->sections);
|
||||
if (header->file_format_info.compression_type == XEX_COMPRESSION_BASIC) {
|
||||
xe_free(header->file_format_info.compression_info.basic.blocks);
|
||||
}
|
||||
for (size_t n = 0; n < header->import_library_count; n++) {
|
||||
xe_xex2_import_library_t *library = &header->import_libraries[n];
|
||||
xe_free(library->records);
|
||||
}
|
||||
|
||||
xex->memory = NULL;
|
||||
}
|
||||
|
||||
xe_xex2_ref xe_xex2_retain(xe_xex2_ref xex) {
|
||||
xe_ref_retain((xe_ref)xex);
|
||||
return xex;
|
||||
}
|
||||
|
||||
void xe_xex2_release(xe_xex2_ref xex) {
|
||||
xe_ref_release((xe_ref)xex, (xe_ref_dealloc_t)xe_xex2_dealloc);
|
||||
}
|
||||
|
||||
const xechar_t* xe_xex2_get_name(xe_xex2_ref xex) {
|
||||
// TODO(benvanik): get name.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const xe_xex2_header_t* xe_xex2_get_header(xe_xex2_ref xex) {
|
||||
return &xex->header;
|
||||
}
|
||||
|
||||
int xe_xex2_read_header(const uint8_t *addr, const size_t length,
|
||||
xe_xex2_header_t *header) {
|
||||
const uint8_t *p = addr;
|
||||
const uint8_t *pc;
|
||||
const uint8_t *ps;
|
||||
xe_xex2_loader_info_t *ldr;
|
||||
|
||||
header->xex2 = XEGETUINT32BE(p + 0x00);
|
||||
if (header->xex2 != 0x58455832) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
header->module_flags = (xe_xex2_module_flags)XEGETUINT32BE(p + 0x04);
|
||||
header->exe_offset = XEGETUINT32BE(p + 0x08);
|
||||
header->unknown0 = XEGETUINT32BE(p + 0x0C);
|
||||
header->certificate_offset = XEGETUINT32BE(p + 0x10);
|
||||
header->header_count = XEGETUINT32BE(p + 0x14);
|
||||
|
||||
for (size_t n = 0; n < header->header_count; n++) {
|
||||
const uint8_t *ph = p + 0x18 + (n * 8);
|
||||
const uint32_t key = XEGETUINT32BE(ph + 0x00);
|
||||
const uint32_t data_offset = XEGETUINT32BE(ph + 0x04);
|
||||
|
||||
xe_xex2_opt_header_t *opt_header = &header->headers[n];
|
||||
opt_header->key = key;
|
||||
switch (key & 0xFF) {
|
||||
case 0x01:
|
||||
// dataOffset = data
|
||||
opt_header->length = 0;
|
||||
opt_header->value = data_offset;
|
||||
break;
|
||||
case 0xFF:
|
||||
// dataOffset = offset (first dword in data is size)
|
||||
opt_header->length = XEGETUINT32BE(p + data_offset);
|
||||
opt_header->offset = data_offset;
|
||||
break;
|
||||
default:
|
||||
// dataOffset = size in dwords
|
||||
opt_header->length = (key & 0xFF) * 4;
|
||||
opt_header->offset = data_offset;
|
||||
break;
|
||||
}
|
||||
|
||||
const uint8_t *pp = p + opt_header->offset;
|
||||
switch (opt_header->key) {
|
||||
case XEX_HEADER_SYSTEM_FLAGS:
|
||||
header->system_flags = (xe_xex2_system_flags)data_offset;
|
||||
break;
|
||||
case XEX_HEADER_RESOURCE_INFO:
|
||||
{
|
||||
xe_xex2_resource_info_t *res = &header->resource_info;
|
||||
XEEXPECTZERO(xe_copy_memory(res->title_id,
|
||||
sizeof(res->title_id), pp + 0x04, 8));
|
||||
res->address = XEGETUINT32BE(pp + 0x0C);
|
||||
res->size = XEGETUINT32BE(pp + 0x10);
|
||||
if ((opt_header->length - 4) / 16 > 1) {
|
||||
// Ignoring extra resources (not yet seen)
|
||||
XELOGW("ignoring extra XEX_HEADER_RESOURCE_INFO resources");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XEX_HEADER_EXECUTION_INFO:
|
||||
{
|
||||
xe_xex2_execution_info_t *ex = &header->execution_info;
|
||||
ex->media_id = XEGETUINT32BE(pp + 0x00);
|
||||
ex->version.value = XEGETUINT32BE(pp + 0x04);
|
||||
ex->base_version.value = XEGETUINT32BE(pp + 0x08);
|
||||
ex->title_id = XEGETUINT32BE(pp + 0x0C);
|
||||
ex->platform = XEGETUINT8BE(pp + 0x10);
|
||||
ex->executable_table = XEGETUINT8BE(pp + 0x11);
|
||||
ex->disc_number = XEGETUINT8BE(pp + 0x12);
|
||||
ex->disc_count = XEGETUINT8BE(pp + 0x13);
|
||||
ex->savegame_id = XEGETUINT32BE(pp + 0x14);
|
||||
}
|
||||
break;
|
||||
case XEX_HEADER_GAME_RATINGS:
|
||||
{
|
||||
xe_xex2_game_ratings_t *ratings = &header->game_ratings;
|
||||
ratings->esrb = (xe_xex2_rating_esrb_value)XEGETUINT8BE(pp + 0x00);
|
||||
ratings->pegi = (xe_xex2_rating_pegi_value)XEGETUINT8BE(pp + 0x01);
|
||||
ratings->pegifi = (xe_xex2_rating_pegi_fi_value)XEGETUINT8BE(pp + 0x02);
|
||||
ratings->pegipt = (xe_xex2_rating_pegi_pt_value)XEGETUINT8BE(pp + 0x03);
|
||||
ratings->bbfc = (xe_xex2_rating_bbfc_value)XEGETUINT8BE(pp + 0x04);
|
||||
ratings->cero = (xe_xex2_rating_cero_value)XEGETUINT8BE(pp + 0x05);
|
||||
ratings->usk = (xe_xex2_rating_usk_value)XEGETUINT8BE(pp + 0x06);
|
||||
ratings->oflcau = (xe_xex2_rating_oflc_au_value)XEGETUINT8BE(pp + 0x07);
|
||||
ratings->oflcnz = (xe_xex2_rating_oflc_nz_value)XEGETUINT8BE(pp + 0x08);
|
||||
ratings->kmrb = (xe_xex2_rating_kmrb_value)XEGETUINT8BE(pp + 0x09);
|
||||
ratings->brazil = (xe_xex2_rating_brazil_value)XEGETUINT8BE(pp + 0x0A);
|
||||
ratings->fpb = (xe_xex2_rating_fpb_value)XEGETUINT8BE(pp + 0x0B);
|
||||
}
|
||||
break;
|
||||
case XEX_HEADER_TLS_INFO:
|
||||
{
|
||||
xe_xex2_tls_info_t *tls = &header->tls_info;
|
||||
tls->slot_count = XEGETUINT32BE(pp + 0x00);
|
||||
tls->raw_data_address = XEGETUINT32BE(pp + 0x04);
|
||||
tls->data_size = XEGETUINT32BE(pp + 0x08);
|
||||
tls->raw_data_size = XEGETUINT32BE(pp + 0x0C);
|
||||
}
|
||||
break;
|
||||
case XEX_HEADER_IMAGE_BASE_ADDRESS:
|
||||
header->exe_address = opt_header->value;
|
||||
break;
|
||||
case XEX_HEADER_ENTRY_POINT:
|
||||
header->exe_entry_point = opt_header->value;
|
||||
break;
|
||||
case XEX_HEADER_DEFAULT_STACK_SIZE:
|
||||
header->exe_stack_size = opt_header->value;
|
||||
break;
|
||||
case XEX_HEADER_DEFAULT_HEAP_SIZE:
|
||||
header->exe_heap_size = opt_header->value;
|
||||
break;
|
||||
case XEX_HEADER_IMPORT_LIBRARIES:
|
||||
{
|
||||
const size_t max_count = XECOUNT(header->import_libraries);
|
||||
size_t count = XEGETUINT32BE(pp + 0x08);
|
||||
XEASSERT(count <= max_count);
|
||||
if (count > max_count) {
|
||||
XELOGW("ignoring %zu extra entries in XEX_HEADER_IMPORT_LIBRARIES",
|
||||
(max_count - count));
|
||||
count = max_count;
|
||||
}
|
||||
header->import_library_count = count;
|
||||
|
||||
uint32_t string_table_size = XEGETUINT32BE(pp + 0x04);
|
||||
const char *string_table = (const char*)(pp + 0x0C);
|
||||
|
||||
pp += 12 + string_table_size;
|
||||
for (size_t m = 0; m < count; m++) {
|
||||
xe_xex2_import_library_t *library = &header->import_libraries[m];
|
||||
XEEXPECTZERO(xe_copy_memory(library->digest, sizeof(library->digest),
|
||||
pp + 0x04, 20));
|
||||
library->import_id = XEGETUINT32BE(pp + 0x18);
|
||||
library->version.value = XEGETUINT32BE(pp + 0x1C);
|
||||
library->min_version.value = XEGETUINT32BE(pp + 0x20);
|
||||
|
||||
const uint16_t name_index = XEGETUINT16BE(pp + 0x24);
|
||||
for (size_t i = 0, j = 0; i < string_table_size;) {
|
||||
if (j == name_index) {
|
||||
XEIGNORE(xestrcpya(library->name, XECOUNT(library->name),
|
||||
string_table + i));
|
||||
break;
|
||||
}
|
||||
if (string_table[i] == 0) {
|
||||
i++;
|
||||
if (i % 4) {
|
||||
i += 4 - (i % 4);
|
||||
}
|
||||
j++;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
library->record_count = XEGETUINT16BE(pp + 0x26);
|
||||
library->records = (uint32_t*)xe_calloc(
|
||||
library->record_count * sizeof(uint32_t));
|
||||
XEEXPECTNOTNULL(library->records);
|
||||
pp += 0x28;
|
||||
for (size_t i = 0; i < library->record_count; i++) {
|
||||
library->records[i] = XEGETUINT32BE(pp);
|
||||
pp += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XEX_HEADER_STATIC_LIBRARIES:
|
||||
{
|
||||
const size_t max_count = XECOUNT(header->static_libraries);
|
||||
size_t count = (opt_header->length - 4) / 16;
|
||||
XEASSERT(count <= max_count);
|
||||
if (count > max_count) {
|
||||
XELOGW("ignoring %zu extra entries in XEX_HEADER_STATIC_LIBRARIES",
|
||||
(max_count - count));
|
||||
count = max_count;
|
||||
}
|
||||
header->static_library_count = count;
|
||||
pp += 4;
|
||||
for (size_t m = 0; m < count; m++) {
|
||||
xe_xex2_static_library_t *library = &header->static_libraries[m];
|
||||
XEEXPECTZERO(xe_copy_memory(library->name, sizeof(library->name),
|
||||
pp + 0x00, 8));
|
||||
library->name[8] = 0;
|
||||
library->major = XEGETUINT16BE(pp + 0x08);
|
||||
library->minor = XEGETUINT16BE(pp + 0x0A);
|
||||
library->build = XEGETUINT16BE(pp + 0x0C);
|
||||
uint16_t qfeapproval = XEGETUINT16BE(pp + 0x0E);
|
||||
library->approval = (xe_xex2_approval_type)(qfeapproval & 0x8000);
|
||||
library->qfe = qfeapproval & ~0x8000;
|
||||
pp += 16;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XEX_HEADER_FILE_FORMAT_INFO:
|
||||
{
|
||||
xe_xex2_file_format_info_t *fmt = &header->file_format_info;
|
||||
fmt->encryption_type =
|
||||
(xe_xex2_encryption_type)XEGETUINT16BE(pp + 0x04);
|
||||
fmt->compression_type =
|
||||
(xe_xex2_compression_type)XEGETUINT16BE(pp + 0x06);
|
||||
switch (fmt->compression_type) {
|
||||
case XEX_COMPRESSION_NONE:
|
||||
// TODO: XEX_COMPRESSION_NONE
|
||||
XEASSERTALWAYS();
|
||||
break;
|
||||
case XEX_COMPRESSION_BASIC:
|
||||
{
|
||||
xe_xex2_file_basic_compression_info_t *comp_info =
|
||||
&fmt->compression_info.basic;
|
||||
uint32_t info_size = XEGETUINT32BE(pp + 0x00);
|
||||
comp_info->block_count = (info_size - 8) / 8;
|
||||
comp_info->blocks = (xe_xex2_file_basic_compression_block_t*)
|
||||
xe_calloc(comp_info->block_count *
|
||||
sizeof(xe_xex2_file_basic_compression_block_t));
|
||||
XEEXPECTNOTNULL(comp_info->blocks);
|
||||
for (size_t m = 0; m < comp_info->block_count; m++) {
|
||||
xe_xex2_file_basic_compression_block_t *block =
|
||||
&comp_info->blocks[m];
|
||||
block->data_size = XEGETUINT32BE(pp + 0x08 + (m * 8));
|
||||
block->zero_size = XEGETUINT32BE(pp + 0x0C + (m * 8));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XEX_COMPRESSION_NORMAL:
|
||||
{
|
||||
xe_xex2_file_normal_compression_info_t *comp_info =
|
||||
&fmt->compression_info.normal;
|
||||
uint32_t window_size = XEGETUINT32BE(pp + 0x08);
|
||||
uint32_t window_bits = 0;
|
||||
for (size_t m = 0; m < 32; m++, window_bits++) {
|
||||
window_size <<= 1;
|
||||
if (window_size == 0x80000000) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
comp_info->window_size = XEGETUINT32BE(pp + 0x08);
|
||||
comp_info->window_bits = window_bits;
|
||||
comp_info->block_size = XEGETUINT32BE(pp + 0x0C);
|
||||
XEEXPECTZERO(xe_copy_memory(comp_info->block_hash,
|
||||
sizeof(comp_info->block_hash),
|
||||
pp + 0x10, 20));
|
||||
}
|
||||
break;
|
||||
case XEX_COMPRESSION_DELTA:
|
||||
// TODO: XEX_COMPRESSION_DELTA
|
||||
XEASSERTALWAYS();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Loader info.
|
||||
pc = p + header->certificate_offset;
|
||||
ldr = &header->loader_info;
|
||||
ldr->header_size = XEGETUINT32BE(pc + 0x000);
|
||||
ldr->image_size = XEGETUINT32BE(pc + 0x004);
|
||||
XEEXPECTZERO(xe_copy_memory(ldr->rsa_signature, sizeof(ldr->rsa_signature),
|
||||
pc + 0x008, 256));
|
||||
ldr->unklength = XEGETUINT32BE(pc + 0x108);
|
||||
ldr->image_flags = (xe_xex2_image_flags)XEGETUINT32BE(pc + 0x10C);
|
||||
ldr->load_address = XEGETUINT32BE(pc + 0x110);
|
||||
XEEXPECTZERO(xe_copy_memory(ldr->section_digest, sizeof(ldr->section_digest),
|
||||
pc + 0x114, 20));
|
||||
ldr->import_table_count = XEGETUINT32BE(pc + 0x128);
|
||||
XEEXPECTZERO(xe_copy_memory(ldr->import_table_digest,
|
||||
sizeof(ldr->import_table_digest),
|
||||
pc + 0x12C, 20));
|
||||
XEEXPECTZERO(xe_copy_memory(ldr->media_id, sizeof(ldr->media_id),
|
||||
pc + 0x140, 16));
|
||||
XEEXPECTZERO(xe_copy_memory(ldr->file_key, sizeof(ldr->file_key),
|
||||
pc + 0x150, 16));
|
||||
ldr->export_table = XEGETUINT32BE(pc + 0x160);
|
||||
XEEXPECTZERO(xe_copy_memory(ldr->header_digest, sizeof(ldr->header_digest),
|
||||
pc + 0x164, 20));
|
||||
ldr->game_regions = (xe_xex2_region_flags)XEGETUINT32BE(pc + 0x178);
|
||||
ldr->media_flags = (xe_xex2_media_flags)XEGETUINT32BE(pc + 0x17C);
|
||||
|
||||
// Section info follows loader info.
|
||||
ps = p + header->certificate_offset + 0x180;
|
||||
header->section_count = XEGETUINT32BE(ps + 0x000);
|
||||
ps += 4;
|
||||
header->sections = (xe_xex2_section_t*)xe_calloc(
|
||||
header->section_count * sizeof(xe_xex2_section_t));
|
||||
XEEXPECTNOTNULL(header->sections);
|
||||
for (size_t n = 0; n < header->section_count; n++) {
|
||||
xe_xex2_section_t *section = &header->sections[n];
|
||||
section->info.value = XEGETUINT32BE(ps);
|
||||
ps += 4;
|
||||
XEEXPECTZERO(xe_copy_memory(section->digest, sizeof(section->digest), ps,
|
||||
sizeof(section->digest)));
|
||||
ps += sizeof(section->digest);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
XECLEANUP:
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xe_xex2_decrypt_key(xe_xex2_header_t *header) {
|
||||
const static uint8_t xe_xex2_retail_key[16] = {
|
||||
0x20, 0xB1, 0x85, 0xA5, 0x9D, 0x28, 0xFD, 0xC3,
|
||||
0x40, 0x58, 0x3F, 0xBB, 0x08, 0x96, 0xBF, 0x91
|
||||
};
|
||||
const static uint8_t xe_xex2_devkit_key[16] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
// Guess key based on file info.
|
||||
// TODO: better way to finding out which key to use?
|
||||
const uint8_t *xexkey;
|
||||
if (header->execution_info.title_id) {
|
||||
xexkey = xe_xex2_retail_key;
|
||||
} else {
|
||||
xexkey = xe_xex2_devkit_key;
|
||||
}
|
||||
|
||||
// Decrypt the header key.
|
||||
uint32_t rk[4 * (MAXNR + 1)];
|
||||
int32_t Nr = rijndaelKeySetupDec(rk, xexkey, 128);
|
||||
rijndaelDecrypt(rk, Nr,
|
||||
header->loader_info.file_key, header->session_key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct mspack_memory_file_t {
|
||||
struct mspack_system sys;
|
||||
void *buffer;
|
||||
off_t buffer_size;
|
||||
off_t offset;
|
||||
} mspack_memory_file;
|
||||
mspack_memory_file *mspack_memory_open(struct mspack_system *sys,
|
||||
void* buffer, const size_t buffer_size) {
|
||||
XEASSERT(buffer_size < INT_MAX);
|
||||
if (buffer_size >= INT_MAX) {
|
||||
return NULL;
|
||||
}
|
||||
mspack_memory_file *memfile = (mspack_memory_file*)xe_calloc(
|
||||
sizeof(mspack_memory_file));
|
||||
if (!memfile) {
|
||||
return NULL;
|
||||
}
|
||||
memfile->buffer = buffer;
|
||||
memfile->buffer_size = (off_t)buffer_size;
|
||||
memfile->offset = 0;
|
||||
return memfile;
|
||||
}
|
||||
void mspack_memory_close(mspack_memory_file *file) {
|
||||
mspack_memory_file *memfile = (mspack_memory_file*)file;
|
||||
xe_free(memfile);
|
||||
}
|
||||
int mspack_memory_read(struct mspack_file *file, void *buffer, int chars) {
|
||||
mspack_memory_file *memfile = (mspack_memory_file*)file;
|
||||
const off_t remaining = memfile->buffer_size - memfile->offset;
|
||||
const off_t total = MIN(chars, remaining);
|
||||
if (xe_copy_memory(buffer, total,
|
||||
(uint8_t*)memfile->buffer + memfile->offset, total)) {
|
||||
return -1;
|
||||
}
|
||||
memfile->offset += total;
|
||||
return (int)total;
|
||||
}
|
||||
int mspack_memory_write(struct mspack_file *file, void *buffer, int chars) {
|
||||
mspack_memory_file *memfile = (mspack_memory_file*)file;
|
||||
const off_t remaining = memfile->buffer_size - memfile->offset;
|
||||
const off_t total = MIN(chars, remaining);
|
||||
if (xe_copy_memory((uint8_t*)memfile->buffer + memfile->offset,
|
||||
memfile->buffer_size - memfile->offset, buffer, total)) {
|
||||
return -1;
|
||||
}
|
||||
memfile->offset += total;
|
||||
return (int)total;
|
||||
}
|
||||
void *mspack_memory_alloc(struct mspack_system *sys, size_t chars) {
|
||||
XEUNREFERENCED(sys);
|
||||
return xe_calloc(chars);
|
||||
}
|
||||
void mspack_memory_free(void *ptr) {
|
||||
xe_free(ptr);
|
||||
}
|
||||
void mspack_memory_copy(void *src, void *dest, size_t chars) {
|
||||
xe_copy_memory(dest, chars, src, chars);
|
||||
}
|
||||
struct mspack_system *mspack_memory_sys_create() {
|
||||
struct mspack_system *sys = (struct mspack_system *)xe_calloc(
|
||||
sizeof(struct mspack_system));
|
||||
if (!sys) {
|
||||
return NULL;
|
||||
}
|
||||
sys->read = mspack_memory_read;
|
||||
sys->write = mspack_memory_write;
|
||||
sys->alloc = mspack_memory_alloc;
|
||||
sys->free = mspack_memory_free;
|
||||
sys->copy = mspack_memory_copy;
|
||||
return sys;
|
||||
}
|
||||
void mspack_memory_sys_destroy(struct mspack_system *sys) {
|
||||
xe_free(sys);
|
||||
}
|
||||
|
||||
void xe_xex2_decrypt_buffer(const uint8_t *session_key,
|
||||
const uint8_t *input_buffer,
|
||||
const size_t input_size, uint8_t* output_buffer,
|
||||
const size_t output_size) {
|
||||
uint32_t rk[4 * (MAXNR + 1)];
|
||||
uint8_t ivec[16] = {0};
|
||||
int32_t Nr = rijndaelKeySetupDec(rk, session_key, 128);
|
||||
const uint8_t *ct = input_buffer;
|
||||
uint8_t* pt = output_buffer;
|
||||
for (size_t n = 0; n < input_size; n += 16, ct += 16, pt += 16) {
|
||||
// Decrypt 16 uint8_ts from input -> output.
|
||||
rijndaelDecrypt(rk, Nr, ct, pt);
|
||||
for (size_t i = 0; i < 16; i++) {
|
||||
// XOR with previous.
|
||||
pt[i] ^= ivec[i];
|
||||
// Set previous.
|
||||
ivec[i] = ct[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int xe_xex2_read_image_uncompressed(const xe_xex2_header_t *header,
|
||||
const uint8_t *xex_addr,
|
||||
const size_t xex_length,
|
||||
Memory* memory) {
|
||||
// Allocate in-place the XEX memory.
|
||||
const size_t exe_length = xex_length - header->exe_offset;
|
||||
size_t uncompressed_size = exe_length;
|
||||
uint32_t alloc_result = (uint32_t)memory->HeapAlloc(
|
||||
header->exe_address, uncompressed_size,
|
||||
MEMORY_FLAG_ZERO);
|
||||
if (!alloc_result) {
|
||||
XELOGE("Unable to allocate XEX memory at %.8X-%.8X.",
|
||||
header->exe_address, uncompressed_size);
|
||||
return 2;
|
||||
}
|
||||
uint8_t *buffer = memory->Translate(header->exe_address);
|
||||
|
||||
const uint8_t *p = (const uint8_t*)xex_addr + header->exe_offset;
|
||||
|
||||
switch (header->file_format_info.encryption_type) {
|
||||
case XEX_ENCRYPTION_NONE:
|
||||
return xe_copy_memory(buffer, uncompressed_size, p, exe_length);
|
||||
case XEX_ENCRYPTION_NORMAL:
|
||||
xe_xex2_decrypt_buffer(header->session_key, p, exe_length, buffer,
|
||||
uncompressed_size);
|
||||
return 0;
|
||||
default:
|
||||
XEASSERTALWAYS();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xe_xex2_read_image_basic_compressed(const xe_xex2_header_t *header,
|
||||
const uint8_t *xex_addr,
|
||||
const size_t xex_length,
|
||||
Memory* memory) {
|
||||
const size_t exe_length = xex_length - header->exe_offset;
|
||||
const uint8_t* source_buffer = (const uint8_t*)xex_addr + header->exe_offset;
|
||||
const uint8_t *p = source_buffer;
|
||||
|
||||
// Calculate uncompressed length.
|
||||
size_t uncompressed_size = 0;
|
||||
const xe_xex2_file_basic_compression_info_t* comp_info =
|
||||
&header->file_format_info.compression_info.basic;
|
||||
for (size_t n = 0; n < comp_info->block_count; n++) {
|
||||
const size_t data_size = comp_info->blocks[n].data_size;
|
||||
const size_t zero_size = comp_info->blocks[n].zero_size;
|
||||
uncompressed_size += data_size + zero_size;
|
||||
}
|
||||
|
||||
// Allocate in-place the XEX memory.
|
||||
uint32_t alloc_result = (uint32_t)memory->HeapAlloc(
|
||||
header->exe_address, uncompressed_size,
|
||||
MEMORY_FLAG_ZERO);
|
||||
if (!alloc_result) {
|
||||
XELOGE("Unable to allocate XEX memory at %.8X-%.8X.",
|
||||
header->exe_address, uncompressed_size);
|
||||
XEFAIL();
|
||||
}
|
||||
uint8_t *buffer = memory->Translate(header->exe_address);
|
||||
uint8_t *d = buffer;
|
||||
|
||||
uint32_t rk[4 * (MAXNR + 1)];
|
||||
uint8_t ivec[16] = {0};
|
||||
int32_t Nr = rijndaelKeySetupDec(rk, header->session_key, 128);
|
||||
|
||||
for (size_t n = 0; n < comp_info->block_count; n++) {
|
||||
const size_t data_size = comp_info->blocks[n].data_size;
|
||||
const size_t zero_size = comp_info->blocks[n].zero_size;
|
||||
|
||||
switch (header->file_format_info.encryption_type) {
|
||||
case XEX_ENCRYPTION_NONE:
|
||||
XEEXPECTZERO(xe_copy_memory(d, uncompressed_size - (d - buffer), p,
|
||||
exe_length - (p - source_buffer)));
|
||||
break;
|
||||
case XEX_ENCRYPTION_NORMAL:
|
||||
{
|
||||
const uint8_t *ct = p;
|
||||
uint8_t* pt = d;
|
||||
for (size_t n = 0; n < data_size; n += 16, ct += 16, pt += 16) {
|
||||
// Decrypt 16 uint8_ts from input -> output.
|
||||
rijndaelDecrypt(rk, Nr, ct, pt);
|
||||
for (size_t i = 0; i < 16; i++) {
|
||||
// XOR with previous.
|
||||
pt[i] ^= ivec[i];
|
||||
// Set previous.
|
||||
ivec[i] = ct[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
XEASSERTALWAYS();
|
||||
return 1;
|
||||
}
|
||||
|
||||
p += data_size;
|
||||
d += data_size + zero_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
XECLEANUP:
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xe_xex2_read_image_compressed(const xe_xex2_header_t *header,
|
||||
const uint8_t *xex_addr,
|
||||
const size_t xex_length,
|
||||
Memory* memory) {
|
||||
const size_t exe_length = xex_length - header->exe_offset;
|
||||
const uint8_t *exe_buffer = (const uint8_t*)xex_addr + header->exe_offset;
|
||||
|
||||
// src -> dest:
|
||||
// - decrypt (if encrypted)
|
||||
// - de-block:
|
||||
// 4b total size of next block in uint8_ts
|
||||
// 20b hash of entire next block (including size/hash)
|
||||
// Nb block uint8_ts
|
||||
// - decompress block contents
|
||||
|
||||
int result_code = 1;
|
||||
|
||||
uint8_t *compress_buffer = NULL;
|
||||
const uint8_t *p = NULL;
|
||||
uint8_t *d = NULL;
|
||||
uint8_t *deblock_buffer = NULL;
|
||||
size_t block_size = 0;
|
||||
size_t uncompressed_size = 0;
|
||||
struct mspack_system *sys = NULL;
|
||||
mspack_memory_file *lzxsrc = NULL;
|
||||
mspack_memory_file *lzxdst = NULL;
|
||||
struct lzxd_stream *lzxd = NULL;
|
||||
|
||||
// Decrypt (if needed).
|
||||
bool free_input = false;
|
||||
const uint8_t *input_buffer = exe_buffer;
|
||||
const size_t input_size = exe_length;
|
||||
switch (header->file_format_info.encryption_type) {
|
||||
case XEX_ENCRYPTION_NONE:
|
||||
// No-op.
|
||||
break;
|
||||
case XEX_ENCRYPTION_NORMAL:
|
||||
// TODO: a way to do without a copy/alloc?
|
||||
free_input = true;
|
||||
input_buffer = (const uint8_t*)xe_calloc(input_size);
|
||||
XEEXPECTNOTNULL(input_buffer);
|
||||
xe_xex2_decrypt_buffer(header->session_key, exe_buffer, exe_length,
|
||||
(uint8_t*)input_buffer, input_size);
|
||||
break;
|
||||
default:
|
||||
XEASSERTALWAYS();
|
||||
return false;
|
||||
}
|
||||
|
||||
compress_buffer = (uint8_t*)xe_calloc(exe_length);
|
||||
XEEXPECTNOTNULL(compress_buffer);
|
||||
|
||||
p = input_buffer;
|
||||
d = compress_buffer;
|
||||
|
||||
// De-block.
|
||||
deblock_buffer = (uint8_t*)xe_calloc(input_size);
|
||||
XEEXPECTNOTNULL(deblock_buffer);
|
||||
block_size = header->file_format_info.compression_info.normal.block_size;
|
||||
while (block_size) {
|
||||
const uint8_t *pnext = p + block_size;
|
||||
const size_t next_size = XEGETINT32BE(p);
|
||||
p += 4;
|
||||
p += 20; // skip 20b hash
|
||||
|
||||
while(true) {
|
||||
const size_t chunk_size = (p[0] << 8) | p[1];
|
||||
p += 2;
|
||||
if (!chunk_size) {
|
||||
break;
|
||||
}
|
||||
xe_copy_memory(d, exe_length - (d - compress_buffer), p, chunk_size);
|
||||
p += chunk_size;
|
||||
d += chunk_size;
|
||||
|
||||
uncompressed_size += 0x8000;
|
||||
}
|
||||
|
||||
p = pnext;
|
||||
block_size = next_size;
|
||||
}
|
||||
|
||||
// Allocate in-place the XEX memory.
|
||||
uint32_t alloc_result = (uint32_t)memory->HeapAlloc(
|
||||
header->exe_address, uncompressed_size,
|
||||
MEMORY_FLAG_ZERO);
|
||||
if (!alloc_result) {
|
||||
XELOGE("Unable to allocate XEX memory at %.8X-%.8X.",
|
||||
header->exe_address, uncompressed_size);
|
||||
result_code = 2;
|
||||
XEFAIL();
|
||||
}
|
||||
uint8_t *buffer = memory->Translate(header->exe_address);
|
||||
|
||||
// Setup decompressor and decompress.
|
||||
sys = mspack_memory_sys_create();
|
||||
XEEXPECTNOTNULL(sys);
|
||||
lzxsrc = mspack_memory_open(sys, (void*)compress_buffer, d - compress_buffer);
|
||||
XEEXPECTNOTNULL(lzxsrc);
|
||||
lzxdst = mspack_memory_open(sys, buffer, uncompressed_size);
|
||||
XEEXPECTNOTNULL(lzxdst);
|
||||
lzxd = lzxd_init(
|
||||
sys,
|
||||
(struct mspack_file *)lzxsrc,
|
||||
(struct mspack_file *)lzxdst,
|
||||
header->file_format_info.compression_info.normal.window_bits,
|
||||
0,
|
||||
32768,
|
||||
(off_t)header->loader_info.image_size);
|
||||
XEEXPECTNOTNULL(lzxd);
|
||||
XEEXPECTZERO(lzxd_decompress(lzxd, (off_t)header->loader_info.image_size));
|
||||
|
||||
result_code = 0;
|
||||
|
||||
XECLEANUP:
|
||||
if (lzxd) {
|
||||
lzxd_free(lzxd);
|
||||
lzxd = NULL;
|
||||
}
|
||||
if (lzxsrc) {
|
||||
mspack_memory_close(lzxsrc);
|
||||
lzxsrc = NULL;
|
||||
}
|
||||
if (lzxdst) {
|
||||
mspack_memory_close(lzxdst);
|
||||
lzxdst = NULL;
|
||||
}
|
||||
if (sys) {
|
||||
mspack_memory_sys_destroy(sys);
|
||||
sys = NULL;
|
||||
}
|
||||
xe_free(compress_buffer);
|
||||
xe_free(deblock_buffer);
|
||||
if (free_input) {
|
||||
xe_free((void*)input_buffer);
|
||||
}
|
||||
return result_code;
|
||||
}
|
||||
|
||||
int xe_xex2_read_image(xe_xex2_ref xex, const uint8_t *xex_addr,
|
||||
const size_t xex_length, Memory* memory) {
|
||||
const xe_xex2_header_t *header = &xex->header;
|
||||
switch (header->file_format_info.compression_type) {
|
||||
case XEX_COMPRESSION_NONE:
|
||||
return xe_xex2_read_image_uncompressed(
|
||||
header, xex_addr, xex_length, memory);
|
||||
case XEX_COMPRESSION_BASIC:
|
||||
return xe_xex2_read_image_basic_compressed(
|
||||
header, xex_addr, xex_length, memory);
|
||||
case XEX_COMPRESSION_NORMAL:
|
||||
return xe_xex2_read_image_compressed(
|
||||
header, xex_addr, xex_length, memory);
|
||||
default:
|
||||
XEASSERTALWAYS();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int xe_xex2_load_pe(xe_xex2_ref xex) {
|
||||
const xe_xex2_header_t* header = &xex->header;
|
||||
const uint8_t* p = xex->memory->Translate(header->exe_address);
|
||||
|
||||
// Verify DOS signature (MZ).
|
||||
const IMAGE_DOS_HEADER* doshdr = (const IMAGE_DOS_HEADER*)p;
|
||||
if (doshdr->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
XELOGE("PE signature mismatch; likely bad decryption/decompression");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Move to the NT header offset from the DOS header.
|
||||
p += doshdr->e_lfanew;
|
||||
|
||||
// Verify NT signature (PE\0\0).
|
||||
const IMAGE_NT_HEADERS32* nthdr = (const IMAGE_NT_HEADERS32*)(p);
|
||||
if (nthdr->Signature != IMAGE_NT_SIGNATURE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Verify matches an Xbox PE.
|
||||
const IMAGE_FILE_HEADER* filehdr = &nthdr->FileHeader;
|
||||
if ((filehdr->Machine != IMAGE_FILE_MACHINE_POWERPCBE) ||
|
||||
!(filehdr->Characteristics & IMAGE_FILE_32BIT_MACHINE)) {
|
||||
return 1;
|
||||
}
|
||||
// Verify the expected size.
|
||||
if (filehdr->SizeOfOptionalHeader != IMAGE_SIZEOF_NT_OPTIONAL_HEADER) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Verify optional header is 32bit.
|
||||
const IMAGE_OPTIONAL_HEADER32* opthdr = &nthdr->OptionalHeader;
|
||||
if (opthdr->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
||||
return 1;
|
||||
}
|
||||
// Verify subsystem.
|
||||
if (opthdr->Subsystem != IMAGE_SUBSYSTEM_XBOX) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Linker version - likely 8+
|
||||
// Could be useful for recognizing certain patterns
|
||||
//opthdr->MajorLinkerVersion; opthdr->MinorLinkerVersion;
|
||||
|
||||
// Data directories of interest:
|
||||
// EXPORT IMAGE_EXPORT_DIRECTORY
|
||||
// IMPORT IMAGE_IMPORT_DESCRIPTOR[]
|
||||
// EXCEPTION IMAGE_CE_RUNTIME_FUNCTION_ENTRY[]
|
||||
// BASERELOC
|
||||
// DEBUG IMAGE_DEBUG_DIRECTORY[]
|
||||
// ARCHITECTURE /IMAGE_ARCHITECTURE_HEADER/ ----- import thunks!
|
||||
// TLS IMAGE_TLS_DIRECTORY
|
||||
// IAT Import Address Table ptr
|
||||
//opthdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_X].VirtualAddress / .Size
|
||||
|
||||
// Quick scan to determine bounds of sections.
|
||||
size_t upper_address = 0;
|
||||
const IMAGE_SECTION_HEADER* sechdr = IMAGE_FIRST_SECTION(nthdr);
|
||||
for (size_t n = 0; n < filehdr->NumberOfSections; n++, sechdr++) {
|
||||
const size_t physical_address = opthdr->ImageBase + sechdr->VirtualAddress;
|
||||
upper_address =
|
||||
MAX(upper_address, physical_address + sechdr->Misc.VirtualSize);
|
||||
}
|
||||
|
||||
// Setup/load sections.
|
||||
sechdr = IMAGE_FIRST_SECTION(nthdr);
|
||||
for (size_t n = 0; n < filehdr->NumberOfSections; n++, sechdr++) {
|
||||
PESection* section = (PESection*)xe_calloc(sizeof(PESection));
|
||||
xe_copy_memory(section->name, sizeof(section->name),
|
||||
sechdr->Name, sizeof(sechdr->Name));
|
||||
section->name[8] = 0;
|
||||
section->raw_address = sechdr->PointerToRawData;
|
||||
section->raw_size = sechdr->SizeOfRawData;
|
||||
section->address = header->exe_address + sechdr->VirtualAddress;
|
||||
section->size = sechdr->Misc.VirtualSize;
|
||||
section->flags = sechdr->Characteristics;
|
||||
xex->sections->push_back(section);
|
||||
}
|
||||
|
||||
//DumpTLSDirectory(pImageBase, pNTHeader, (PIMAGE_TLS_DIRECTORY32)0);
|
||||
//DumpExportsSection(pImageBase, pNTHeader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const PESection* xe_xex2_get_pe_section(xe_xex2_ref xex, const char* name) {
|
||||
for (std::vector<PESection*>::iterator it = xex->sections->begin();
|
||||
it != xex->sections->end(); ++it) {
|
||||
if (!xestrcmpa((*it)->name, name)) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int xe_xex2_get_import_infos(xe_xex2_ref xex,
|
||||
const xe_xex2_import_library_t *library,
|
||||
xe_xex2_import_info_t **out_import_infos,
|
||||
size_t *out_import_info_count) {
|
||||
uint8_t *mem = xex->memory->membase();
|
||||
const xe_xex2_header_t *header = xe_xex2_get_header(xex);
|
||||
|
||||
// Find library index for verification.
|
||||
size_t library_index = -1;
|
||||
for (size_t n = 0; n < header->import_library_count; n++) {
|
||||
if (&header->import_libraries[n] == library) {
|
||||
library_index = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
XEASSERT(library_index != (size_t)-1);
|
||||
|
||||
// Records:
|
||||
// The number of records does not correspond to the number of imports!
|
||||
// Each record points at either a location in text or data - dereferencing the
|
||||
// pointer will yield a value that & 0xFFFF = the import ordinal,
|
||||
// >> 16 & 0xFF = import library index, and >> 24 & 0xFF = 0 if a variable
|
||||
// (just get address) or 1 if a thunk (needs rewrite).
|
||||
|
||||
// Calculate real count.
|
||||
size_t info_count = 0;
|
||||
for (size_t n = 0; n < library->record_count; n++) {
|
||||
const uint32_t record = library->records[n];
|
||||
const uint32_t value = XEGETUINT32BE(mem + record);
|
||||
if (value & 0xFF000000) {
|
||||
// Thunk for previous record - ignore.
|
||||
} else {
|
||||
// Variable/thunk.
|
||||
info_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate storage.
|
||||
xe_xex2_import_info_t *infos = (xe_xex2_import_info_t*)xe_calloc(
|
||||
info_count * sizeof(xe_xex2_import_info_t));
|
||||
XEEXPECTNOTNULL(infos);
|
||||
|
||||
XEASSERTNOTZERO(info_count);
|
||||
|
||||
// Construct infos.
|
||||
for (size_t n = 0, i = 0; n < library->record_count; n++) {
|
||||
const uint32_t record = library->records[n];
|
||||
const uint32_t value = XEGETUINT32BE(mem + record);
|
||||
const uint32_t type = (value & 0xFF000000) >> 24;
|
||||
|
||||
// Verify library index matches given library.
|
||||
//XEASSERT(library_index == ((value >> 16) & 0xFF));
|
||||
|
||||
switch (type) {
|
||||
case 0x00:
|
||||
{
|
||||
xe_xex2_import_info_t* info = &infos[i++];
|
||||
info->ordinal = value & 0xFFFF;
|
||||
info->value_address = record;
|
||||
}
|
||||
break;
|
||||
case 0x01:
|
||||
{
|
||||
// Thunk for previous record.
|
||||
XEASSERT(i > 0);
|
||||
xe_xex2_import_info_t* info = &infos[i - 1];
|
||||
XEASSERT(info->ordinal == (value & 0xFFFF));
|
||||
info->thunk_address = record;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//XEASSERTALWAYS();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*out_import_info_count = info_count;
|
||||
*out_import_infos = infos;
|
||||
return 0;
|
||||
|
||||
XECLEANUP:
|
||||
xe_free(infos);
|
||||
*out_import_info_count = 0;
|
||||
*out_import_infos = NULL;
|
||||
return 1;
|
||||
}
|
||||
64
src/xenia/kernel/util/xex2.h
Normal file
64
src/xenia/kernel/util/xex2.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_UTIL_XEX2_H_
|
||||
#define XENIA_KERNEL_UTIL_XEX2_H_
|
||||
|
||||
#include <xenia/core.h>
|
||||
#include <xenia/kernel/util/xex2_info.h>
|
||||
|
||||
typedef struct {
|
||||
int reserved;
|
||||
} xe_xex2_options_t;
|
||||
|
||||
struct xe_xex2;
|
||||
typedef struct xe_xex2* xe_xex2_ref;
|
||||
|
||||
typedef struct {
|
||||
uint32_t ordinal;
|
||||
uint32_t value_address; // address to place value
|
||||
uint32_t thunk_address; // NULL or address of thunk
|
||||
} xe_xex2_import_info_t;
|
||||
|
||||
enum xe_pe_section_flags_e {
|
||||
kXEPESectionContainsCode = 0x00000020,
|
||||
kXEPESectionContainsDataInit = 0x00000040,
|
||||
kXEPESectionContainsDataUninit = 0x00000080,
|
||||
kXEPESectionMemoryExecute = 0x20000000,
|
||||
kXEPESectionMemoryRead = 0x40000000,
|
||||
kXEPESectionMemoryWrite = 0x80000000,
|
||||
};
|
||||
|
||||
class PESection {
|
||||
public:
|
||||
char name[9]; // 8 + 1 for \0
|
||||
uint32_t raw_address;
|
||||
uint32_t raw_size;
|
||||
uint32_t address;
|
||||
uint32_t size;
|
||||
uint32_t flags; // kXEPESection*
|
||||
};
|
||||
|
||||
xe_xex2_ref xe_xex2_load(xe::Memory* memory,
|
||||
const void* addr, const size_t length,
|
||||
xe_xex2_options_t options);
|
||||
xe_xex2_ref xe_xex2_retain(xe_xex2_ref xex);
|
||||
void xe_xex2_release(xe_xex2_ref xex);
|
||||
|
||||
const xechar_t *xe_xex2_get_name(xe_xex2_ref xex);
|
||||
const xe_xex2_header_t *xe_xex2_get_header(xe_xex2_ref xex);
|
||||
const PESection* xe_xex2_get_pe_section(xe_xex2_ref xex, const char* name);
|
||||
|
||||
int xe_xex2_get_import_infos(xe_xex2_ref xex,
|
||||
const xe_xex2_import_library_t *library,
|
||||
xe_xex2_import_info_t **out_import_infos,
|
||||
size_t *out_import_info_count);
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_UTIL_XEX2_H_
|
||||
459
src/xenia/kernel/util/xex2_info.h
Normal file
459
src/xenia/kernel/util/xex2_info.h
Normal file
@@ -0,0 +1,459 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_XEX2_INFO_H_
|
||||
#define XENIA_KERNEL_XEX2_INFO_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
|
||||
|
||||
typedef enum {
|
||||
XEX_HEADER_RESOURCE_INFO = 0x000002FF,
|
||||
XEX_HEADER_FILE_FORMAT_INFO = 0x000003FF,
|
||||
XEX_HEADER_DELTA_PATCH_DESCRIPTOR = 0x000005FF,
|
||||
XEX_HEADER_BASE_REFERENCE = 0x00000405,
|
||||
XEX_HEADER_BOUNDING_PATH = 0x000080FF,
|
||||
XEX_HEADER_DEVICE_ID = 0x00008105,
|
||||
XEX_HEADER_ORIGINAL_BASE_ADDRESS = 0x00010001,
|
||||
XEX_HEADER_ENTRY_POINT = 0x00010100,
|
||||
XEX_HEADER_IMAGE_BASE_ADDRESS = 0x00010201,
|
||||
XEX_HEADER_IMPORT_LIBRARIES = 0x000103FF,
|
||||
XEX_HEADER_CHECKSUM_TIMESTAMP = 0x00018002,
|
||||
XEX_HEADER_ENABLED_FOR_CALLCAP = 0x00018102,
|
||||
XEX_HEADER_ENABLED_FOR_FASTCAP = 0x00018200,
|
||||
XEX_HEADER_ORIGINAL_PE_NAME = 0x000183FF,
|
||||
XEX_HEADER_STATIC_LIBRARIES = 0x000200FF,
|
||||
XEX_HEADER_TLS_INFO = 0x00020104,
|
||||
XEX_HEADER_DEFAULT_STACK_SIZE = 0x00020200,
|
||||
XEX_HEADER_DEFAULT_FILESYSTEM_CACHE_SIZE = 0x00020301,
|
||||
XEX_HEADER_DEFAULT_HEAP_SIZE = 0x00020401,
|
||||
XEX_HEADER_PAGE_HEAP_SIZE_AND_FLAGS = 0x00028002,
|
||||
XEX_HEADER_SYSTEM_FLAGS = 0x00030000,
|
||||
XEX_HEADER_EXECUTION_INFO = 0x00040006,
|
||||
XEX_HEADER_TITLE_WORKSPACE_SIZE = 0x00040201,
|
||||
XEX_HEADER_GAME_RATINGS = 0x00040310,
|
||||
XEX_HEADER_LAN_KEY = 0x00040404,
|
||||
XEX_HEADER_XBOX360_LOGO = 0x000405FF,
|
||||
XEX_HEADER_MULTIDISC_MEDIA_IDS = 0x000406FF,
|
||||
XEX_HEADER_ALTERNATE_TITLE_IDS = 0x000407FF,
|
||||
XEX_HEADER_ADDITIONAL_TITLE_MEMORY = 0x00040801,
|
||||
XEX_HEADER_EXPORTS_BY_NAME = 0x00E10402,
|
||||
} xe_xex2_header_keys;
|
||||
|
||||
typedef enum {
|
||||
XEX_MODULE_TITLE = 0x00000001,
|
||||
XEX_MODULE_EXPORTS_TO_TITLE = 0x00000002,
|
||||
XEX_MODULE_SYSTEM_DEBUGGER = 0x00000004,
|
||||
XEX_MODULE_DLL_MODULE = 0x00000008,
|
||||
XEX_MODULE_MODULE_PATCH = 0x00000010,
|
||||
XEX_MODULE_PATCH_FULL = 0x00000020,
|
||||
XEX_MODULE_PATCH_DELTA = 0x00000040,
|
||||
XEX_MODULE_USER_MODE = 0x00000080,
|
||||
} xe_xex2_module_flags;
|
||||
|
||||
typedef enum {
|
||||
XEX_SYSTEM_NO_FORCED_REBOOT = 0x00000001,
|
||||
XEX_SYSTEM_FOREGROUND_TASKS = 0x00000002,
|
||||
XEX_SYSTEM_NO_ODD_MAPPING = 0x00000004,
|
||||
XEX_SYSTEM_HANDLE_MCE_INPUT = 0x00000008,
|
||||
XEX_SYSTEM_RESTRICTED_HUD_FEATURES = 0x00000010,
|
||||
XEX_SYSTEM_HANDLE_GAMEPAD_DISCONNECT = 0x00000020,
|
||||
XEX_SYSTEM_INSECURE_SOCKETS = 0x00000040,
|
||||
XEX_SYSTEM_XBOX1_INTEROPERABILITY = 0x00000080,
|
||||
XEX_SYSTEM_DASH_CONTEXT = 0x00000100,
|
||||
XEX_SYSTEM_USES_GAME_VOICE_CHANNEL = 0x00000200,
|
||||
XEX_SYSTEM_PAL50_INCOMPATIBLE = 0x00000400,
|
||||
XEX_SYSTEM_INSECURE_UTILITY_DRIVE = 0x00000800,
|
||||
XEX_SYSTEM_XAM_HOOKS = 0x00001000,
|
||||
XEX_SYSTEM_ACCESS_PII = 0x00002000,
|
||||
XEX_SYSTEM_CROSS_PLATFORM_SYSTEM_LINK = 0x00004000,
|
||||
XEX_SYSTEM_MULTIDISC_SWAP = 0x00008000,
|
||||
XEX_SYSTEM_MULTIDISC_INSECURE_MEDIA = 0x00010000,
|
||||
XEX_SYSTEM_AP25_MEDIA = 0x00020000,
|
||||
XEX_SYSTEM_NO_CONFIRM_EXIT = 0x00040000,
|
||||
XEX_SYSTEM_ALLOW_BACKGROUND_DOWNLOAD = 0x00080000,
|
||||
XEX_SYSTEM_CREATE_PERSISTABLE_RAMDRIVE = 0x00100000,
|
||||
XEX_SYSTEM_INHERIT_PERSISTENT_RAMDRIVE = 0x00200000,
|
||||
XEX_SYSTEM_ALLOW_HUD_VIBRATION = 0x00400000,
|
||||
XEX_SYSTEM_ACCESS_UTILITY_PARTITIONS = 0x00800000,
|
||||
XEX_SYSTEM_IPTV_INPUT_SUPPORTED = 0x01000000,
|
||||
XEX_SYSTEM_PREFER_BIG_BUTTON_INPUT = 0x02000000,
|
||||
XEX_SYSTEM_ALLOW_EXTENDED_SYSTEM_RESERVATION = 0x04000000,
|
||||
XEX_SYSTEM_MULTIDISC_CROSS_TITLE = 0x08000000,
|
||||
XEX_SYSTEM_INSTALL_INCOMPATIBLE = 0x10000000,
|
||||
XEX_SYSTEM_ALLOW_AVATAR_GET_METADATA_BY_XUID = 0x20000000,
|
||||
XEX_SYSTEM_ALLOW_CONTROLLER_SWAPPING = 0x40000000,
|
||||
XEX_SYSTEM_DASH_EXTENSIBILITY_MODULE = 0x80000000,
|
||||
// TODO: figure out how stored
|
||||
/*XEX_SYSTEM_ALLOW_NETWORK_READ_CANCEL = 0x0,
|
||||
XEX_SYSTEM_UNINTERRUPTABLE_READS = 0x0,
|
||||
XEX_SYSTEM_REQUIRE_FULL_EXPERIENCE = 0x0,
|
||||
XEX_SYSTEM_GAME_VOICE_REQUIRED_UI = 0x0,
|
||||
XEX_SYSTEM_CAMERA_ANGLE = 0x0,
|
||||
XEX_SYSTEM_SKELETAL_TRACKING_REQUIRED = 0x0,
|
||||
XEX_SYSTEM_SKELETAL_TRACKING_SUPPORTED = 0x0,*/
|
||||
} xe_xex2_system_flags;
|
||||
|
||||
// ESRB (Entertainment Software Rating Board)
|
||||
typedef enum {
|
||||
XEX_RATING_ESRB_eC = 0x00,
|
||||
XEX_RATING_ESRB_E = 0x02,
|
||||
XEX_RATING_ESRB_E10 = 0x04,
|
||||
XEX_RATING_ESRB_T = 0x06,
|
||||
XEX_RATING_ESRB_M = 0x08,
|
||||
XEX_RATING_ESRB_AO = 0x0E,
|
||||
XEX_RATING_ESRB_UNRATED = 0xFF,
|
||||
} xe_xex2_rating_esrb_value;
|
||||
// PEGI (Pan European Game Information)
|
||||
typedef enum {
|
||||
XEX_RATING_PEGI_3_PLUS = 0,
|
||||
XEX_RATING_PEGI_7_PLUS = 4,
|
||||
XEX_RATING_PEGI_12_PLUS = 9,
|
||||
XEX_RATING_PEGI_16_PLUS = 13,
|
||||
XEX_RATING_PEGI_18_PLUS = 14,
|
||||
XEX_RATING_PEGI_UNRATED = 0xFF,
|
||||
} xe_xex2_rating_pegi_value;
|
||||
// PEGI (Pan European Game Information) - Finland
|
||||
typedef enum {
|
||||
XEX_RATING_PEGI_FI_3_PLUS = 0,
|
||||
XEX_RATING_PEGI_FI_7_PLUS = 4,
|
||||
XEX_RATING_PEGI_FI_11_PLUS = 8,
|
||||
XEX_RATING_PEGI_FI_15_PLUS = 12,
|
||||
XEX_RATING_PEGI_FI_18_PLUS = 14,
|
||||
XEX_RATING_PEGI_FI_UNRATED = 0xFF,
|
||||
} xe_xex2_rating_pegi_fi_value;
|
||||
// PEGI (Pan European Game Information) - Portugal
|
||||
typedef enum {
|
||||
XEX_RATING_PEGI_PT_4_PLUS = 1,
|
||||
XEX_RATING_PEGI_PT_6_PLUS = 3,
|
||||
XEX_RATING_PEGI_PT_12_PLUS = 9,
|
||||
XEX_RATING_PEGI_PT_16_PLUS = 13,
|
||||
XEX_RATING_PEGI_PT_18_PLUS = 14,
|
||||
XEX_RATING_PEGI_PT_UNRATED = 0xFF,
|
||||
} xe_xex2_rating_pegi_pt_value;
|
||||
// BBFC (British Board of Film Classification) - UK/Ireland
|
||||
typedef enum {
|
||||
XEX_RATING_BBFC_UNIVERSAL = 1,
|
||||
XEX_RATING_BBFC_PG = 5,
|
||||
XEX_RATING_BBFC_3_PLUS = 0,
|
||||
XEX_RATING_BBFC_7_PLUS = 4,
|
||||
XEX_RATING_BBFC_12_PLUS = 9,
|
||||
XEX_RATING_BBFC_15_PLUS = 12,
|
||||
XEX_RATING_BBFC_16_PLUS = 13,
|
||||
XEX_RATING_BBFC_18_PLUS = 14,
|
||||
XEX_RATING_BBFC_UNRATED = 0xFF,
|
||||
} xe_xex2_rating_bbfc_value;
|
||||
// CERO (Computer Entertainment Rating Organization)
|
||||
typedef enum {
|
||||
XEX_RATING_CERO_A = 0,
|
||||
XEX_RATING_CERO_B = 2,
|
||||
XEX_RATING_CERO_C = 4,
|
||||
XEX_RATING_CERO_D = 6,
|
||||
XEX_RATING_CERO_Z = 8,
|
||||
XEX_RATING_CERO_UNRATED = 0xFF,
|
||||
} xe_xex2_rating_cero_value;
|
||||
// USK (Unterhaltungssoftware SelbstKontrolle)
|
||||
typedef enum {
|
||||
XEX_RATING_USK_ALL = 0,
|
||||
XEX_RATING_USK_6_PLUS = 2,
|
||||
XEX_RATING_USK_12_PLUS = 4,
|
||||
XEX_RATING_USK_16_PLUS = 6,
|
||||
XEX_RATING_USK_18_PLUS = 8,
|
||||
XEX_RATING_USK_UNRATED = 0xFF,
|
||||
} xe_xex2_rating_usk_value;
|
||||
// OFLC (Office of Film and Literature Classification) - Australia
|
||||
typedef enum {
|
||||
XEX_RATING_OFLC_AU_G = 0,
|
||||
XEX_RATING_OFLC_AU_PG = 2,
|
||||
XEX_RATING_OFLC_AU_M = 4,
|
||||
XEX_RATING_OFLC_AU_MA15_PLUS = 6,
|
||||
XEX_RATING_OFLC_AU_UNRATED = 0xFF,
|
||||
} xe_xex2_rating_oflc_au_value;
|
||||
// OFLC (Office of Film and Literature Classification) - New Zealand
|
||||
typedef enum {
|
||||
XEX_RATING_OFLC_NZ_G = 0,
|
||||
XEX_RATING_OFLC_NZ_PG = 2,
|
||||
XEX_RATING_OFLC_NZ_M = 4,
|
||||
XEX_RATING_OFLC_NZ_MA15_PLUS = 6,
|
||||
XEX_RATING_OFLC_NZ_UNRATED = 0xFF,
|
||||
} xe_xex2_rating_oflc_nz_value;
|
||||
// KMRB (Korea Media Rating Board)
|
||||
typedef enum {
|
||||
XEX_RATING_KMRB_ALL = 0,
|
||||
XEX_RATING_KMRB_12_PLUS = 2,
|
||||
XEX_RATING_KMRB_15_PLUS = 4,
|
||||
XEX_RATING_KMRB_18_PLUS = 6,
|
||||
XEX_RATING_KMRB_UNRATED = 0xFF,
|
||||
} xe_xex2_rating_kmrb_value;
|
||||
// Brazil
|
||||
typedef enum {
|
||||
XEX_RATING_BRAZIL_ALL = 0,
|
||||
XEX_RATING_BRAZIL_12_PLUS = 2,
|
||||
XEX_RATING_BRAZIL_14_PLUS = 4,
|
||||
XEX_RATING_BRAZIL_16_PLUS = 5,
|
||||
XEX_RATING_BRAZIL_18_PLUS = 8,
|
||||
XEX_RATING_BRAZIL_UNRATED = 0xFF,
|
||||
} xe_xex2_rating_brazil_value;
|
||||
// FPB (Film and Publication Board)
|
||||
typedef enum {
|
||||
XEX_RATING_FPB_ALL = 0,
|
||||
XEX_RATING_FPB_PG = 6,
|
||||
XEX_RATING_FPB_10_PLUS = 7,
|
||||
XEX_RATING_FPB_13_PLUS = 10,
|
||||
XEX_RATING_FPB_16_PLUS = 13,
|
||||
XEX_RATING_FPB_18_PLUS = 14,
|
||||
XEX_RATING_FPB_UNRATED = 0xFF,
|
||||
} xe_xex2_rating_fpb_value;
|
||||
|
||||
typedef struct {
|
||||
xe_xex2_rating_esrb_value esrb;
|
||||
xe_xex2_rating_pegi_value pegi;
|
||||
xe_xex2_rating_pegi_fi_value pegifi;
|
||||
xe_xex2_rating_pegi_pt_value pegipt;
|
||||
xe_xex2_rating_bbfc_value bbfc;
|
||||
xe_xex2_rating_cero_value cero;
|
||||
xe_xex2_rating_usk_value usk;
|
||||
xe_xex2_rating_oflc_au_value oflcau;
|
||||
xe_xex2_rating_oflc_nz_value oflcnz;
|
||||
xe_xex2_rating_kmrb_value kmrb;
|
||||
xe_xex2_rating_brazil_value brazil;
|
||||
xe_xex2_rating_fpb_value fpb;
|
||||
} xe_xex2_game_ratings_t;
|
||||
|
||||
typedef union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint32_t major : 4;
|
||||
uint32_t minor : 4;
|
||||
uint32_t build : 16;
|
||||
uint32_t qfe : 8;
|
||||
};
|
||||
} xe_xex2_version_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t key;
|
||||
uint32_t length;
|
||||
union {
|
||||
uint32_t value;
|
||||
uint32_t offset;
|
||||
};
|
||||
} xe_xex2_opt_header_t;
|
||||
|
||||
typedef struct {
|
||||
char title_id[8];
|
||||
uint32_t address;
|
||||
uint32_t size;
|
||||
} xe_xex2_resource_info_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t media_id;
|
||||
xe_xex2_version_t version;
|
||||
xe_xex2_version_t base_version;
|
||||
uint32_t title_id;
|
||||
uint8_t platform;
|
||||
uint8_t executable_table;
|
||||
uint8_t disc_number;
|
||||
uint8_t disc_count;
|
||||
uint32_t savegame_id;
|
||||
} xe_xex2_execution_info_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t slot_count;
|
||||
uint32_t raw_data_address;
|
||||
uint32_t data_size;
|
||||
uint32_t raw_data_size;
|
||||
} xe_xex2_tls_info_t;
|
||||
|
||||
typedef struct {
|
||||
char name[32];
|
||||
uint8_t digest[20];
|
||||
uint32_t import_id;
|
||||
xe_xex2_version_t version;
|
||||
xe_xex2_version_t min_version;
|
||||
size_t record_count;
|
||||
uint32_t *records;
|
||||
} xe_xex2_import_library_t;
|
||||
|
||||
typedef enum {
|
||||
XEX_APPROVAL_UNAPPROVED = 0,
|
||||
XEX_APPROVAL_POSSIBLE = 1,
|
||||
XEX_APPROVAL_APPROVED = 2,
|
||||
XEX_APPROVAL_EXPIRED = 3,
|
||||
} xe_xex2_approval_type;
|
||||
|
||||
typedef struct {
|
||||
char name[9]; // 8 + 1 for \0
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
uint16_t build;
|
||||
uint16_t qfe;
|
||||
xe_xex2_approval_type approval;
|
||||
} xe_xex2_static_library_t;
|
||||
|
||||
typedef enum {
|
||||
XEX_ENCRYPTION_NONE = 0,
|
||||
XEX_ENCRYPTION_NORMAL = 1,
|
||||
} xe_xex2_encryption_type;
|
||||
|
||||
typedef enum {
|
||||
XEX_COMPRESSION_NONE = 0,
|
||||
XEX_COMPRESSION_BASIC = 1,
|
||||
XEX_COMPRESSION_NORMAL = 2,
|
||||
XEX_COMPRESSION_DELTA = 3,
|
||||
} xe_xex2_compression_type;
|
||||
|
||||
typedef struct {
|
||||
uint32_t data_size;
|
||||
uint32_t zero_size;
|
||||
} xe_xex2_file_basic_compression_block_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t block_count;
|
||||
xe_xex2_file_basic_compression_block_t *blocks;
|
||||
} xe_xex2_file_basic_compression_info_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t window_size;
|
||||
uint32_t window_bits;
|
||||
uint32_t block_size;
|
||||
uint8_t block_hash[20];
|
||||
} xe_xex2_file_normal_compression_info_t;
|
||||
|
||||
typedef struct {
|
||||
xe_xex2_encryption_type encryption_type;
|
||||
xe_xex2_compression_type compression_type;
|
||||
union {
|
||||
xe_xex2_file_basic_compression_info_t basic;
|
||||
xe_xex2_file_normal_compression_info_t normal;
|
||||
} compression_info;
|
||||
} xe_xex2_file_format_info_t;
|
||||
|
||||
typedef enum {
|
||||
XEX_IMAGE_MANUFACTURING_UTILITY = 0x00000002,
|
||||
XEX_IMAGE_MANUFACTURING_SUPPORT_TOOLS = 0x00000004,
|
||||
XEX_IMAGE_XGD2_MEDIA_ONLY = 0x00000008,
|
||||
XEX_IMAGE_CARDEA_KEY = 0x00000100,
|
||||
XEX_IMAGE_XEIKA_KEY = 0x00000200,
|
||||
XEX_IMAGE_USERMODE_TITLE = 0x00000400,
|
||||
XEX_IMAGE_USERMODE_SYSTEM = 0x00000800,
|
||||
XEX_IMAGE_ORANGE0 = 0x00001000,
|
||||
XEX_IMAGE_ORANGE1 = 0x00002000,
|
||||
XEX_IMAGE_ORANGE2 = 0x00004000,
|
||||
XEX_IMAGE_IPTV_SIGNUP_APPLICATION = 0x00010000,
|
||||
XEX_IMAGE_IPTV_TITLE_APPLICATION = 0x00020000,
|
||||
XEX_IMAGE_KEYVAULT_PRIVILEGES_REQUIRED = 0x04000000,
|
||||
XEX_IMAGE_ONLINE_ACTIVATION_REQUIRED = 0x08000000,
|
||||
XEX_IMAGE_PAGE_SIZE_4KB = 0x10000000, // else 64KB
|
||||
XEX_IMAGE_REGION_FREE = 0x20000000,
|
||||
XEX_IMAGE_REVOCATION_CHECK_OPTIONAL = 0x40000000,
|
||||
XEX_IMAGE_REVOCATION_CHECK_REQUIRED = 0x80000000,
|
||||
} xe_xex2_image_flags;
|
||||
|
||||
typedef enum {
|
||||
XEX_MEDIA_HARDDISK = 0x00000001,
|
||||
XEX_MEDIA_DVD_X2 = 0x00000002,
|
||||
XEX_MEDIA_DVD_CD = 0x00000004,
|
||||
XEX_MEDIA_DVD_5 = 0x00000008,
|
||||
XEX_MEDIA_DVD_9 = 0x00000010,
|
||||
XEX_MEDIA_SYSTEM_FLASH = 0x00000020,
|
||||
XEX_MEDIA_MEMORY_UNIT = 0x00000080,
|
||||
XEX_MEDIA_USB_MASS_STORAGE_DEVICE = 0x00000100,
|
||||
XEX_MEDIA_NETWORK = 0x00000200,
|
||||
XEX_MEDIA_DIRECT_FROM_MEMORY = 0x00000400,
|
||||
XEX_MEDIA_RAM_DRIVE = 0x00000800,
|
||||
XEX_MEDIA_SVOD = 0x00001000,
|
||||
XEX_MEDIA_INSECURE_PACKAGE = 0x01000000,
|
||||
XEX_MEDIA_SAVEGAME_PACKAGE = 0x02000000,
|
||||
XEX_MEDIA_LOCALLY_SIGNED_PACKAGE = 0x04000000,
|
||||
XEX_MEDIA_LIVE_SIGNED_PACKAGE = 0x08000000,
|
||||
XEX_MEDIA_XBOX_PACKAGE = 0x10000000,
|
||||
} xe_xex2_media_flags;
|
||||
|
||||
typedef enum {
|
||||
XEX_REGION_NTSCU = 0x000000FF,
|
||||
XEX_REGION_NTSCJ = 0x0000FF00,
|
||||
XEX_REGION_NTSCJ_JAPAN = 0x00000100,
|
||||
XEX_REGION_NTSCJ_CHINA = 0x00000200,
|
||||
XEX_REGION_PAL = 0x00FF0000,
|
||||
XEX_REGION_PAL_AU_NZ = 0x00010000,
|
||||
XEX_REGION_OTHER = 0xFF000000,
|
||||
XEX_REGION_ALL = 0xFFFFFFFF,
|
||||
} xe_xex2_region_flags;
|
||||
|
||||
typedef struct {
|
||||
uint32_t header_size;
|
||||
uint32_t image_size;
|
||||
uint8_t rsa_signature[256];
|
||||
uint32_t unklength;
|
||||
xe_xex2_image_flags image_flags;
|
||||
uint32_t load_address;
|
||||
uint8_t section_digest[20];
|
||||
uint32_t import_table_count;
|
||||
uint8_t import_table_digest[20];
|
||||
uint8_t media_id[16];
|
||||
uint8_t file_key[16];
|
||||
uint32_t export_table;
|
||||
uint8_t header_digest[20];
|
||||
xe_xex2_region_flags game_regions;
|
||||
xe_xex2_media_flags media_flags;
|
||||
} xe_xex2_loader_info_t;
|
||||
|
||||
typedef enum {
|
||||
XEX_SECTION_CODE = 1,
|
||||
XEX_SECTION_DATA = 2,
|
||||
XEX_SECTION_READONLY_DATA = 3,
|
||||
} xe_xex2_section_type;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
xe_xex2_section_type type : 4;
|
||||
uint32_t page_count : 28; // # of 64kb pages
|
||||
};
|
||||
uint32_t value; // To make uint8_t swapping easier
|
||||
} info;
|
||||
uint8_t digest[20];
|
||||
} xe_xex2_section_t;
|
||||
|
||||
#define xe_xex2_section_length 0x00010000
|
||||
|
||||
typedef struct {
|
||||
uint32_t xex2;
|
||||
xe_xex2_module_flags module_flags;
|
||||
uint32_t exe_offset;
|
||||
uint32_t unknown0;
|
||||
uint32_t certificate_offset;
|
||||
|
||||
xe_xex2_system_flags system_flags;
|
||||
xe_xex2_resource_info_t resource_info;
|
||||
xe_xex2_execution_info_t execution_info;
|
||||
xe_xex2_game_ratings_t game_ratings;
|
||||
xe_xex2_tls_info_t tls_info;
|
||||
size_t import_library_count;
|
||||
xe_xex2_import_library_t import_libraries[32];
|
||||
size_t static_library_count;
|
||||
xe_xex2_static_library_t static_libraries[32];
|
||||
xe_xex2_file_format_info_t file_format_info;
|
||||
xe_xex2_loader_info_t loader_info;
|
||||
uint8_t session_key[16];
|
||||
|
||||
uint32_t exe_address;
|
||||
uint32_t exe_entry_point;
|
||||
uint32_t exe_stack_size;
|
||||
uint32_t exe_heap_size;
|
||||
|
||||
size_t header_count;
|
||||
xe_xex2_opt_header_t headers[64];
|
||||
|
||||
size_t section_count;
|
||||
xe_xex2_section_t* sections;
|
||||
} xe_xex2_header_t;
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_XEX2_INFO_H_
|
||||
Reference in New Issue
Block a user