Last active
May 9, 2020 03:17
-
-
Save Nukem9/8889220f787cafcb60bc167d65a0d871 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "stdafx.h" | |
#include <stdio.h> | |
#include <vector> | |
#include <string> | |
#include <unordered_set> | |
#include <unordered_map> | |
class igBaseMeta | |
{ | |
public: | |
char _pad0[0x10]; | |
const char *Name; | |
}; | |
static_assert(offsetof(igBaseMeta, Name) == 0x10); | |
class igMetaObject : public igBaseMeta | |
{ | |
public: | |
uint32_t MemberCount; | |
char _pad1[0x8]; | |
class igMetaField **Members; | |
char _pad2[0x10]; | |
igMetaObject *Parent; | |
char _pad3[0x12]; | |
uint16_t SizeofSize; | |
}; | |
static_assert(offsetof(igMetaObject, MemberCount) == 0x18); | |
static_assert(offsetof(igMetaObject, Members) == 0x28); | |
static_assert(offsetof(igMetaObject, Parent) == 0x40); | |
static_assert(offsetof(igMetaObject, SizeofSize) == 0x5A); | |
class igMetaField | |
{ | |
public: | |
uintptr_t igMetaFieldVtable; | |
uint16_t ParentMetaObjectIndex; | |
uint16_t TypeIndex; | |
uint16_t InternalIndex; | |
uint16_t Size; | |
uint32_t Offset; | |
void *Attributes; | |
void *Properties; | |
const char *FieldName; | |
class igMemoryRefMetaField *Default; | |
virtual igBaseMeta *GetMetaType() = 0; | |
}; | |
static_assert(offsetof(igMetaField, ParentMetaObjectIndex) == 0x10); | |
static_assert(offsetof(igMetaField, Offset) == 0x18); | |
static_assert(offsetof(igMetaField, FieldName) == 0x30); | |
static_assert(offsetof(igMetaField, Default) == 0x38); | |
class igEnumMetaField : public igMetaField | |
{ | |
public: | |
uintptr_t igEnumMetaFieldVtable; | |
igBaseMeta *MetaEnum;// igMetaEnum * | |
}; | |
static_assert(offsetof(igEnumMetaField, MetaEnum) == 0x48); | |
class igBitFieldMetaField : public igMetaField | |
{ | |
public: | |
char _pad0[0x8]; | |
uint32_t Shift; | |
uint32_t Bits; | |
igMetaField *StorageMetaField; | |
igMetaField *AssignmentMetaField; | |
}; | |
static_assert(offsetof(igBitFieldMetaField, Shift) == 0x48); | |
static_assert(offsetof(igBitFieldMetaField, Bits) == 0x4C); | |
class igRefMetaField : public igMetaField | |
{ | |
public: | |
uintptr_t igRefMetaFieldVtable; | |
bool Construct; | |
bool Destruct; | |
bool Reconstruct; | |
bool RefCounted; | |
}; | |
static_assert(offsetof(igRefMetaField, Construct) == 0x48); | |
class igHandleMetaField : public igRefMetaField | |
{ | |
public: | |
igMetaObject *MetaObject; | |
}; | |
static_assert(offsetof(igHandleMetaField, MetaObject) == 0x50); | |
class igObjectRefMetaField : public igRefMetaField | |
{ | |
public: | |
igMetaObject *MetaObject; | |
}; | |
static_assert(offsetof(igObjectRefMetaField, MetaObject) == 0x50); | |
class igMemoryRefMetaField : public igRefMetaField | |
{ | |
public: | |
int MemSize; | |
igMetaField *MemType; | |
int32_t MemTypeAlignment; | |
igMetaField *MemTypeRef; | |
bool ReleaseOnCopy; | |
bool ReleaseOnReset; | |
}; | |
static_assert(offsetof(igMemoryRefMetaField, MemType) == 0x58); | |
class igVectorMetaField : public igRefMetaField | |
{ | |
public: | |
igMetaField *MemType; | |
igMetaField *MemTypeRef; | |
int32_t MemTypeAlignment; | |
igMetaObject *ElementType; | |
int32_t InitialCapacity; | |
}; | |
static_assert(offsetof(igVectorMetaField, ElementType) == 0x68); | |
std::string GetMetaTypeName(igMetaField *Field) | |
{ | |
char temp[1024] = {}; | |
auto type = Field->GetMetaType()->Name; | |
#if 0 | |
if (!_stricmp(type, "igBoolMetaField")) | |
return "bool"; | |
else if (!_stricmp(type, "igCharMetaField")) | |
return "int8_t"; | |
else if (!_stricmp(type, "igUnsignedCharMetaField")) | |
return "uint8_t"; | |
else if (!_stricmp(type, "igShortMetaField")) | |
return "int16_t"; | |
else if (!_stricmp(type, "igUnsignedShortMetaField")) | |
return "uint16_t"; | |
else if (!_stricmp(type, "igIntMetaField")) | |
return "int32_t"; | |
else if (!_stricmp(type, "igUnsignedIntMetaField")) | |
return "uint32_t"; | |
else if (!_stricmp(type, "igFloatMetaField")) | |
return "float"; | |
else if (!_stricmp(type, "igVec2fMetaField")) | |
return "float2"; | |
else if (!_stricmp(type, "igVec3fMetaField")) | |
return "float3"; | |
else if (!_stricmp(type, "igVec4fMetaField")) | |
return "float4"; | |
else if (!_stricmp(type, "igSizeTypeMetaField")) | |
return "size_t"; | |
else if (!_stricmp(type, "igStringMetaField")) | |
return "const char*"; | |
#endif | |
if (!_stricmp(type, "igEnumMetaField")) | |
return static_cast<igEnumMetaField *>(Field)->MetaEnum->Name; | |
if (!_stricmp(type, "igBitFieldMetaField")) | |
{ | |
auto ref = static_cast<igBitFieldMetaField *>(Field); | |
sprintf_s(temp, "Bitfield<%d, %d>", ref->Shift, ref->Bits); | |
return temp; | |
} | |
if (!_stricmp(type, "igObjectRefMetaField")) | |
{ | |
sprintf_s(temp, "%s*", static_cast<igObjectRefMetaField *>(Field)->MetaObject->Name); | |
return temp; | |
} | |
if (!_stricmp(type, "igHandleMetaField")) | |
{ | |
auto ref = static_cast<igHandleMetaField *>(Field); | |
sprintf_s(temp, "Handle<%s>", ref->MetaObject ? ref->MetaObject->Name : "igObjectRef"); | |
return temp; | |
} | |
if (!_stricmp(type, "igMemoryRefMetaField")) | |
{ | |
auto ref = static_cast<igMemoryRefMetaField *>(Field); | |
sprintf_s(temp, "MemoryRef<%s, %s, %d>", ref->MemType ? ref->MemType->GetMetaType()->Name : "igObjectRef", ref->MemTypeRef ? ref->MemTypeRef->GetMetaType()->Name : "igObjectRef", ref->MemTypeAlignment); | |
return temp; | |
} | |
if (!_stricmp(type, "igVectorMetaField")) | |
{ | |
auto ref = static_cast<igVectorMetaField *>(Field); | |
sprintf_s(temp, "Vector<%s, %s, %s, %d>", | |
ref->ElementType ? ref->ElementType->Name : "igObjectRef", | |
ref->MemType ? ref->MemType->GetMetaType()->Name : "igObjectRef", | |
ref->MemTypeRef ? ref->MemTypeRef->GetMetaType()->Name : "igObjectRef", | |
ref->InitialCapacity); | |
return temp; | |
} | |
return type; | |
} | |
uintptr_t sub_140DF02C0; | |
uintptr_t sub_140DDC550; | |
uintptr_t sub_140E74CD0; | |
std::vector<igMetaObject *> ProcessedTypes; | |
void DumpAllStructures() | |
{ | |
// Grab all metafield sizes first. Some will be wrong (igRawRefArrayMetaField, igStructMetaField) since they're variable. | |
std::unordered_map<std::string_view, uint32_t> metafieldSizes; | |
for (auto s : ProcessedTypes) | |
{ | |
for (uint32_t i = 0; i < s->MemberCount; i++) | |
metafieldSizes.emplace(s->Members[i]->GetMetaType()->Name, s->Members[i]->Size); | |
} | |
for (auto s : ProcessedTypes) | |
{ | |
std::vector<igMetaField *> fields; | |
std::unordered_set<igMetaField *> overrides; | |
for (uint32_t i = 0; i < s->MemberCount; i++) | |
{ | |
// Sometimes a child class will inherit a member variable from the parent and change the base type (aka templates). But their reflection doesn't support templates. This isn't legal in C++. | |
if (s->Parent && s->Members[i]->Offset < s->Parent->SizeofSize && i < s->Parent->MemberCount) | |
{ | |
if (_stricmp(GetMetaTypeName(s->Members[i]).c_str(), GetMetaTypeName(s->Parent->Members[i]).c_str())) | |
overrides.emplace(s->Members[i]); | |
} | |
fields.emplace_back(s->Members[i]); | |
} | |
std::sort(fields.begin(), fields.end(), [](igMetaField *a, igMetaField *b) | |
{ | |
return a->Offset < b->Offset; | |
}); | |
printf("// PTR: 0x%p -- 0x%p\n", s, s->Members); | |
printf("// sizeof() = 0x%X (%d)\n", (uint32_t)s->SizeofSize, (uint32_t)s->SizeofSize); | |
if (s->Parent) | |
printf("class %s : public %s\n{\n", s->Name, s->Parent->Name); | |
else | |
printf("class %s\n{\n", s->Name); | |
printf("public:\n"); | |
for (auto field : fields) | |
{ | |
if (overrides.count(field) <= 0) | |
{ | |
// Skip any that are part of the parent class | |
if (s->Parent && field->Offset < s->Parent->SizeofSize) | |
continue; | |
printf("\t%s %s; // 0x%X\n", GetMetaTypeName(field).c_str(), field->FieldName, field->Offset); | |
} | |
else | |
{ | |
// Base type override - always printed | |
printf("\t%s %s; // 0x%X OVERRIDE\n", GetMetaTypeName(field).c_str(), field->FieldName, field->Offset); | |
} | |
} | |
// Inject a fake member to get the meta field size (on disk) | |
if (strstr(s->Name, "MetaField")) | |
{ | |
if (metafieldSizes.count(s->Name)) | |
printf("\tmetafield_t _data[%d]; // METAFIELD SIZE\n", metafieldSizes[s->Name]); | |
else | |
printf("\tmetafield_t _data[0]; // METAFIELD SIZE DATA NOT PRESENT\n"); | |
} | |
printf("};\n\n"); | |
} | |
fflush(stdout); | |
fflush(stderr); | |
TerminateProcess(GetCurrentProcess(), 0); | |
} | |
__int64 __fastcall hk_sub_140DF02C0(igMetaObject*& a1, __int64 a2, __int64 (*a3)(void), __int64 a4, const char *a5, __int64 a6, __int64 a7, void (*a8)(void), __int64 a9) | |
{ | |
// a1 = global type info instance | |
// a4 = parent struct type info | |
// a5 = struct name | |
__int64 ret = ((decltype(&hk_sub_140DF02C0))sub_140DF02C0)(a1, a2, a3, a4, a5, a6, a7, a8, a9); | |
if (std::find(ProcessedTypes.begin(), ProcessedTypes.end(), a1) == ProcessedTypes.end()) | |
ProcessedTypes.emplace_back(a1); | |
return ret; | |
} | |
__int64 __fastcall hk_sub_140DDC550(const char *a1, const char **a2, uint32_t *a3, uint32_t a4, char a5, __int64 a6, const char *a7) | |
{ | |
// a1 = enum name | |
// a2 = enum entry names | |
// a3 = enum values | |
// a4 = count | |
// a7 = parent type | |
if (a7) | |
printf("enum %s::%s\n{\n", a7, a1); | |
else | |
printf("enum %s\n{\n", a1); | |
for (uint32_t i = 0; i < a4; i++) | |
printf("\t%s = 0x%X, // %d\n", a2[i], a3[i], a3[i]); | |
printf("};\n\n"); | |
if (strstr(a1, "ECrashSecretZones")) | |
DumpAllStructures(); | |
return ((decltype(&hk_sub_140DDC550))sub_140DDC550)(a1, a2, a3, a4, a5, a6, a7); | |
} | |
__int64 __fastcall hk_sub_140E74CD0(__int64 a1, const char *a2) | |
{ | |
auto fnvHash = [](const char *Str) | |
{ | |
auto length = strlen(Str) + 1; | |
auto hash = 2166136261u; | |
for (size_t i = 0; i < length; ++i) | |
{ | |
hash ^= *Str++; | |
hash *= 16777619u; | |
} | |
return hash; | |
}; | |
// Print every unique string that gets sent through this hash function | |
if (a2) | |
{ | |
static std::unordered_set<uint32_t> hashes; | |
auto hash = fnvHash(a2); | |
if (!hashes.count(hash)) | |
{ | |
fprintf(stderr, "%s\n", a2); | |
hashes.emplace(hash); | |
} | |
} | |
return ((decltype(&hk_sub_140E74CD0))sub_140E74CD0)(a1, a2); | |
} | |
BOOL APIENTRY DllMain(HMODULE hModule, DWORD fdwReason, LPVOID lpReserved) | |
{ | |
if (fdwReason == DLL_PROCESS_ATTACH) | |
{ | |
DisableThreadLibraryCalls(hModule); | |
g_ModuleBase = (uintptr_t)GetModuleHandle(nullptr); | |
freopen("C:\\CrashBandicootNSaneTrilogy.txt", "w", stdout); | |
freopen("C:\\CrashBandicootNSaneTrilogy_err.txt", "w", stderr); | |
setvbuf(stdout, nullptr, _IONBF, 0); | |
setvbuf(stderr, nullptr, _IONBF, 0); | |
sub_140DF02C0 = (uintptr_t)Detours::X64::DetourFunction((uint8_t *)FindPatternSimple(g_ModuleBase, g_ModuleSize, (uint8_t *)"\x48\x89\x5C\x24\x18\x55\x56\x57\x41\x55\x41\x56\x48\x83\xEC\x30\x48\x83\x39\x00\x49\x8B\xF1\x4D\x8B\xF0\x48\x8B\xDA\x48\x8B\xF9\x75\x3E", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"), (uint8_t *)&hk_sub_140DF02C0); | |
sub_140DDC550 = (uintptr_t)Detours::X64::DetourFunction((uint8_t *)FindPatternSimple(g_ModuleBase, g_ModuleSize, (uint8_t *)"\x48\x89\x5C\x24\x10\x4C\x89\x44\x24\x18\x55\x56\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48\x83\xEC\x20\x4C\x8B\xE2\x41\x8B\xF1", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"), (uint8_t *)&hk_sub_140DDC550); | |
//sub_140E74CD0 = (uintptr_t)Detours::X64::DetourFunction((uint8_t *)FindPatternSimple(g_ModuleBase, g_ModuleSize, (uint8_t *)"\x40\x56\x41\x57\x48\x83\xEC\x38\x48\x8B\xF2\x4C\x8B\xF9\x48\x85\xD2\x75\x0A\x33\xC0\x48\x83\xC4\x38\x41\x5F\x5E\xC3\x48\x8D\x51\x2C\x48\x89\x7C\x24\x30\x33\xFF", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"), (uint8_t *)&hk_sub_140E74CD0); | |
} | |
return TRUE; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment