Initial Commit

This commit is contained in:
Sajid
2024-09-07 18:00:09 +06:00
commit 0f9a53f75a
3352 changed files with 1563708 additions and 0 deletions

View 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
View 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
View 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
View 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
View 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
View 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
View 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);