first commit

This commit is contained in:
dasha 2026-01-05 23:50:53 +03:00
commit 7dd9dd689e
40 changed files with 4100 additions and 0 deletions

View file

@ -0,0 +1,436 @@
#include "pch.h"
#include "Il2CppOffsets.h"
#include "Il2CppApi.h"
#include <libloaderapi.h>
#include <cstdio>
#include <cstdint>
#include <cstddef>
// Type and reflection API implementations
char* Il2CppApi::TypeGetName(const Il2CppType* type) {
auto func = RemoteFuncCall<char*, const Il2CppType*>(
il2CppOffsets::Class::il2cpp_type_get_name
);
return func(type);
}
// Type system API implementations
Il2CppClass* Il2CppApi::GetTypeInfoFromTypeDefinitionIndex(TypeDefinitionIndex index) {
auto func = RemoteFuncCall<Il2CppClass*, TypeDefinitionIndex>(
il2CppOffsets::GetTypeInfoFromTypeDefinitionIndex
);
return func(index);
}
const char* Il2CppApi::ClassGetNamespace(Il2CppClass* klass) {
auto func = RemoteFuncCall<const char*, Il2CppClass*>(
il2CppOffsets::Class::il2cpp_class_get_namespace
);
return func(klass);
}
const char* Il2CppApi::ClassGetName(Il2CppClass* klass) {
auto func = RemoteFuncCall<const char*, Il2CppClass*>(
il2CppOffsets::Class::il2cpp_class_get_name
);
return func(klass);
}
bool Il2CppApi::ClassIsEnum(const Il2CppClass* klass) {
auto func = RemoteFuncCall<bool, const Il2CppClass*>(
il2CppOffsets::Class::il2cpp_class_is_enum
);
auto result = func(klass) != 0;
return result;
}
bool Il2CppApi::ClassIsValueType(const Il2CppClass* klass) {
auto func = RemoteFuncCall<bool, const Il2CppClass*>(
il2CppOffsets::Type::class_is_valuetype
);
return func(klass);
}
int Il2CppApi::ClassGetFlags(const Il2CppClass* klass) {
auto func = RemoteFuncCall<bool, const Il2CppClass*>(
il2CppOffsets::Class::il2cpp_class_get_flags
);
return func(klass);
}
Il2CppClass* Il2CppApi::ClassGetParent(Il2CppClass* klass) {
auto func = RemoteFuncCall<Il2CppClass*, Il2CppClass*>(
il2CppOffsets::Class::il2cpp_class_get_parent
);
return func(klass);
}
const Il2CppType* Il2CppApi::ClassGetType(Il2CppClass* klass) {
auto func = RemoteFuncCall<const Il2CppType*, Il2CppClass*>(
il2CppOffsets::Class::il2cpp_class_get_type
);
return func(klass);
}
Il2CppClass* Il2CppApi::ClassFromName(const Il2CppImage* image, const char* namespaze, const char* name) {
auto func = RemoteFuncCall<Il2CppClass*, const Il2CppImage*, const char*, const char*>(
il2CppOffsets::Class::il2cpp_class_from_name
);
return func(image, namespaze, name);
}
bool Il2CppApi::ClassInit(Il2CppClass* klass) {
auto func = RemoteFuncCall<bool, Il2CppClass*>(
il2CppOffsets::RuntimeStuff::il2cpp_vm_class_init
);
return func(klass);
}
// Method API implementations
const uint8_t* Il2CppApi::ClassGetMethods(Il2CppClass* klass, void* iter) {
auto func = RemoteFuncCall<const uint8_t*, Il2CppClass*, void*>(
il2CppOffsets::Class::il2cpp_class_get_methods
);
return func(klass, iter);
}
const char* Il2CppApi::MethodGetName(const uint8_t* MethodPtr) {
auto func = RemoteFuncCall<const char*, const uint8_t*>(
il2CppOffsets::Methods::il2cpp_method_get_name
);
return func(MethodPtr);
}
const Il2CppType* Il2CppApi::MethodGetReturnType(const uint8_t* method) {
auto func = RemoteFuncCall<const Il2CppType*, const uint8_t*>(
il2CppOffsets::Methods::il2cpp_method_get_return_type
);
return func(method);
}
const uint32_t Il2CppApi::MethodGetParamCount(const uint8_t* method) {
auto func = RemoteFuncCall<const uint32_t, const uint8_t*>(
il2CppOffsets::Methods::il2cpp_method_get_param_count
);
return func(method);
}
const Il2CppType* Il2CppApi::MethodGetParam(const uint8_t* method, uint32_t index) {
auto func = RemoteFuncCall<const Il2CppType*, const uint8_t*, uint32_t>(
il2CppOffsets::Methods::il2cpp_method_get_param
);
return func(method, index);
}
const char* Il2CppApi::MethodGetParamName(const uint8_t* method, uint32_t index) {
auto func = RemoteFuncCall<const char*, const uint8_t*, uint32_t>(
il2CppOffsets::Methods::il2cpp_method_get_param_name
);
return func(method, index);
}
const uintptr_t* Il2CppApi::ClassGetMethodFromName(Il2CppClass* klass, const char* name, int argsCount) {
auto func = RemoteFuncCall<uintptr_t*, Il2CppClass*, const char*, int>(
il2CppOffsets::Class::il2cpp_class_get_method_from_name
);
ClassInit(klass);
return func(klass, name, argsCount);
}
std::string Il2CppApi::GetMethodModifier(uint32_t flags) {
std::stringstream Modifiers;
auto access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
switch (access) {
case METHOD_ATTRIBUTE_PRIVATE: Modifiers << "private "; break;
case METHOD_ATTRIBUTE_PUBLIC: Modifiers << "public "; break;
case METHOD_ATTRIBUTE_FAMILY: Modifiers << "protected "; break;
case METHOD_ATTRIBUTE_ASSEM:
case METHOD_ATTRIBUTE_FAM_AND_ASSEM: Modifiers << "internal "; break;
case METHOD_ATTRIBUTE_FAM_OR_ASSEM: Modifiers << "protected internal "; break;
}
if (flags & METHOD_ATTRIBUTE_STATIC) Modifiers << "static ";
if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
Modifiers << "abstract ";
if ((flags & METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK) == METHOD_ATTRIBUTE_REUSE_SLOT) {
Modifiers << "override ";
}
}
else if (flags & METHOD_ATTRIBUTE_FINAL) {
if ((flags & METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK) == METHOD_ATTRIBUTE_REUSE_SLOT) {
Modifiers << "sealed override ";
}
}
else if (flags & METHOD_ATTRIBUTE_VIRTUAL) {
if ((flags & METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK) == METHOD_ATTRIBUTE_NEW_SLOT) {
Modifiers << "virtual ";
}
else {
Modifiers << "override ";
}
}
if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) Modifiers << "extern ";
return Modifiers.str();
}
// Field API implementations
uintptr_t* Il2CppApi::ClassGetFields(Il2CppClass* klass, void** iter) {
auto func = RemoteFuncCall<uintptr_t*, Il2CppClass*, void**>(
il2CppOffsets::Class::il2cpp_class_get_fields
);
ClassInit(klass);
return func(klass, iter);
}
int Il2CppApi::FieldGetFlags(uintptr_t* field) {
auto func = RemoteFuncCall<int, uintptr_t*>(
il2CppOffsets::Field::il2cpp_field_get_flags
);
return func(field);
}
const Il2CppType* Il2CppApi::FieldGetType(uintptr_t* field) {
auto func = RemoteFuncCall<const Il2CppType*, uintptr_t*>(
il2CppOffsets::Field::il2cpp_field_get_type
);
return func(field);
}
const char* Il2CppApi::FieldGetName(uintptr_t* field) {
auto func = RemoteFuncCall<const char*, uintptr_t*>(
il2CppOffsets::Field::il2cpp_field_get_name
);
return func(field);
}
void Il2CppApi::FieldStaticGetValue(uintptr_t* field, void* value) {
auto func = RemoteFuncCall<void, uintptr_t*, void*>(
il2CppOffsets::Field::il2cpp_field_static_get_value
);
func(field, value);
}
size_t Il2CppApi::FieldStaticGetValue(uintptr_t* field) {
size_t out = 0;
FieldStaticGetValue(
field,
&out
);
return out;
}
bool Il2CppApi::FieldIsInstance(uintptr_t* field) {
int flags = Il2CppApi::FieldGetFlags(field);
return (flags & FIELD_ATTRIBUTE_STATIC) == 0;
}
size_t Il2CppApi::FieldGetOffset(uintptr_t* field) {
auto func = RemoteFuncCall<size_t, uintptr_t*>(
il2CppOffsets::Field::il2cpp_field_get_offset
);
return func(field);
}
uint32_t Il2CppApi::FieldGetToken(uintptr_t* field) {
auto func = RemoteFuncCall<uint32_t, uintptr_t*>(
il2CppOffsets::Field::il2cpp_field_get_token
);
return func(field);
}
// Generic type API implementations
const size_t* Il2CppApi::ClassGetInterfaces(const uint8_t* klass, size_t& count) {
const uint64_t count_ptr = *reinterpret_cast<const uint64_t*>(klass + 24);
count = static_cast<size_t>(*reinterpret_cast<const uint8_t*>(count_ptr + 67LL)) ^ 0x9BLL;
const size_t* interfaces = *reinterpret_cast<const size_t* const*>(klass + 16);
return interfaces ? interfaces : nullptr;
}
const Il2CppGenericContainer* Il2CppApi::GenericClassGetGenericContainer(const Il2CppGenericClass* generic_class) {
if (!generic_class) return nullptr;
return generic_class->genericContainer;
}
const Il2CppGenericClass* Il2CppApi::ClassGetGenericClass(const Il2CppClass* klass) {
if (!klass) return nullptr;
return klass->generic_class;
}
uint32_t Il2CppApi::ClassGetGenericArgCount(const Il2CppClass* klass) {
auto generic_class = ClassGetGenericClass(klass);
if (!generic_class) return 0;
auto generic_container = GenericClassGetGenericContainer(generic_class);
if (!generic_container) return 0;
return generic_container->type_argc;
}
const void* Il2CppApi::ClassGetGenericArgType(const Il2CppClass* klass, uint64_t index) {
if (!klass) return nullptr;
const Il2CppGenericClass* generic_class = klass->generic_class;
if (!generic_class) return nullptr;
const Il2CppGenericContainer* generic_container = generic_class->genericContainer;
if (!generic_container) return nullptr;
const void** argv = generic_container->type_argv;
if (!argv) return nullptr;
return argv[index];
}
bool Il2CppApi::ClassIsGeneric(const Il2CppClass* klass) {
if (!klass) return false;
const Il2CppGenericClass* generic_class = klass->generic_class;
if (!generic_class) return false;
return generic_class->genericContainer != nullptr;
}
Il2CppClass* Il2CppApi::FromIl2CppType(const Il2CppType* type) {
auto func = RemoteFuncCall<Il2CppClass*, const Il2CppType*>(
il2CppOffsets::Class::FromIl2CppType
);
return func(type);
}
// Runtime API implementations
const uintptr_t* Il2CppApi::RuntimeClassInit() {
auto func = RemoteFuncCall<const uintptr_t*>(
il2CppOffsets::RuntimeStuff::il2cpp_runtime_class_init
);
return func();
}
Il2CppObject* Il2CppApi::MethodInvoke(const uintptr_t* method, void* obj, void** params) { //under the hood this is il2cpp_runtime_invoke
Il2CppException* exception = nullptr;
auto func = RemoteFuncCall<Il2CppObject*, const uintptr_t*, void*, void**, Il2CppException**>(
il2CppOffsets::RuntimeStuff::il2cpp_runtime_invoke
);
return func(method, obj, params, &exception);
}
Il2CppDomain* Il2CppApi::DomainGet() {
auto func = RemoteFuncCall<Il2CppDomain*>(
il2CppOffsets::Domain::il2cpp_domain_get
);
return func();
}
Il2CppAssembly** Il2CppApi::DomainGetAssemblies(size_t* size) {
uintptr_t assemblies_array = il2CppOffsets::gIBaseAddress + 0x43B5138;
uintptr_t* asm_start_ptr = *reinterpret_cast<uintptr_t**>(assemblies_array);
uintptr_t* asm_end_ptr = *reinterpret_cast<uintptr_t**>(assemblies_array + sizeof(uintptr_t));
*size = (reinterpret_cast<uintptr_t>(asm_end_ptr) - reinterpret_cast<uintptr_t>(asm_start_ptr)) / sizeof(uintptr_t);
return reinterpret_cast<Il2CppAssembly**>(asm_start_ptr);
}
const Il2CppAssembly* Il2CppApi::DomainAssemblyOpen(const char* name)
{
// RCX = Il2CppDomain*, RDX = const char*
auto func = RemoteFuncCall<const Il2CppAssembly*,
Il2CppDomain*,
const char*>(
il2CppOffsets::Domain::il2cpp_domain_assembly_open
);
Il2CppDomain* domain = DomainGet();
return func(domain, name);
}
const Il2CppImage* Il2CppApi::AssemblyGetImage(const Il2CppAssembly* assembly) {
auto func = RemoteFuncCall<const Il2CppImage*, const Il2CppAssembly*>(
il2CppOffsets::Domain::il2cpp_assembly_get_image
);
return func(assembly);
}
Il2CppClass* Il2CppApi::ObjectGetClass(Il2CppObject* obj)
{
return obj->klass;
}
const void* Il2CppApi::ObjectUnbox(Il2CppObject* obj) {
return reinterpret_cast<void*>(reinterpret_cast<uint8_t*>(obj) + sizeof(Il2CppObject));
}
Il2CppArray* Il2CppApi::ArrayNew(Il2CppClass* elementTypeInfo, il2cpp_array_size_t length) {
auto func = RemoteFuncCall<Il2CppArray*, Il2CppClass*, il2cpp_array_size_t>(
il2CppOffsets::RuntimeStuff::il2cpp_vm_array_new
);
return func(elementTypeInfo, length);
}
Il2CppObject* Il2CppApi::ObjectNew(Il2CppClass* klass) {
auto func = RemoteFuncCall<Il2CppObject*, Il2CppClass*>(
il2CppOffsets::RuntimeStuff::il2cpp_object_new
);
ClassInit(klass);
return func(klass);
}
void Il2CppApi::GCDisable() {
auto func = RemoteFuncCall<void>(
il2CppOffsets::GC::il2cpp_gc_disable
);
return func();
}
Il2CppThread* Il2CppApi::ThreadAttach(Il2CppDomain* domain) {
auto func = RemoteFuncCall<Il2CppThread*, Il2CppDomain*>(
il2CppOffsets::RuntimeStuff::il2cpp_thread_attach
);
return func(domain);
}
const char* Il2CppApi::AssemblyGetName(const Il2CppAssembly* assembly) {
auto baseAddress = reinterpret_cast<const uint8_t*>(assembly);
uint64_t* encryptedPtr = reinterpret_cast<uint64_t*>(const_cast<uint8_t*>(baseAddress) + 0x18LL);
uint64_t ptrObfuscated = *encryptedPtr;
uint64_t realPtr = ptrObfuscated - 0x6E24B24F7558EC86LL;
return reinterpret_cast<const char*>(realPtr);
}
uint32_t Il2CppApi::ImageGetClassCount(const Il2CppImage* image)
{
uint8_t* base = reinterpret_cast<uint8_t*>(const_cast<Il2CppImage*>(image));
uint32_t rawValue = *reinterpret_cast<uint32_t*>(base + 16);
uint32_t value = rawValue ^ 0x183E6E00u;
return value;
}
Il2CppClass* Il2CppApi::ImageGetClass(const Il2CppImage* image, size_t index) {
uint8_t* base = reinterpret_cast<uint8_t*>(const_cast<Il2CppImage*>(image));
uint32_t rawValue = *reinterpret_cast<uint32_t*>(base + 48);
int value = rawValue - 1579693933;
return Il2CppApi::GetTypeInfoFromTypeDefinitionIndex(value + index);
}

