first commit
This commit is contained in:
commit
7dd9dd689e
40 changed files with 4100 additions and 0 deletions
436
Core/il2cpp/Api/Il2CppApi.cpp
Normal file
436
Core/il2cpp/Api/Il2CppApi.cpp
Normal 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);
|
||||
}
|
||||
|
||||
83
Core/il2cpp/Api/Il2CppApi.h
Normal file
83
Core/il2cpp/Api/Il2CppApi.h
Normal 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);
|
||||
}
|
||||
};
|
||||
53
Core/il2cpp/Helper/Il2CppHelper.cpp
Normal file
53
Core/il2cpp/Helper/Il2CppHelper.cpp
Normal 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;
|
||||
}
|
||||
9
Core/il2cpp/Helper/Il2CppHelper.h
Normal file
9
Core/il2cpp/Helper/Il2CppHelper.h
Normal 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);
|
||||
};
|
||||
253
Core/il2cpp/Metadata/Il2CppMetadata.cpp
Normal file
253
Core/il2cpp/Metadata/Il2CppMetadata.cpp
Normal 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();
|
||||
}
|
||||
9
Core/il2cpp/Metadata/Il2CppMetadata.h
Normal file
9
Core/il2cpp/Metadata/Il2CppMetadata.h
Normal 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);
|
||||
};
|
||||
66
Core/il2cpp/Offsets/Il2CppOffsets.h
Normal file
66
Core/il2cpp/Offsets/Il2CppOffsets.h
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue