Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Nukem9/8889220f787cafcb60bc167d65a0d871 to your computer and use it in GitHub Desktop.
Save Nukem9/8889220f787cafcb60bc167d65a0d871 to your computer and use it in GitHub Desktop.
#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