View file

@ -0,0 +1,83 @@
#pragma once
#include <cstdint>
#include <functional>
#include <string>
#include <map>
#include "il2cpp-class.h"
#include "Il2CppOffsets.h"
#include "il2cpp-metadata.h"
#include "il2cpp-tabledefs.h"
#include "il2cpp-api-types.h"
class Il2CppApi {
public:
// Type system API
static Il2CppClass* GetTypeInfoFromTypeDefinitionIndex(TypeDefinitionIndex index);
static const char* ClassGetNamespace(Il2CppClass* klass);
static const char* ClassGetName(Il2CppClass* klass);
static bool ClassIsEnum(const Il2CppClass* klass);
static bool ClassIsValueType(const Il2CppClass* klass);
static int ClassGetFlags(const Il2CppClass* klass);
static Il2CppClass* ClassGetParent(Il2CppClass* klass);
static const Il2CppType* ClassGetType(Il2CppClass* klass);
static Il2CppClass* ClassFromName(const Il2CppImage* image, const char* namespaze, const char* name);
static bool ClassInit(Il2CppClass* klass);
// Method API
static const uint8_t* ClassGetMethods(Il2CppClass* klass, void* iter);
static const char* MethodGetName(const uint8_t* MethodPtr);
static const Il2CppType* MethodGetReturnType(const uint8_t* method);
static const uint32_t MethodGetParamCount(const uint8_t* method);
static const Il2CppType* MethodGetParam(const uint8_t* method, uint32_t index);
static const char* MethodGetParamName(const uint8_t* method, uint32_t index);
static const uintptr_t* ClassGetMethodFromName(Il2CppClass* klass, const char* name, int argsCount);
static std::string GetMethodModifier(uint32_t flags);
// Field API
static uintptr_t* ClassGetFields(Il2CppClass* klass, void** iter);
static int FieldGetFlags(uintptr_t* field);
static const Il2CppType* FieldGetType(uintptr_t* field);
static const char* FieldGetName(uintptr_t* field);
static void FieldStaticGetValue(uintptr_t* field, void* value);
static size_t FieldStaticGetValue(uintptr_t* field);
static bool FieldIsInstance(uintptr_t* field);
static size_t FieldGetOffset(uintptr_t* field);
static uint32_t FieldGetToken(uintptr_t* field);
// Generic type API
static const void* ObjectUnbox(Il2CppObject* obj);
static const size_t* ClassGetInterfaces(const uint8_t* klass, size_t& count);
static const Il2CppGenericContainer* GenericClassGetGenericContainer(const Il2CppGenericClass* generic_class);
static const Il2CppGenericClass* ClassGetGenericClass(const Il2CppClass* klass);
static uint32_t ClassGetGenericArgCount(const Il2CppClass* klass);
static const void* ClassGetGenericArgType(const Il2CppClass* klass, uint64_t index);
static bool ClassIsGeneric(const Il2CppClass* klass);
// Type and reflection API
static char* TypeGetName(const Il2CppType* type);
static Il2CppClass* FromIl2CppType(const Il2CppType* type);
// Runtime API
static const uintptr_t* RuntimeClassInit();
static Il2CppDomain* DomainGet();
static Il2CppObject* MethodInvoke(const uintptr_t* method, void* obj, void** params);
static Il2CppAssembly** DomainGetAssemblies(size_t* size);
static const Il2CppAssembly* DomainAssemblyOpen(const char* name);
static const Il2CppImage* AssemblyGetImage(const Il2CppAssembly* assembly);
static const char* AssemblyGetName(const Il2CppAssembly* assembly);
static Il2CppClass* ObjectGetClass(Il2CppObject* obj);
static uint32_t ImageGetClassCount(const Il2CppImage* image);
static Il2CppThread* ThreadAttach(Il2CppDomain* domain);
static Il2CppArray* ArrayNew(Il2CppClass* elementTypeInfo, il2cpp_array_size_t length);
static Il2CppObject* ObjectNew(Il2CppClass* klass);
static void GCDisable();
static Il2CppClass* ImageGetClass(const Il2CppImage* image, size_t index);
private:
template <typename ReturnType, typename... Args>
static auto RemoteFuncCall(uintptr_t offset) {
using FuncType = ReturnType(*)(Args...);
return reinterpret_cast<FuncType>(offset + il2CppOffsets::gIBaseAddress);
}
};

