dumpcs-dumper/Core/il2cpp/Metadata/Il2CppMetadata.cpp
2026-01-05 23:50:53 +03:00

253 lines
No EOL
7.6 KiB
C++

#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();
}