首页
社区
课程
招聘
[原创]IL2CPP 逆向初探
发表于: 2023-8-4 09:52 22579

[原创]IL2CPP 逆向初探

P.Z 活跃值
2
2023-8-4 09:52
22579

il2cpp 将游戏 C# 代码转换为 C++ 代码,然后编译为各平台 Native 代码。

虽然游戏逻辑是以 Native 代码运行, 但依然要实现 C# 某些语言特性(如GC、反射),il2cpp将所有的 C# 中的类名、方法名、属性名、字符串等地址信息记录在 global-metadata.dat 文件。

il2cpp启动时会从这个文件读取所需要的类名、方法名、属性名、字符串等地址信息。

Unity 使用 Mono 方式打包出来的 apk,那么此类逆向我们需要先解压apk,然后利用 IL2CPPDumper 来获取主逻辑代码符号

https://github.com/Perfare/Il2CppDumper

想要利用上述工具,首先是要拿到这两个文件

Android

源\lib\armeabi-v8a\libil2cpp.so

源\assets\bin\Data\Managed\Metadata\global-metadata.dat

PC

<app-name>_Data/il2cpp_data/Metadata/global-metadata.dat

UnityPlayer.dll

随后放入 input 目录

点击该.dat即可

随后我们去 output 目录查看

dump.cs

这个文件会把 C# 的 dll 代码的类、方法、字段列出来

IL2cpp.h

生成的 cpp 头文件,从头文件里可以看到相关的数据结构

script.json

以 json 格式显示类的方法信息

stringliteral.json

以 json 的格式显示所有字符串信息

DummyDll

进入该目录,可以看到很多dll,其中就有 Assembly-CSharp.dll 和我们刚刚的 dump.cs 内容是一致的

当进行 IL2CPP 打包时,选择 CPU 架构可以选择 ARMv7 和 ARM64,所以相对应我们在 apk 解压后所看到的就是 arm64-v8a 和 armeabi-v7a,简单来说就是 64位 和 32位

随后放入相对应的 IDA,再按 ALT + F7 选择该文件

再选该文件

再导入头文件

经过漫长的等待就成功恢复符号了

https://katyscode.wordpress.com/2021/02/23/il2cpp-finding-obfuscated-global-metadata/

然而刚刚那标准的一套用 IL2CPPDumper 的套路并不完全适用,很多厂商都采取了对抗措施,接下来讲解混淆 global-metadata.dat 的思路

当拿到我们的 metadata 文件后,放入查找十六进制的文件,如果开头魔术字依然是 AF 1B B1 FA,那么一般来说是没有被混淆的

那如果不是这个魔术字,一般来说也是被混淆了,而就像平常的逆向一样,程序运行起来肯定是会解密数据然后使用,这个思路同样使用于这,程序运行起来直接搜索该魔术字即可拿到 针对运行时解密的混淆手段

然而也有几种情况是上述方法解决不了的,我们得了解一下 metadata 的加载过程,因为混淆手段就有可能混入其中

而加载的调用链如下

而在我们逆向中,这些都是不带符号的,然而我们可以对着源码来找到相对应的函数(不同版本的源码有一些差别)

il2cpp_init (located in il2cpp-api.cpp, comments elided):

il2cpp::vm::Runtime::Init (located in vm/Runtime.cpp):

il2cpp::vm::MetadataCache::Initialize (located in vm/MetadataCache.cpp, comments elided):

il2cpp::vm::MetadataLoader::LoadMetadataFile (located in vm/MetadataLoader.cpp):

有了这些源码,我们只需要在 IDA 中对照他们识别出相对应的函数,而关键是后两个函数,分别是

il2cpp::vm::MetadataLoader::LoadMetadataFile 该函数将 metadata 的文件名文件映射入内存

il2cpp::vm::MetadataCache::Initialize 该函数将映射文件的指针存储在全局变量中,然后开始从这变量读取数据结构

所然!解混淆或是解密代码一般都在这两个函数里,我们只需要样本代码与源码对比差别即可。

特别指出在引用文中的一个例子,现在看一个 IDA 中的例子

对比下源码不难发现 sub_180261550 就是 il2cpp::vm::MetadataLoader::LoadMetadataFromFile

需要注意的是这个 v0 指针十分重要,因为解混淆或是解密都会调用到这个指针(一般是在加载前解密,而不是在加载后解密,这样会导致未解密的数据残余在内存中影响性能),通常来说应用程序在访问 metadata 前执行解密,或是在 il2cpp: : vm: : MetadataLoader: : LoadMetadataFromFile 之前或之中。