View file

@ -0,0 +1,53 @@
#include "pch.h"
#include "Il2CppHelper.h"
const uint8_t* Il2CppHelper::FindMethodInHierarchy(Il2CppClass* klass, const std::string &methodName, const std::vector<std::string> paramCount) {
const uint8_t* method = nullptr;
while (klass != nullptr) {
method = FindMethod(klass, methodName, paramCount);
if(method) break;
klass = Il2CppApi::ClassGetParent(klass);
}
return method;
}
const uint8_t* Il2CppHelper::FindMethod(Il2CppClass* klass, const std::string &name, const std::vector<std::string> &arg_types)
{
Il2CppApi::ClassInit(klass);
void* iter = nullptr;
while (auto method = Il2CppApi::ClassGetMethods(klass, &iter)) {
auto methodName = Il2CppApi::MethodGetName(method);
if (methodName == name) {
auto paramCount = Il2CppApi::MethodGetParamCount(method);
if (paramCount == arg_types.size()) {
bool fail = false;
for (size_t i = 0; i < paramCount; ++i) {
auto typeName = Il2CppApi::TypeGetName(Il2CppApi::MethodGetParam(method, i));
if (arg_types[i] != typeName) {
fail = true;
break;
}
}
if (!fail) {
return method;
}
}
}
}
return nullptr;
}
uintptr_t* Il2CppHelper::GetFieldDataPtr(uintptr_t* field, Il2CppObject* object) {
size_t offset = Il2CppApi::FieldGetOffset(field);
uintptr_t* base_ptr = reinterpret_cast<uintptr_t*>(object);
return base_ptr + offset;
}

