论坛首页 安全编程开发区 阅读主题

[原创]纯静态解决遇到的各类global-metadata加密问题

254 浏览 20 回复
#1 楼主 2026-06-01 21:09:11
在通过Il2cppdumper工具尝试dump unity游戏的sdk时,经常会碰到一些加密的global-metadata.dat,导致无法成功dump。搜索网上的文章或工具个人感觉最好用两种分别是。1.动态dump解密后的metadata。2.利用il2cpp_api(未混淆)动态dump CS文件。本文总共4个例子,有能用以上办法解决的,也有不能用以上方法解决的,全都是纯静态解决,按照从易到难的顺序。既然要解密,肯定要先了解加密的位置在哪里。通过github能下载到2020年的unity源码,找到MetadataCache.cpp中的il2cpp::vm::MetadataCache::Initialize函数,而这里也是大多数metadata解密的位置。因考虑篇幅问题,一部分的代码都只会截取一部分。观看源码可以知道,我们可以利用global-metadata.dat或Metadata字符串去索引到具体的函数实现。而大多数的加密操作一般都在这两个函数。让我们正式开始第一个案例吧!先通过Metadata字符串索引到LoadMetadataFile函数。如果是十分熟悉这两个函数的师傅,一眼就可以知道这个函数里没有进行解密操作,接着索引到Initialize函数if ( v4 )后的伪代码已经是将metadata的结构头和一些值填入到内存中了,按理说应该在sub_35FC404读取metadata后进行解密操作。既然没找到,那就查看一下metadata的数据。
如果有观察了解过metadata结构头,或是对数字比较敏感的师傅,一眼就能看出来,这个metadata的加密十分规律。
拿一个正常的结构头,会更加直观,因为metadata存储的多是各个参数的偏移和数量,因此很少有数据大于0xffffff(小端序)因此通过观察03 07 0b 0f等偏移,可以观察出一定的加减规律。再细致可以观察出这个规律是呈16一轮,这是我们在观察0x100这个偏移,这里存储的是关于windows相关的数据,apk是用不到的,因此多是不变的。因此我们只需要提取0x100的十六个字节,并且对偏移0x8的数据异或0x1,即可得到一个异或表。随便找一个ai写一个脚本即可
可以看到我们得到了一个很干净的metadata,只需要把头部修复一下即可。第二个案例,我在so中无法搜索到metadata相关的字符串,查看assets资源文件,发现文件路径名和文件名都被修改成无意义命名。但好在LoadMetadataFile函数中还有一个ERROR: Could not open %s 字符串找到函数后,发现路径名字被改为gloxinia,再向上索引,发现解密函数操作我们再向上索引,成功找到我们的Initialize函数,我的metadata名字叫做feast_plaint_knight拉进010查看,这个metadata初看大概也是一个循环异或的规律。
但老是写解密脚本显然不是我这种懒狗的思路。这里当然要使用出我们的顶级解密工具Unidbg!动态dump的原理除了识别metadata特征就是hook读取metadata返回的指针。通过把unidbg模拟执行,不用传入任何参数,只需要配置一下globla-metadata.dat的路径读取问题即可。来到第三个案例,查看metadata
加快节奏,直接来到so中观察加密函数可以看到函数把global-metadata.dat字符串解密后,读取再解密的过程。其实就是加密了结构头和两个metadata的区段,stringLiteralDataOffset和stringOffset。通过unidbg,这次我们断在v24 = *(v10 + 100);解密完后将两个区段dump出来,这里就不详细讲诉了,一样的操作我们来观察dump下来的结构头。
惊奇的发现,不仅顺序被打乱,还被塞入很多无用数据。读过源码可以知道,这里填入的有s_GlobalMetadataHeader的一些结构头数据,但是观察偏移0xf8 0xc0明显是不对的,它映照的是打乱顺序后的结构头。因此我们无法通过解密后的metadata进行sdkdump,还需要修复s_GlobalMetadataHeader。哪如何快速的修复我们的s_GlobalMetadataHeader呢,我想到的第一个方法是通过拿一份同版本的未魔改的so文件,再索引进行比较。
我们通过010模板拿到我们的结构头
在ida中对s_GlobalMetadataHeader进行填入
这里我未详细修改,将后面的字符串删除即可。但是我们身为一个懒狗,将近60个数据,一个个去寻找,并且可能还有遗漏,显然不是我们的风格。
我们拿案例1解密后的metadata来观看,可以发现除了头部特征字节和末尾没用的字节,其余字节都是紧凑相连的。例如stringLiteralOffset+stringLiteralCount==stringLiteralDataOffset0x100+0x39458==0x39558我们只需要开头stringLiteralOffset和stringLiteralCount的数据就可以推算出全部的数据。因为我们拥有所有正确的结构头,通过遍历stringLiteralDataOffset+打乱结构头数组[i]==打乱结构头数组[j]以此类推。最后这个例子还有一个小坑在读取后还需要加0x1e4才是真正的数值修复后:
直接查看so最后一个例子就是加强版的3号例子,加密了7个区块,且观察这两行代码,dest指向的就是metadata指针。3号例子是统一的0x1e4,而这个例子,是不同的加减数,让我们无法利用上面那个方法计算。但是通过观察发现,这个加减数大多都在0x50以内。因此我们可以添加一个区间值stringLiteralOffset+stringLiteralCount ±0x50 ≈≈stringLiteralDataOffset但这样有一个隐患,可能出现两个或多个值,这里我使用的方法是了解每个结构体中各个值的意义,这样把每个值都添加一边跳转过去查看。修复后:
如果写得不好,请轻喷,代码基本让ai都能编写出来,就没贴出来了。如果师傅们有更好的方法请多多分享让我学习一下!!!bool il2cpp::vm::MetadataCache::Initialize()

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-289395.htm
#2 2026-06-01 21:09:11
大佬们 这个游戏是bao ke meng da ji jie是tprt加固然后我去hook这俩地址 用的是大佬的unidbg代码下方是我的代码