那么以上套路是针对我们能在 il2cpp 里找到 il2cpp_init 的函数,但是如果没有,我们就要继续往上找 UnityPlayer.dll 或者 libunity.so,而这个我们没有办法用源码对照,不过我们可以创建一个 Unity 项目生成 PDB,就可以看到名字和符号那些。

对于这种情况我们主要关心 il2cpp_init.cpp 到底是哪里被引用与调用,那么未被混淆的流程如此

UnityMainImpl 有很多函数调用,不过我们可以通过字符串来寻找

LoadIl2Cpp 也同样可以字符串快速寻找

InitializeIl2CppFromMain

然而有相当不同的变化在不同的版本中,他们的共同特点是对 il2cpp_init 的调用和 IL2CPP Root Domain 与 unused_application_configuration,所以通过这些我们也同样快速找到(如果没有混淆的话)。

IL2CPP逆向,无壳。

于是惯用套路查找 libil2cpp.so 和 global-metadata.dat 来恢复符号,metadata未被混淆,所以可以直接恢复。

接着可以配合 Assembly-CSharp.dll 或 dump.cs 来配合查看函数信息。

尝试 hook IL2CPP 的函数,可是都不行,看别人博客都是模拟器跳这个,我真机跳这个是为什么,hook 未果

那么开始静态审计,既然是音游,通关调试肯定是全部按好即可,于是在 Assembly-CSharp.dll 很容易定位到 notehit notemiss 这些函数

共同点就是算好分数,就直接调用 GameManager__update,而该函数往里查找可以发现调用了 d3mug.so 文件里的 update 函数

那么可以得出结论每次点击到 preciseTime 就会正确 update,而该 update 函数会把值更新到 Server:instance 里

而之后的分数结算的函数 ScoreScene__Start 只是检测了 Server::instance 前缀是否位 D3CTF

那么怎么点才是 preciseTime 呢,而音游落下的方法并不是随即的,而是固定的,所以我们可以找一下加载这个数据的地方

既然有符号,看到可疑的直接看即可,于是发现

往上找,于是发现加载路径

于是利用 AssetStudio 来提取数据

于是我们大概审一下生成地图的函数,可知后面那个就是我们要的 preciseTime

于是总结一下

所以其中一个解密思路就是我们主动调用每次 notehit 会调用的 update 函数,将 preciseTime 数据传入,最后再读取一下解密完的数据即可

于是用下 Frida 即可

Get Flag!

IL2CPP逆向,无壳。

但是这次 metadata 混淆了,可以发现一开始的魔术字的不是原来的样子了,于是两个思路

第一就是运行后内存中直接搜索魔术字

第二就是本文刚开始写的,对比源代码找加载 metadata 的部分既然加密了,在那也许就能找到解密的地方

而该题没法直接在内存中直接搜索到原本的魔术字,于是采用第二种方法,再回忆下调用链

于是直接搜 init 即可找到 il2cpp::vm::Runtime::Init

随后进入该函数后一个个查找对比源码可以发现 sub_4B5564 为 il2cpp::vm::MetadataCache::Initialize

那么看该函数可以很明显发现,global-metadata.dat 字符串变成了其他字符串,但程序运行 sub_4B5518 会自动解密回去

于是对应着源码 sub_513060 就是 il2cpp::vm::MetadataLoader::LoadMetadataFile,返回一个指针完全吻合

那么解密的 metadata 的地方就只可能是 LoadMetadataFile 该函数了,于是将该函数与原函数对比说实话看不太出来到底哪里变了,当然我们也可以一个个点进去看看哪个比较可疑,当然还有个方法找个没被混淆的对比即可,如图

很明显 sub_512FDC 就是不一样的地方(刚刚调试了一下这几个符号全恢复了??是巧合吗)

写出解密脚本

恢复了之后,魔术字还是不对,不过很明显是人为写上去的魔术字了,直接改回原来的魔术字即可

那么恢复了就很简单了,直接定位到关键函数

(upload/attach/202308/930234_UG4KEG5SZJ9W6Y2.png)

发现只是个AES加密,密钥 IV直接交叉引用找赋值给 Check_TypeInfo 即可

于是搓一个解密脚本(cyberChef的AES是真不行啊)

Get Flag!

Reference

https://katyscode.wordpress.com/2021/02/23/il2cpp-finding-obfuscated-global-metadata/

https://cloud.tencent.com/developer/article/2216959

https://blog.shi1011.cn/ctf/2223

https://blog.csdn.net/linxinfa/article/details/116572369