View file

@ -0,0 +1,9 @@
#pragma once
#include "Il2CppApi.h"
class Il2CppHelper {
public:
static const uint8_t* FindMethodInHierarchy(Il2CppClass* klass, const std::string &methodName, const std::vector<std::string> paramCount);
static const uint8_t* FindMethod(Il2CppClass* klass, const std::string &name, const std::vector<std::string> &arg_types);
static uintptr_t* GetFieldDataPtr(uintptr_t* field, Il2CppObject* object);
};

View file

@ -0,0 +1,253 @@
#include "pch.h"
#include "Il2CppMetadata.h"
enum class Il2CppType_Flag {
is_param,
is_return,
is_field,
is_class,
};
std::string Il2CppType_Helper(const Il2CppType* type_ptr, Il2CppType_Flag flag) {
std::string ret;
const uint8_t type_flag = (reinterpret_cast<const uint8_t*>(type_ptr))[11];
if (flag == Il2CppType_Flag::is_return
|| flag == Il2CppType_Flag::is_field) {
if (type_flag & IL2CPP_TYPE_BYREF) {
ret += "ref ";
}
}
if (flag == Il2CppType_Flag::is_param) {
if (type_flag & IL2CPP_TYPE_BYREF) {
if (type_ptr->attrs & PARAM_ATTRIBUTE_OUT && !(type_ptr->attrs & PARAM_ATTRIBUTE_IN)) {
ret += "out ";
}
else if (type_ptr->attrs & PARAM_ATTRIBUTE_IN && !(type_ptr->attrs & PARAM_ATTRIBUTE_OUT)) {
ret += "in ";
}
else {
ret += "ref ";
}
}
else {
if (type_ptr->attrs & PARAM_ATTRIBUTE_IN) {
ret += "[In] ";
}
if (type_ptr->attrs & PARAM_ATTRIBUTE_OUT) {
ret += "[Out] ";
}
}
}
ret += Il2CppApi::TypeGetName(type_ptr);
return ret;
}
std::string Il2CppMetadata::DumpClass(Il2CppClass* klass) {
uint8_t* byte_klass = reinterpret_cast<uint8_t*>(klass);
std::stringstream outPut;
/*Il2CppApi::ClassInit(klass); */
auto QualName = Il2CppApi::TypeGetName(Il2CppApi::ClassGetType(klass));
auto flags = Il2CppApi::ClassGetFlags(klass);
if (flags & TYPE_ATTRIBUTE_SERIALIZABLE) {
outPut << "[Serializable]\n";
}
//TODO attribute
bool is_valuetype = Il2CppApi::ClassIsValueType(klass);
bool is_enum = Il2CppApi::ClassIsEnum(klass);
auto visibility = flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
switch (visibility) {
case TYPE_ATTRIBUTE_PUBLIC:
case TYPE_ATTRIBUTE_NESTED_PUBLIC:
outPut << "public ";
break;
case TYPE_ATTRIBUTE_NOT_PUBLIC:
case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
outPut << "internal ";
break;
case TYPE_ATTRIBUTE_NESTED_PRIVATE:
outPut << "private ";
break;
case TYPE_ATTRIBUTE_NESTED_FAMILY:
outPut << "protected ";
break;
case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
outPut << "protected internal ";
break;
}
if (flags & TYPE_ATTRIBUTE_ABSTRACT && flags & TYPE_ATTRIBUTE_SEALED) {
outPut << "static ";
}
else if (!(flags & TYPE_ATTRIBUTE_INTERFACE) && flags & TYPE_ATTRIBUTE_ABSTRACT) {
outPut << "abstract ";
}
else if (!is_valuetype && !is_enum && flags & TYPE_ATTRIBUTE_SEALED) {
outPut << "sealed ";
}
if (flags & TYPE_ATTRIBUTE_INTERFACE) {
outPut << "interface ";
}
else if (is_enum) {
outPut << "enum ";
}
else if (is_valuetype) {
outPut << "struct ";
}
else {
outPut << "class ";
}
outPut << QualName;
std::vector<std::string> extends;
auto parent = Il2CppApi::ClassGetParent(klass);
if (!is_valuetype && !is_enum && parent) {
auto parent_type = Il2CppApi::ClassGetType(parent);
if (parent_type->type != IL2CPP_TYPE_OBJECT) {
extends.emplace_back(Il2CppApi::ClassGetName(parent));
}
}
{
size_t count = 0;
auto interfaces = Il2CppApi::ClassGetInterfaces(byte_klass, count);
for (size_t i = 0; i < count; ++i) {
Il2CppClass* itf = reinterpret_cast<Il2CppClass*>(interfaces[i]);
if (itf) {
const Il2CppType* ifaceType = Il2CppApi::ClassGetType(itf);
const char* fullName = Il2CppApi::TypeGetName(ifaceType);
extends.emplace_back(fullName);
}
}
}
if (!extends.empty()) {
outPut << " : " << extends[0];
for (int i = 1; i < extends.size(); ++i) {
outPut << ", " << extends[i];
}
}
outPut << "\n{";
outPut << Il2CppMetadata::DumpClassFields(klass);
outPut << Il2CppMetadata::DumpClassMethods(klass);
outPut << "}\n";
return outPut.str();
}
std::string Il2CppMetadata::DumpClassMethods(Il2CppClass* klass) {
std::stringstream outPut;
outPut << "\n\t// Methods\n";
void* iter = nullptr;
while (const uint8_t* method = Il2CppApi::ClassGetMethods(klass, &iter)) {
//TODO attribute
int64_t VA = *(reinterpret_cast<const uint64_t*>(method + il2CppOffsets::Methods::method_pointer));
int64_t RVA = VA - il2CppOffsets::gIBaseAddress;
if (method) {
outPut << "\t// RVA: 0x"
<< std::hex << RVA
<< " VA: 0x"
<< std::hex << VA;
}
else {
outPut << "\t// RVA: 0x VA: 0x0";
}
outPut << "\n\t";
const uint32_t flags = *reinterpret_cast<const uint32_t*>(method + il2CppOffsets::Methods::il2cpp_method_get_flags);
outPut << Il2CppApi::GetMethodModifier(flags);
//TODO genericContainerIndex
const Il2CppType* return_type = Il2CppApi::MethodGetReturnType(method);
outPut << Il2CppType_Helper(return_type, Il2CppType_Flag::is_return) << " "
<< Il2CppApi::MethodGetName(method) << "(";
const uint32_t param_count = Il2CppApi::MethodGetParamCount(method);
for (uint32_t i = 0; i < param_count; ++i) {
const Il2CppType* param_type = Il2CppApi::MethodGetParam(method, i);
outPut << Il2CppType_Helper(param_type, Il2CppType_Flag::is_param) << " "
<< Il2CppApi::MethodGetParamName(method, i);
outPut << ", ";
}
if (param_count != 0) {
outPut.seekp(-2, std::ios_base::cur);
}
outPut << ") { }\n";
//TODO GenericInstMethod
}
return outPut.str();
}
std::string Il2CppMetadata::DumpClassFields(Il2CppClass* klass) {
std::stringstream outPut;
outPut << "\n\t// Fields\n";
auto is_enum = Il2CppApi::ClassIsEnum(klass);
void* iter = nullptr;
while (auto field = Il2CppApi::ClassGetFields(klass, &iter)) {
//TODO attribute
outPut << "\t";
auto attrs = Il2CppApi::FieldGetFlags(field);
auto access = attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
switch (access) {
case FIELD_ATTRIBUTE_PRIVATE:
outPut << "private ";
break;
case FIELD_ATTRIBUTE_PUBLIC:
outPut << "public ";
break;
case FIELD_ATTRIBUTE_FAMILY:
outPut << "protected ";
break;
case FIELD_ATTRIBUTE_ASSEMBLY:
case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
outPut << "internal ";
break;
case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
outPut << "protected internal ";
break;
}
if (attrs & FIELD_ATTRIBUTE_LITERAL) {
outPut << "const ";
}
else {
if (attrs & FIELD_ATTRIBUTE_STATIC) {
outPut << "static ";
}
if (attrs & FIELD_ATTRIBUTE_INIT_ONLY) {
outPut << "readonly ";
}
}
const Il2CppType* field_type = Il2CppApi::FieldGetType(field);
outPut << Il2CppType_Helper(field_type, Il2CppType_Flag::is_field) <<
" " << Il2CppApi::FieldGetName(field);
if (attrs & FIELD_ATTRIBUTE_LITERAL && is_enum) {
uint64_t val = 0;
Il2CppApi::FieldStaticGetValue(field, &val);
outPut << " = " << std::dec << val;
}
outPut << "; // 0x" << std::hex << Il2CppApi::FieldGetOffset(field) << "\n";
}
return outPut.str();
}