打印结果是

然后我查看了这个地址的值为啥会这样我很蒙 看不懂
求帮助 我想知道具体是怎么打印这个大佬的0x我是改过的 发现0x它报错 希望大佬能讲讲
球球大佬了
#3 2026-06-01 21:09:11
感谢分享
#4 2026-06-01 21:09:11
一直没有解决的问题。看看这里能不能学到。
#5 2026-06-01 21:09:11
感谢大佬分享
#6 2026-06-01 21:09:11
感谢大佬分享
#7 2026-06-01 21:09:11
mb_vhwdzyqo


大佬们 这个游戏是bao ke meng da ji jie是tprt加固然后我去hook这俩地址 用的是大佬的unidbg代码下方是我的代码打印结果是然后我查看了这个地址的值为啥会这样我很蒙 看不懂 ...

用frida + 物理机去dump,直接就是解密后的文件
#8 2026-06-01 21:09:11
学习
#9 2026-06-01 21:09:11
哥 你还在吗球球了
#10 2026-06-01 21:09:11
感谢分享
#11 2026-06-01 21:09:11
public boolean onHit(Emulator<?> emulator, long address) {
                    // 读取后的地址添加一个断点,dump出来即可,可让ai直接写
                    return true;
          });哥 这里的代码能发过来吗
#12 2026-06-01 21:09:11
不错
#13 2026-06-01 21:09:11
哥 我真的好想学 你看到了能发下样本的名字吗
#14 2026-06-01 21:09:11
哥 四个样本分别是啥 我想动手试试
#15 2026-06-01 21:09:11
感谢分享
#16 2026-06-01 21:09:11
tql
‹ 上一页 1 2 下一页 ›

请登录后参与讨论

立即登录 注册账号