视频版:
https://www.bilibili.com/video/BV1DN41127Wy/?spm_id_from=333.337.search-card.all.click

function frida_Memory(pattern)
{
Java.perform(function ()
{
    console.log("头部标识:" + pattern);
    var addrArray = Process.enumerateRanges("r--");
    for (var i = 0; i < addrArray.length; i++)
    {
        var addr = addrArray[i];
        Memory.scan(addr.base, addr.size, pattern,
        {
            onMatch: function (address, size)
            {
                console.log('搜索到 ' + pattern + " 地址是:" + address.toString());
                console.log(hexdump(address,
                    {
                        offset: 0,
                        length: 64,
                        header: true,
                        ansi: true
                    }
                    ));
                //0x108,0x10C如果不行,换0x100,0x104
                var DefinitionsOffset = parseInt(address, 16) + 0x108;
                var DefinitionsOffset_size = Memory.readInt(ptr(DefinitionsOffset));
 
                var DefinitionsCount = parseInt(address, 16) + 0x10C;
                var DefinitionsCount_size = Memory.readInt(ptr(DefinitionsCount));
 
                //根据两个偏移得出global-metadata大小
                var global_metadata_size = DefinitionsOffset_size + DefinitionsCount_size
                    console.log("大小:", global_metadata_size);
                var file = new File("/data/data/" + get_self_process_name() + "/global-metadata.dat", "wb");
                file.write(Memory.readByteArray(address, global_metadata_size));
                file.flush();
                file.close();
                console.log('导出完毕...');
            },
            onComplete: function ()
            {
                //console.log("搜索完毕")
            }
        }
        );
    }
}
);
}
setImmediate(frida_Memory("AF 1B B1 FA")); //global-metadata.dat头部特征
function frida_Memory(pattern)
{
Java.perform(function ()
{
    console.log("头部标识:" + pattern);
    var addrArray = Process.enumerateRanges("r--");
    for (var i = 0; i < addrArray.length; i++)
    {
        var addr = addrArray[i];
        Memory.scan(addr.base, addr.size, pattern,
        {
            onMatch: function (address, size)
            {
                console.log('搜索到 ' + pattern + " 地址是:" + address.toString());
                console.log(hexdump(address,
                    {
                        offset: 0,
                        length: 64,
                        header: true,
                        ansi: true
                    }
                    ));
                //0x108,0x10C如果不行,换0x100,0x104
                var DefinitionsOffset = parseInt(address, 16) + 0x108;
                var DefinitionsOffset_size = Memory.readInt(ptr(DefinitionsOffset));
 
                var DefinitionsCount = parseInt(address, 16) + 0x10C;
                var DefinitionsCount_size = Memory.readInt(ptr(DefinitionsCount));
 
                //根据两个偏移得出global-metadata大小
                var global_metadata_size = DefinitionsOffset_size + DefinitionsCount_size
                    console.log("大小:", global_metadata_size);
                var file = new File("/data/data/" + get_self_process_name() + "/global-metadata.dat", "wb");
                file.write(Memory.readByteArray(address, global_metadata_size));
                file.flush();
                file.close();
                console.log('导出完毕...');
            },
            onComplete: function ()
            {
                //console.log("搜索完毕")
            }
        }
        );
    }
}
);
}
setImmediate(frida_Memory("AF 1B B1 FA")); //global-metadata.dat头部特征
il2cpp_init
  -> il2cpp::vm::Runtime::Init
    -> il2cpp::vm::MetadataCache::Initialize
      -> il2cpp::vm::MetadataLoader::LoadMetadataFile
il2cpp_init
  -> il2cpp::vm::Runtime::Init
    -> il2cpp::vm::MetadataCache::Initialize
      -> il2cpp::vm::MetadataLoader::LoadMetadataFile