View file

@ -0,0 +1,9 @@
#pragma once
#include "Il2CppApi.h"
class Il2CppMetadata {
public:
static std::string DumpClass(Il2CppClass* klass);
static std::string DumpClassMethods(Il2CppClass* klass);
static std::string DumpClassFields(Il2CppClass* klass);
};

View file

@ -0,0 +1,66 @@
#pragma once
#include "pch.h"
//APIs Offsets Should Be Changed Every Update!
namespace il2CppOffsets {
const uintptr_t gIBaseAddress = reinterpret_cast<const uintptr_t>(GetModuleHandleA("GenshinImpact.exe"));
constexpr int GetTypeInfoFromTypeDefinitionIndex = 0x5391B0;
//easily gotten by searching this string " because generic types cannot have explicit layout."
namespace Class {
constexpr int il2cpp_type_get_name = 0x4C2710;
constexpr int il2cpp_class_get_namespace = 0x4C1900;
//string: " %s%s%s must be instantiated using the ScriptableObject.CreateInstance method instead of new %s."
constexpr int il2cpp_class_get_name = 0x4C18F0;
//string: " %s%s%s must be instantiated using the ScriptableObject.CreateInstance method instead of new %s."
constexpr int il2cpp_class_get_methods = 0x4C18B0;
constexpr int FromIl2CppType = 0x5299B0;
constexpr int il2cpp_class_from_name = 0x4C1800;
constexpr int il2cpp_class_get_method_from_name = 0x4C18D0;
constexpr int il2cpp_class_get_fields = 0x4C1810;
constexpr int il2cpp_class_get_flags = 0x4C19A0;
constexpr int il2cpp_class_get_type = 0x4C1A00;
constexpr int il2cpp_class_get_parent = 0x4C1940;
constexpr int il2cpp_class_is_enum = 0x4C1AD0;
}
namespace Methods {
const int il2cpp_method_get_name = 0x4C2150;
const int il2cpp_method_get_return_type = 0x4C2130;
const int il2cpp_method_get_param_count = 0x4C21A0;
const int il2cpp_method_get_param = 0x4C21B0;
const int il2cpp_method_get_param_name = 0x4C22B0;
constexpr int method_pointer = 0x8;
constexpr int il2cpp_method_get_flags = 0x2A;
}
namespace GC {
constexpr int il2cpp_gc_disable = 0x4C1EA0;
}
namespace Domain {
constexpr int il2cpp_domain_get = 0x4C1B30;
constexpr int il2cpp_domain_get_assemblies = 0x0;
constexpr int il2cpp_domain_assembly_open = 0x4C1BC0;
constexpr int il2cpp_assembly_get_image = 0x4C1770;
}
namespace Field {
constexpr int il2cpp_field_get_name = 0x4C1C50;
constexpr int il2cpp_field_get_type = 0x4C1CA0;
constexpr int il2cpp_field_get_flags = 0x4C1C60;
constexpr int il2cpp_field_get_offset = 0x4C1C90;
constexpr int il2cpp_field_get_token = 0x4C1C80;
constexpr int il2cpp_field_static_get_value = 0x4C1E30;
}
namespace RuntimeStuff {
constexpr int il2cpp_runtime_class_init = 0x4C8DF0;
constexpr int il2cpp_vm_class_init = 0x52ED90;
constexpr int il2cpp_thread_attach = 0x4C26A0;
constexpr int il2cpp_vm_array_new = 0x4C1720;
constexpr int il2cpp_object_new = 0x545A00;
constexpr int il2cpp_runtime_invoke = 0x4C23C0;
}
namespace Type {
constexpr int class_is_valuetype = 0x4C1990;
}
}