mirror of
https://github.com/hedge-dev/XenonRecomp.git
synced 2025-11-04 14:57:09 +00:00
Initial Commit
This commit is contained in:
5
PowerUtils/CMakeLists.txt
Normal file
5
PowerUtils/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
project("PowerUtils")
|
||||
add_library(PowerUtils "disasm.h" "disasm.cpp" "file.h" "xex.cpp")
|
||||
|
||||
target_include_directories(PowerUtils PUBLIC .)
|
||||
target_link_libraries(PowerUtils PUBLIC capstone)
|
||||
23
PowerUtils/disasm.cpp
Normal file
23
PowerUtils/disasm.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "disasm.h"
|
||||
|
||||
DisassemblerEngine ppc::gPPCBigEndianDisassembler{ CS_ARCH_PPC, CS_MODE_BIG_ENDIAN };
|
||||
|
||||
DisassemblerEngine::DisassemblerEngine(cs_arch arch, cs_mode mode)
|
||||
{
|
||||
cs_open(arch, mode, &handle);
|
||||
}
|
||||
|
||||
size_t DisassemblerEngine::Disassemble(const uint8_t* code, size_t size, uint64_t base, size_t count, cs_insn** instructions) const
|
||||
{
|
||||
return cs_disasm(handle, code, size, base, count, instructions);
|
||||
}
|
||||
|
||||
void DisassemblerEngine::SetOption(cs_opt_type option, size_t value)
|
||||
{
|
||||
cs_option(handle, option, value);
|
||||
}
|
||||
|
||||
DisassemblerEngine::~DisassemblerEngine()
|
||||
{
|
||||
cs_close(&handle);
|
||||
}
|
||||
34
PowerUtils/disasm.h
Normal file
34
PowerUtils/disasm.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include <capstone/capstone.h>
|
||||
|
||||
struct DisassemblerEngine
|
||||
{
|
||||
csh handle{};
|
||||
|
||||
DisassemblerEngine(const DisassemblerEngine&) = default;
|
||||
DisassemblerEngine& operator=(const DisassemblerEngine&) = delete;
|
||||
|
||||
DisassemblerEngine(cs_arch arch, cs_mode mode);
|
||||
~DisassemblerEngine();
|
||||
size_t Disassemble(const uint8_t* code, size_t size, uint64_t base, size_t count, cs_insn** instructions) const;
|
||||
void SetOption(cs_opt_type option, size_t value);
|
||||
|
||||
void SetDetail(bool value)
|
||||
{
|
||||
SetOption(CS_OPT_DETAIL, value);
|
||||
}
|
||||
};
|
||||
|
||||
namespace ppc
|
||||
{
|
||||
extern DisassemblerEngine gPPCBigEndianDisassembler;
|
||||
static size_t Disassemble(const uint8_t* code, size_t size, uint64_t base, size_t count, cs_insn** instructions)
|
||||
{
|
||||
return gPPCBigEndianDisassembler.Disassemble(code, size, base, count, instructions);
|
||||
}
|
||||
|
||||
static void SetDetail(bool value)
|
||||
{
|
||||
gPPCBigEndianDisassembler.SetDetail(value);
|
||||
}
|
||||
}
|
||||
25
PowerUtils/file.h
Normal file
25
PowerUtils/file.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
|
||||
inline static std::vector<uint8_t> LoadFile(const char* path)
|
||||
{
|
||||
std::vector<uint8_t> data{};
|
||||
auto* stream = fopen(path, "rb");
|
||||
if (stream == nullptr)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
fseek(stream, 0, SEEK_END);
|
||||
|
||||
const auto size = ftell(stream);
|
||||
|
||||
fseek(stream, 0, SEEK_SET);
|
||||
|
||||
data.resize(size);
|
||||
|
||||
fread(data.data(), 1, data.size(), stream);
|
||||
fclose(stream);
|
||||
|
||||
return data;
|
||||
}
|
||||
288
PowerUtils/xbox.h
Normal file
288
PowerUtils/xbox.h
Normal file
@@ -0,0 +1,288 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <bit>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#define near
|
||||
#define far
|
||||
|
||||
typedef char CHAR;
|
||||
typedef wchar_t WCHAR;
|
||||
typedef unsigned long DWORD;
|
||||
typedef int BOOL;
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short WORD;
|
||||
typedef float FLOAT;
|
||||
typedef FLOAT* PFLOAT;
|
||||
typedef BOOL near* PBOOL;
|
||||
typedef BOOL far* LPBOOL;
|
||||
typedef BYTE near* PBYTE;
|
||||
typedef BYTE far* LPBYTE;
|
||||
typedef int near* PINT;
|
||||
typedef int far* LPINT;
|
||||
typedef WORD near* PWORD;
|
||||
typedef WORD far* LPWORD;
|
||||
typedef long far* LPLONG;
|
||||
typedef DWORD near* PDWORD;
|
||||
typedef DWORD far* LPDWORD;
|
||||
typedef void far* LPVOID;
|
||||
typedef const void far* LPCVOID;
|
||||
typedef unsigned long ULONG;
|
||||
typedef ULONG* PULONG;
|
||||
typedef signed long LONG;
|
||||
typedef LONG* PLONG;
|
||||
typedef unsigned long long ULONGLONG;
|
||||
typedef ULONGLONG* PULONGLONG;
|
||||
typedef unsigned short USHORT;
|
||||
typedef USHORT* PUSHORT;
|
||||
typedef unsigned char UCHAR;
|
||||
typedef UCHAR* PUCHAR;
|
||||
typedef char* PSZ;
|
||||
typedef int INT;
|
||||
typedef unsigned int UINT;
|
||||
typedef unsigned int* PUINT;
|
||||
#endif
|
||||
|
||||
// real win32 handles will never use the upper bits unless something goes really wrong
|
||||
#define CHECK_GUEST_HANDLE(HANDLE) (((HANDLE) & 0x80000000) == 0x80000000)
|
||||
#define GUEST_HANDLE(HANDLE) ((HANDLE) | 0x80000000)
|
||||
#define HOST_HANDLE(HANDLE) ((HANDLE) & ~0x80000000)
|
||||
|
||||
template<typename T>
|
||||
struct be
|
||||
{
|
||||
T value;
|
||||
|
||||
be() : value(0)
|
||||
{
|
||||
}
|
||||
|
||||
be(const T v)
|
||||
{
|
||||
set(v);
|
||||
}
|
||||
|
||||
static T byteswap(T value)
|
||||
{
|
||||
if constexpr (std::is_same_v<T, double>)
|
||||
{
|
||||
const uint64_t swapped = std::byteswap(*reinterpret_cast<uint64_t*>(&value));
|
||||
return *reinterpret_cast<const T*>(&swapped);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, float>)
|
||||
{
|
||||
const uint32_t swapped = std::byteswap(*reinterpret_cast<uint32_t*>(&value));
|
||||
return *reinterpret_cast<const T*>(&swapped);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::byteswap(value);
|
||||
}
|
||||
}
|
||||
|
||||
void set(const T v)
|
||||
{
|
||||
value = byteswap(v);
|
||||
}
|
||||
|
||||
T get() const
|
||||
{
|
||||
return byteswap(value);
|
||||
}
|
||||
|
||||
be& operator| (T value)
|
||||
{
|
||||
set(get() | value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
be& operator& (T value)
|
||||
{
|
||||
set(get() & value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator T() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
be& operator=(T v)
|
||||
{
|
||||
set(v);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct xpointer
|
||||
{
|
||||
be<uint32_t> ptr;
|
||||
|
||||
xpointer(T* ptr) : ptr(ptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
T* get() const
|
||||
{
|
||||
if (!ptr.value)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return static_cast<T*>(ptr);
|
||||
}
|
||||
|
||||
operator T* () const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
T* operator->() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
};
|
||||
|
||||
typedef BYTE XBYTE;
|
||||
typedef be<uint16_t> XWORD;
|
||||
typedef be<uint32_t> XDWORD;
|
||||
typedef be<uint64_t> XQWORD;
|
||||
|
||||
typedef XBYTE* XLPBYTE;
|
||||
typedef XWORD* XLPWORD;
|
||||
typedef XDWORD* XLPDWORD;
|
||||
typedef XQWORD* XLPQWORD;
|
||||
|
||||
struct _XLIST_ENTRY;
|
||||
typedef _XLIST_ENTRY XLIST_ENTRY;
|
||||
typedef xpointer<XLIST_ENTRY> PXLIST_ENTRY;
|
||||
|
||||
typedef struct _XLIST_ENTRY
|
||||
{
|
||||
XDWORD Flink;
|
||||
XDWORD Blink;
|
||||
} XLIST_ENTRY;
|
||||
|
||||
typedef struct _XDISPATCHER_HEADER
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
UCHAR Type;
|
||||
union
|
||||
{
|
||||
UCHAR Abandoned;
|
||||
UCHAR Absolute;
|
||||
UCHAR NpxIrql;
|
||||
UCHAR Signalling;
|
||||
};
|
||||
union
|
||||
{
|
||||
UCHAR Size;
|
||||
UCHAR Hand;
|
||||
};
|
||||
union
|
||||
{
|
||||
UCHAR Inserted;
|
||||
UCHAR DebugActive;
|
||||
UCHAR DpcActive;
|
||||
};
|
||||
};
|
||||
XDWORD Lock;
|
||||
};
|
||||
|
||||
XDWORD SignalState;
|
||||
XLIST_ENTRY WaitListHead;
|
||||
} XDISPATCHER_HEADER, * XPDISPATCHER_HEADER;
|
||||
|
||||
// These variables are never accessed in guest code, we can safely use them in little endian
|
||||
typedef struct _XRTL_CRITICAL_SECTION
|
||||
{
|
||||
XDISPATCHER_HEADER Header;
|
||||
long LockCount;
|
||||
int32_t RecursionCount;
|
||||
uint32_t OwningThread;
|
||||
} XRTL_CRITICAL_SECTION;
|
||||
|
||||
typedef struct _XANSI_STRING {
|
||||
XWORD Length;
|
||||
XWORD MaximumLength;
|
||||
xpointer<char> Buffer;
|
||||
} XANSI_STRING;
|
||||
|
||||
typedef struct _XOBJECT_ATTRIBUTES
|
||||
{
|
||||
XDWORD RootDirectory;
|
||||
xpointer<XANSI_STRING> Name;
|
||||
xpointer<void> Attributes;
|
||||
} XOBJECT_ATTRIBUTES;
|
||||
|
||||
typedef XDISPATCHER_HEADER XKEVENT;
|
||||
|
||||
typedef struct _XIO_STATUS_BLOCK
|
||||
{
|
||||
union {
|
||||
XDWORD Status;
|
||||
XDWORD Pointer;
|
||||
};
|
||||
be<uint32_t> Information;
|
||||
} XIO_STATUS_BLOCK;
|
||||
|
||||
typedef struct _XOVERLAPPED {
|
||||
XDWORD Internal;
|
||||
XDWORD InternalHigh;
|
||||
XDWORD Offset;
|
||||
XDWORD OffsetHigh;
|
||||
XDWORD hEvent;
|
||||
} XOVERLAPPED;
|
||||
|
||||
// this name is so dumb
|
||||
typedef struct _XXOVERLAPPED {
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
XDWORD Error;
|
||||
XDWORD Length;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
uint32_t InternalLow;
|
||||
uint32_t InternalHigh;
|
||||
};
|
||||
};
|
||||
uint32_t InternalContext;
|
||||
XDWORD hEvent;
|
||||
XDWORD pCompletionRoutine;
|
||||
XDWORD dwCompletionContext;
|
||||
XDWORD dwExtendedError;
|
||||
} XXOVERLAPPED, *PXXOVERLAPPED;
|
||||
|
||||
static_assert(sizeof(_XXOVERLAPPED) == 0x1C);
|
||||
|
||||
typedef struct _XVIDEO_MODE
|
||||
{
|
||||
be<uint32_t> DisplayWidth;
|
||||
be<uint32_t> DisplayHeight;
|
||||
be<uint32_t> IsInterlaced;
|
||||
be<uint32_t> IsWidescreen;
|
||||
be<uint32_t> IsHighDefinition;
|
||||
be<uint32_t> RefreshRate;
|
||||
be<uint32_t> VideoStandard;
|
||||
be<uint32_t> Unknown4A;
|
||||
be<uint32_t> Unknown01;
|
||||
be<uint32_t> reserved[3];
|
||||
} XVIDEO_MODE;
|
||||
|
||||
typedef struct _XKSEMAPHORE
|
||||
{
|
||||
XDISPATCHER_HEADER Header;
|
||||
XDWORD Limit;
|
||||
} XKSEMAPHORE;
|
||||
53
PowerUtils/xex.cpp
Normal file
53
PowerUtils/xex.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "xex.h"
|
||||
#include <cassert>
|
||||
|
||||
std::unique_ptr<uint8_t[]> Xex2LoadImage(const uint8_t* data)
|
||||
{
|
||||
auto* header = reinterpret_cast<const XEX_HEADER*>(data);
|
||||
auto* security = reinterpret_cast<const XEX2_SECURITY_INFO*>(data + header->AddressOfSecurityInfo);
|
||||
|
||||
const auto* compressionInfo = Xex2FindOptionalHeader<XEX_FILE_FORMAT_INFO>(header, XEX_HEADER_FILE_FORMAT_INFO);
|
||||
|
||||
std::unique_ptr<uint8_t[]> result{};
|
||||
size_t imageSize = security->SizeOfImage;
|
||||
|
||||
if (compressionInfo != nullptr)
|
||||
{
|
||||
assert(compressionInfo->CompressionType >= XEX_COMPRESSION_BASIC);
|
||||
assert(compressionInfo->EncryptionType == XEX_ENCRYPTION_NONE);
|
||||
|
||||
if (compressionInfo->CompressionType == XEX_COMPRESSION_NONE)
|
||||
{
|
||||
result = std::make_unique<uint8_t[]>(imageSize);
|
||||
memcpy(result.get(), data + header->SizeOfHeader, imageSize);
|
||||
}
|
||||
else if (compressionInfo->CompressionType == XEX_COMPRESSION_BASIC)
|
||||
{
|
||||
auto* blocks = reinterpret_cast<const XEX_BASIC_FILE_COMPRESSION_INFO*>(compressionInfo + 1);
|
||||
const size_t numBlocks = (compressionInfo->SizeOfHeader / sizeof(XEX_BASIC_FILE_COMPRESSION_INFO)) - 1;
|
||||
|
||||
imageSize = 0;
|
||||
for (size_t i = 0; i < numBlocks; i++)
|
||||
{
|
||||
imageSize += blocks[i].SizeOfData + blocks[i].SizeOfPadding;
|
||||
}
|
||||
|
||||
result = std::make_unique<uint8_t[]>(imageSize);
|
||||
auto* srcData = data + header->SizeOfHeader;
|
||||
auto* destData = result.get();
|
||||
|
||||
for (size_t i = 0; i < numBlocks; i++)
|
||||
{
|
||||
memcpy(destData, srcData, blocks[i].SizeOfData);
|
||||
|
||||
srcData += blocks[i].SizeOfData;
|
||||
destData += blocks[i].SizeOfData;
|
||||
|
||||
memset(destData, 0, blocks[i].SizeOfPadding);
|
||||
destData += blocks[i].SizeOfPadding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
126
PowerUtils/xex.h
Normal file
126
PowerUtils/xex.h
Normal file
@@ -0,0 +1,126 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "xbox.h"
|
||||
|
||||
#define XEX_COMPRESSION_NONE 0
|
||||
#define XEX_COMPRESSION_BASIC 1
|
||||
|
||||
#define XEX_ENCRYPTION_NONE 0
|
||||
|
||||
enum _XEX_OPTIONAL_HEADER_TYPES
|
||||
{
|
||||
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,
|
||||
};
|
||||
|
||||
typedef struct _XEX_FILE_FORMAT_INFO
|
||||
{
|
||||
be<uint32_t> SizeOfHeader;
|
||||
be<uint16_t> EncryptionType;
|
||||
be<uint16_t> CompressionType;
|
||||
} XEX_FILE_FORMAT_INFO;
|
||||
|
||||
typedef struct _XEX_BASIC_FILE_COMPRESSION_INFO
|
||||
{
|
||||
be<uint32_t> SizeOfData;
|
||||
be<uint32_t> SizeOfPadding;
|
||||
} XEX_BASIC_FILE_COMPRESSION_INFO;
|
||||
|
||||
typedef struct _XEX_OPTIONAL_HEADER
|
||||
{
|
||||
be<uint32_t> Type;
|
||||
be<uint32_t> Address;
|
||||
} XEX_OPTIONAL_HEADER;
|
||||
|
||||
typedef struct _XEX2_SECURITY_INFO
|
||||
{
|
||||
be<uint32_t> SizeOfHeader;
|
||||
be<uint32_t> SizeOfImage;
|
||||
char RsaSignature[0x100];
|
||||
be<uint32_t> Unknown108;
|
||||
be<uint32_t> ImageFlags;
|
||||
be<uint32_t> ImageBase;
|
||||
char SectionDigest[0x14];
|
||||
be<uint32_t> NumberOfImports;
|
||||
char ImportsDigest[0x14];
|
||||
char Xgd2MediaID[0x10];
|
||||
char AesKey[0x10];
|
||||
be<uint32_t> AddressOfExports;
|
||||
char HeaderDigest[0x14];
|
||||
be<uint32_t> Region;
|
||||
be<uint32_t> AllowedMediaTypes;
|
||||
be<uint32_t> NumberOfPageDescriptors;
|
||||
} XEX2_SECURITY_INFO;
|
||||
|
||||
typedef struct _XEX_HEADER
|
||||
{
|
||||
char Signature[4];
|
||||
be<uint32_t> Flags;
|
||||
be<uint32_t> SizeOfHeader;
|
||||
char Reserved[4];
|
||||
be<uint32_t> AddressOfSecurityInfo;
|
||||
be<uint32_t> NumberOfOptionalHeaders;
|
||||
} XEX_HEADER;
|
||||
|
||||
typedef struct _X_RUNTIME_FUNCTION
|
||||
{
|
||||
be<DWORD> BeginAddress;
|
||||
be<DWORD> Flags; // honestly, no idea
|
||||
} X_RUNTIME_FUNCTION;
|
||||
|
||||
template<typename T>
|
||||
inline static const T* Xex2FindOptionalHeader(const void* base, const XEX_OPTIONAL_HEADER* headers, size_t n, _XEX_OPTIONAL_HEADER_TYPES type)
|
||||
{
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
if (headers[i].Type == (uint32_t)type)
|
||||
{
|
||||
if ((type & 0xFF) == 1)
|
||||
{
|
||||
return reinterpret_cast<const T*>(&headers[i].Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
return reinterpret_cast<const T*>(static_cast<const char*>(base) + headers[i].Address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline static const T* Xex2FindOptionalHeader(const XEX_HEADER* header, _XEX_OPTIONAL_HEADER_TYPES type)
|
||||
{
|
||||
return Xex2FindOptionalHeader<T>(header, (XEX_OPTIONAL_HEADER*)(header + 1), header->NumberOfOptionalHeaders, type);
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8_t[]> Xex2LoadImage(const uint8_t* data);
|
||||
Reference in New Issue
Block a user