int il2cpp_init(const char* domain_name)
{
    setlocale(LC_ALL, "");
    return Runtime::Init(domain_name, "v4.0.30319");
}
int il2cpp_init(const char* domain_name)
{
    setlocale(LC_ALL, "");
    return Runtime::Init(domain_name, "v4.0.30319");
}
bool Runtime::Init(const char* filename, const char *runtime_version)
{
    SanityChecks();
  
    os::Initialize();
    os::Locale::Initialize();
    MetadataAllocInitialize();
  
    s_FrameworkVersion = framework_version_for(runtime_version);
  
    os::Image::Initialize();
    os::Thread::Init();
    il2cpp::utils::RegisterRuntimeInitializeAndCleanup::ExecuteInitializations();
  
    if (!MetadataCache::Initialize())
        return false;
    Assembly::Initialize();
    gc::GarbageCollector::Initialize();
  
    Thread::Initialize();
    Reflection::Initialize();
  
    register_allocator(il2cpp::utils::Memory::Malloc);
  
    memset(&il2cpp_defaults, 0, sizeof(Il2CppDefaults));
  
    const Il2CppAssembly* assembly = Assembly::Load("mscorlib.dll");
  
    il2cpp_defaults.corlib = Assembly::GetImage(assembly);
    DEFAULTS_INIT(object_class, "System", "Object");
    DEFAULTS_INIT(void_class, "System", "Void");
    DEFAULTS_INIT_TYPE(boolean_class, "System", "Boolean", bool);
    DEFAULTS_INIT_TYPE(byte_class, "System", "Byte", uint8_t);
    DEFAULTS_INIT_TYPE(sbyte_class, "System", "SByte", int8_t);
    DEFAULTS_INIT_TYPE(int16_class, "System", "Int16", int16_t);
    DEFAULTS_INIT_TYPE(uint16_class, "System", "UInt16", uint16_t);
    DEFAULTS_INIT_TYPE(int32_class, "System", "Int32", int32_t);
    DEFAULTS_INIT_TYPE(uint32_class, "System", "UInt32", uint32_t);
    DEFAULTS_INIT(uint_class, "System", "UIntPtr");
    DEFAULTS_INIT_TYPE(int_class, "System", "IntPtr", intptr_t);
    DEFAULTS_INIT_TYPE(int64_class, "System", "Int64", int64_t);
    DEFAULTS_INIT_TYPE(uint64_class, "System", "UInt64", uint64_t);
    DEFAULTS_INIT_TYPE(single_class, "System", "Single", float);
    DEFAULTS_INIT_TYPE(double_class, "System", "Double", double);
    DEFAULTS_INIT_TYPE(char_class, "System", "Char", Il2CppChar);
    DEFAULTS_INIT(string_class, "System", "String");
    // ...
bool Runtime::Init(const char* filename, const char *runtime_version)
{
    SanityChecks();
  
    os::Initialize();
    os::Locale::Initialize();
    MetadataAllocInitialize();
  
    s_FrameworkVersion = framework_version_for(runtime_version);
  
    os::Image::Initialize();
    os::Thread::Init();
    il2cpp::utils::RegisterRuntimeInitializeAndCleanup::ExecuteInitializations();
  
    if (!MetadataCache::Initialize())
        return false;
    Assembly::Initialize();
    gc::GarbageCollector::Initialize();
  
    Thread::Initialize();
    Reflection::Initialize();
  
    register_allocator(il2cpp::utils::Memory::Malloc);
  
    memset(&il2cpp_defaults, 0, sizeof(Il2CppDefaults));
  
    const Il2CppAssembly* assembly = Assembly::Load("mscorlib.dll");
  
    il2cpp_defaults.corlib = Assembly::GetImage(assembly);
    DEFAULTS_INIT(object_class, "System", "Object");
    DEFAULTS_INIT(void_class, "System", "Void");
    DEFAULTS_INIT_TYPE(boolean_class, "System", "Boolean", bool);
    DEFAULTS_INIT_TYPE(byte_class, "System", "Byte", uint8_t);
    DEFAULTS_INIT_TYPE(sbyte_class, "System", "SByte", int8_t);
    DEFAULTS_INIT_TYPE(int16_class, "System", "Int16", int16_t);
    DEFAULTS_INIT_TYPE(uint16_class, "System", "UInt16", uint16_t);
    DEFAULTS_INIT_TYPE(int32_class, "System", "Int32", int32_t);
    DEFAULTS_INIT_TYPE(uint32_class, "System", "UInt32", uint32_t);
    DEFAULTS_INIT(uint_class, "System", "UIntPtr");
    DEFAULTS_INIT_TYPE(int_class, "System", "IntPtr", intptr_t);
    DEFAULTS_INIT_TYPE(int64_class, "System", "Int64", int64_t);
    DEFAULTS_INIT_TYPE(uint64_class, "System", "UInt64", uint64_t);
    DEFAULTS_INIT_TYPE(single_class, "System", "Single", float);
    DEFAULTS_INIT_TYPE(double_class, "System", "Double", double);
    DEFAULTS_INIT_TYPE(char_class, "System", "Char", Il2CppChar);
    DEFAULTS_INIT(string_class, "System", "String");
    // ...
bool il2cpp::vm::MetadataCache::Initialize()
{
    s_GlobalMetadata = vm::MetadataLoader::LoadMetadataFile("global-metadata.dat");
    if (!s_GlobalMetadata)
        return false;
  
    s_GlobalMetadataHeader = (const Il2CppGlobalMetadataHeader*)s_GlobalMetadata;
    IL2CPP_ASSERT(s_GlobalMetadataHeader->sanity == 0xFAB11BAF);
    IL2CPP_ASSERT(s_GlobalMetadataHeader->version == 24);
  
    s_TypeInfoTable = (Il2CppClass**)IL2CPP_CALLOC(s_Il2CppMetadataRegistration->typesCount, sizeof(Il2CppClass*));
    s_TypeInfoDefinitionTable = (Il2CppClass**)IL2CPP_CALLOC(s_GlobalMetadataHeader->typeDefinitionsCount / sizeof(Il2CppTypeDefinition), sizeof(Il2CppClass*));
    s_MethodInfoDefinitionTable = (const MethodInfo**)IL2CPP_CALLOC(s_GlobalMetadataHeader->methodsCount / sizeof(Il2CppMethodDefinition), sizeof(MethodInfo*));
    s_GenericMethodTable = (const Il2CppGenericMethod**)IL2CPP_CALLOC(s_Il2CppMetadataRegistration->methodSpecsCount, sizeof(Il2CppGenericMethod*));
    s_ImagesCount = s_GlobalMetadataHeader->imagesCount / sizeof(Il2CppImageDefinition);
    s_ImagesTable = (Il2CppImage*)IL2CPP_CALLOC(s_ImagesCount, sizeof(Il2CppImage));
    s_AssembliesCount = s_GlobalMetadataHeader->assembliesCount / sizeof(Il2CppAssemblyDefinition);
    s_AssembliesTable = (Il2CppAssembly*)IL2CPP_CALLOC(s_AssembliesCount, sizeof(Il2CppAssembly));
    // ...
bool il2cpp::vm::MetadataCache::Initialize()
{
    s_GlobalMetadata = vm::MetadataLoader::LoadMetadataFile("global-metadata.dat");
    if (!s_GlobalMetadata)
        return false;
  
    s_GlobalMetadataHeader = (const Il2CppGlobalMetadataHeader*)s_GlobalMetadata;
    IL2CPP_ASSERT(s_GlobalMetadataHeader->sanity == 0xFAB11BAF);
    IL2CPP_ASSERT(s_GlobalMetadataHeader->version == 24);
  
    s_TypeInfoTable = (Il2CppClass**)IL2CPP_CALLOC(s_Il2CppMetadataRegistration->typesCount, sizeof(Il2CppClass*));
    s_TypeInfoDefinitionTable = (Il2CppClass**)IL2CPP_CALLOC(s_GlobalMetadataHeader->typeDefinitionsCount / sizeof(Il2CppTypeDefinition), sizeof(Il2CppClass*));
    s_MethodInfoDefinitionTable = (const MethodInfo**)IL2CPP_CALLOC(s_GlobalMetadataHeader->methodsCount / sizeof(Il2CppMethodDefinition), sizeof(MethodInfo*));
    s_GenericMethodTable = (const Il2CppGenericMethod**)IL2CPP_CALLOC(s_Il2CppMetadataRegistration->methodSpecsCount, sizeof(Il2CppGenericMethod*));
    s_ImagesCount = s_GlobalMetadataHeader->imagesCount / sizeof(Il2CppImageDefinition);
    s_ImagesTable = (Il2CppImage*)IL2CPP_CALLOC(s_ImagesCount, sizeof(Il2CppImage));
    s_AssembliesCount = s_GlobalMetadataHeader->assembliesCount / sizeof(Il2CppAssemblyDefinition);
    s_AssembliesTable = (Il2CppAssembly*)IL2CPP_CALLOC(s_AssembliesCount, sizeof(Il2CppAssembly));
    // ...
void* il2cpp::vm::MetadataLoader::LoadMetadataFile(const char* fileName)
{
    std::string resourcesDirectory = utils::PathUtils::Combine(utils::Runtime::GetDataDir(), utils::StringView<char>("Metadata"));
  
    std::string resourceFilePath = utils::PathUtils::Combine(resourcesDirectory, utils::StringView<char>(fileName, strlen(fileName)));
  
    int error = 0;
    os::FileHandle* handle = os::File::Open(resourceFilePath, kFileModeOpen, kFileAccessRead, kFileShareRead, kFileOptionsNone, &error);
    if (error != 0)
    {
        utils::Logging::Write("ERROR: Could not open %s", resourceFilePath.c_str());
        return NULL;
    }
  
    void* fileBuffer = utils::MemoryMappedFile::Map(handle);
  
    os::File::Close(handle, &error);
    if (error != 0)
    {
        utils::MemoryMappedFile::Unmap(fileBuffer);
        fileBuffer = NULL;
        return NULL;
    }
  
    return fileBuffer;
}
void* il2cpp::vm::MetadataLoader::LoadMetadataFile(const char* fileName)
{
    std::string resourcesDirectory = utils::PathUtils::Combine(utils::Runtime::GetDataDir(), utils::StringView<char>("Metadata"));
  
    std::string resourceFilePath = utils::PathUtils::Combine(resourcesDirectory, utils::StringView<char>(fileName, strlen(fileName)));
  
    int error = 0;
    os::FileHandle* handle = os::File::Open(resourceFilePath, kFileModeOpen, kFileAccessRead, kFileShareRead, kFileOptionsNone, &error);
    if (error != 0)
    {
        utils::Logging::Write("ERROR: Could not open %s", resourceFilePath.c_str());
        return NULL;
    }
  
    void* fileBuffer = utils::MemoryMappedFile::Map(handle);
  
    os::File::Close(handle, &error);
    if (error != 0)
    {
        utils::MemoryMappedFile::Unmap(fileBuffer);
        fileBuffer = NULL;
        return NULL;
    }
  
    return fileBuffer;
}
char il2cpp::vm::MetadataCache::Initialize()
{
  v0 = sub_180261550("global-metadata.dat");
  *&xmmword_182B7C2D8 = v0;
  if ( v0 )
  {
    *(&xmmword_182B7C2D8 + 1) = v0;
    qword_182B7B948 = j_j__calloc_base(*(qword_182B7C2C0 + 48), 8i64);
    qword_182B7B950 = j_j__calloc_base(*(*(&xmmword_182B7C2D8 + 1) + 164i64) / 0x5Cui64, 8i64);
    qword_182B7B958 = j_j__calloc_base(*(*(&xmmword_182B7C2D8 + 1) + 52i64) >> 5, 8i64);
    qword_182B7B968 = j_j__calloc_base(*(qword_182B7C2C0 + 64), 8i64);
    dword_182B7B970 = *(*(&xmmword_182B7C2D8 + 1) + 172i64) / 0x28ui64;
    qword_182B7B978 = j_j__calloc_base(dword_182B7B970, 80i64);
    dword_182B7B980 = *(*(&xmmword_182B7C2D8 + 1) + 180i64) / 0x44ui64;
    qword_182B7B988 = j_j__calloc_base(dword_182B7B980, 96i64);
    v1 = *(&xmmword_182B7C2D8 + 1);
char il2cpp::vm::MetadataCache::Initialize()
{
  v0 = sub_180261550("global-metadata.dat");
  *&xmmword_182B7C2D8 = v0;
  if ( v0 )
  {
    *(&xmmword_182B7C2D8 + 1) = v0;
    qword_182B7B948 = j_j__calloc_base(*(qword_182B7C2C0 + 48), 8i64);
    qword_182B7B950 = j_j__calloc_base(*(*(&xmmword_182B7C2D8 + 1) + 164i64) / 0x5Cui64, 8i64);
    qword_182B7B958 = j_j__calloc_base(*(*(&xmmword_182B7C2D8 + 1) + 52i64) >> 5, 8i64);
    qword_182B7B968 = j_j__calloc_base(*(qword_182B7C2C0 + 64), 8i64);
    dword_182B7B970 = *(*(&xmmword_182B7C2D8 + 1) + 172i64) / 0x28ui64;
    qword_182B7B978 = j_j__calloc_base(dword_182B7B970, 80i64);
    dword_182B7B980 = *(*(&xmmword_182B7C2D8 + 1) + 180i64) / 0x44ui64;
    qword_182B7B988 = j_j__calloc_base(dword_182B7B980, 96i64);
    v1 = *(&xmmword_182B7C2D8 + 1);
  winutils::DisplayErrorMessagesAndQuit("Data folder not found");
}
DetectIL2CPPVersion();
v78.m_data = 0i64;
v78.m_size = 0i64;
v78.m_label.identifier = 68;
v78.m_internal[0] = 0;
core::StringStorageDefault<char>::assign(&v78, "GameAssembly.dll", 0x10ui64);
v27 = !LoadIl2Cpp(&v78);
if ( v78.m_data && v78.m_capacity > 0 )
  operator delete(v78.m_data, v78.m_label);
if ( v27 )
  winutils::DisplayErrorMessagesAndQuit("Failed to load il2cpp");
v78.m_data = 0i64;
v78.m_size = 0i64;
v78.m_label.identifier = 68;
v78.m_internal[0] = 0;
core::StringStorageDefault<char>::assign(&v78, "il2cpp_data", 0xBui64);
  winutils::DisplayErrorMessagesAndQuit("Data folder not found");
}
DetectIL2CPPVersion();
v78.m_data = 0i64;
v78.m_size = 0i64;
v78.m_label.identifier = 68;
v78.m_internal[0] = 0;
core::StringStorageDefault<char>::assign(&v78, "GameAssembly.dll", 0x10ui64);
v27 = !LoadIl2Cpp(&v78);
if ( v78.m_data && v78.m_capacity > 0 )
  operator delete(v78.m_data, v78.m_label);
if ( v27 )
  winutils::DisplayErrorMessagesAndQuit("Failed to load il2cpp");
v78.m_data = 0i64;
v78.m_size = 0i64;
v78.m_label.identifier = 68;
v78.m_internal[0] = 0;
core::StringStorageDefault<char>::assign(&v78, "il2cpp_data", 0xBui64);
v2 = 1;
 il2cpp_init = LookupSymbol(v1, "il2cpp_init", kSymbolRequired);
 if ( !il2cpp_init )
 {
   v2 = 0;
   printf_console("il2cpp: function il2cpp_init not found\n");
 }
 il2cpp_init_utf16 = LookupSymbol(gIl2CppModule, "il2cpp_init_utf16", kSymbolRequired);
 if ( !il2cpp_init_utf16 )
 {
   v2 = 0;
   printf_console("il2cpp: function il2cpp_init_utf16 not found\n");
 }
 il2cpp_shutdown = LookupSymbol(gIl2CppModule, "il2cpp_shutdown", kSymbolRequired);
 if ( !il2cpp_shutdown )
 {
   v2 = 0;
   printf_console("il2cpp: function il2cpp_shutdown not found\n");
 }
v2 = 1;
 il2cpp_init = LookupSymbol(v1, "il2cpp_init", kSymbolRequired);
 if ( !il2cpp_init )
 {
   v2 = 0;
   printf_console("il2cpp: function il2cpp_init not found\n");
 }
 il2cpp_init_utf16 = LookupSymbol(gIl2CppModule, "il2cpp_init_utf16", kSymbolRequired);
 if ( !il2cpp_init_utf16 )
 {
   v2 = 0;
   printf_console("il2cpp: function il2cpp_init_utf16 not found\n");
 }
 il2cpp_shutdown = LookupSymbol(gIl2CppModule, "il2cpp_shutdown", kSymbolRequired);
 if ( !il2cpp_shutdown )
 {
   v2 = 0;
   printf_console("il2cpp: function il2cpp_shutdown not found\n");
 }
char __fastcall InitializeIl2CppFromMain(const core::basic_string<char,core::StringStorageDefault<char> > *monoConfigPath, const core::basic_string<char,core::StringStorageDefault<char> > *dataPath, int argc, const char **argv)
{
  v4 = argv;
  v5 = argc;
  v6 = dataPath;
  v7 = monoConfigPath;
  RegisterAllInternalCalls();
  il2cpp_runtime_unhandled_exception_policy_set(IL2CPP_UNHANDLED_POLICY_LEGACY);
  il2cpp_set_commandline_arguments(v5, v4, 0i64);
  v8 = v7->m_data;
  if ( !v7->m_data )
    v8 = &v7->8;
  il2cpp_set_config_dir(v8);
  v9 = v6->m_data;
  if ( !v6->m_data )
    v9 = &v6->8;
  il2cpp_set_data_dir(v9);
  v10 = GetMonoDebuggerAgentOptions(&result, 0);
  v11 = v10->m_data;
  if ( !v10->m_data )
    v11 = &v10->8;
  il2cpp_debugger_set_agent_options(v11);
  if ( result.m_data && result.m_capacity )
    operator delete(result.m_data, result.m_label);
  il2cpp_init("IL2CPP Root Domain");
  il2cpp_set_config("unused_application_configuration");
  profiling::ScriptingProfiler::Initialize();
  return 1;
}
char __fastcall InitializeIl2CppFromMain(const core::basic_string<char,core::StringStorageDefault<char> > *monoConfigPath, const core::basic_string<char,core::StringStorageDefault<char> > *dataPath, int argc, const char **argv)
{
  v4 = argv;
  v5 = argc;
  v6 = dataPath;
  v7 = monoConfigPath;
  RegisterAllInternalCalls();
  il2cpp_runtime_unhandled_exception_policy_set(IL2CPP_UNHANDLED_POLICY_LEGACY);
  il2cpp_set_commandline_arguments(v5, v4, 0i64);
  v8 = v7->m_data;
  if ( !v7->m_data )
    v8 = &v7->8;
  il2cpp_set_config_dir(v8);
  v9 = v6->m_data;
  if ( !v6->m_data )
    v9 = &v6->8;
  il2cpp_set_data_dir(v9);
  v10 = GetMonoDebuggerAgentOptions(&result, 0);
  v11 = v10->m_data;
  if ( !v10->m_data )
    v11 = &v10->8;
  il2cpp_debugger_set_agent_options(v11);
  if ( result.m_data && result.m_capacity )
    operator delete(result.m_data, result.m_label);
  il2cpp_init("IL2CPP Root Domain");
  il2cpp_set_config("unused_application_configuration");
  profiling::ScriptingProfiler::Initialize();
  return 1;
}
void __fastcall GameManager__NoteHit(GameManager_o *this, float preciseTime, int32_t level, const MethodInfo *method)
{
  struct TMPro_TMP_Text_o *PerfectText; // x19
  System_String_o *v6; // x0
  System_String_o *v7; // x0
  const MethodInfo *v8; // x1
  uint32_t v9; // w0
  int v10; // [xsp+Ch] [xbp-14h] BYREF
 
  v10 = 0;
  if ( level >= 1 )
  {
    PerfectText = this->fields.PerfectText;
    if ( PerfectText )
      goto LABEL_3;
LABEL_8:
    sub_560668();
  }
  PerfectText = this->fields.GoodText;
  if ( !PerfectText )
    goto LABEL_8;
LABEL_3:
  v6 = (PerfectText->klass->vtable._65_get_text.method)(
         PerfectText,
         PerfectText->klass->vtable._66_set_text.methodPtr,
         method);
  v10 = System_Int32__Parse(v6, 0LL) + 1;
  v7 = System_Int32__ToString(&v10, 0LL);
  (PerfectText->klass->vtable._66_set_text.method)(
    PerfectText,
    v7,
    PerfectText->klass->vtable._67_get_fontSharedMaterial.methodPtr);
  if ( (preciseTime * 1000.0) >= 0.0 )
    v9 = (preciseTime * 1000.0);
  else
    v9 = (preciseTime * 1000.0);
  GameManager__update(v9, v8);
}
void __fastcall GameManager__NoteHit(GameManager_o *this, float preciseTime, int32_t level, const MethodInfo *method)
{
  struct TMPro_TMP_Text_o *PerfectText; // x19
  System_String_o *v6; // x0
  System_String_o *v7; // x0
  const MethodInfo *v8; // x1
  uint32_t v9; // w0
  int v10; // [xsp+Ch] [xbp-14h] BYREF
 
  v10 = 0;

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2023-8-4 10:10 被P.Z编辑 ,原因:
收藏
免费 10
支持
分享
最新回复 (13)
雪    币: 483
活跃值: (1010)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
mark
2023-8-30 17:49
0
雪    币: 3751
活跃值: (3156)
能力值: ( LV8,RANK:147 )
在线值:
发帖
回帖
粉丝
3
mark
2023-9-5 09:58
0
雪    币: 3573
活跃值: (31026)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
mark
2023-9-5 10:02
1
雪    币: 0
活跃值: (104)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
很多时候il2cpp的结构体的字段顺序都被随机打乱了,像MethodInfo的methodPointer和name字段的都会被加密
2023-9-7 09:02
0
雪    币: 129
活跃值: (4655)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
eeeeeez 很多时候il2cpp的结构体的字段顺序都被随机打乱了,像MethodInfo的methodPointer和name字段的都会被加密
是的,我遇到过一个读取meta后跟原来的没区别,好像自己解析了这些结构
2023-9-7 09:58
0
雪    币: 102
活跃值: (2155)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
7
mark
2023-9-7 11:02
0
雪    币: 1427
活跃值: (1598)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
遇到过抽函数的, 也遇到过魔改metadata结构的, 乆!
2023-9-7 11:45
2
雪    币: 140
活跃值: (451)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
2023-9-8 00:13
0
雪    币: 120
活跃值: (1603)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
mark
2023-11-23 11:32
0
雪    币: 189
活跃值: (172)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
mark
2023-12-9 01:00
0
雪    币: 199
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
学习了
2023-12-27 11:06
0
雪    币: 95
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
pc怎么dump il2cpp?
2023-12-27 18:02
0
雪    币: 374
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
14
mark
2024-6-12 13:12
0
游客
登录 | 注册 方可回帖
返回
//