![096c408cc7e31a7662b5c67ee9d6f52d.png](https://i-blog.csdnimg.cn/blog_migrate/cfe2c46daa89b1cb1cd4f757a1a9f465.jpeg)
不得不承认,这一次安全升级确实令我废了一番功夫,之前的AndroidManifest.xml都是明文,防止重打包 只利用了登录时候的APK签名认证。而经过这次升级之后,腾讯SDK加入了反调试机制,几乎很难用ida断点调试APK了,自己本身 加了 两个 程序把断点调试端口给占了。
不过针对这种的,我一般在游戏的启动画面在进入ida调试, 内存中搜索PE头来dump文件。一开始感觉很顺利,我很快就搜到不少PE表头。但是感觉不对,dump出来都是些没加密的,像什么System.dll,UnityEngine.dll...啥的,怎么都找不到Assembly-CSharp的地址,好气啊。
![85ba609b18d8f68113b093feec1020ff.png](https://i-blog.csdnimg.cn/blog_migrate/615da61f191b83114aed39ebbbd8464a.jpeg)
不过我在运行程序的时候,调试着调试着,居然发现PE头前面的一段标识居然从内存中消失了,顿时感觉其中有鬼。
![1dd52e09eab7f34d9ba5043d31d48f42.png](https://i-blog.csdnimg.cn/blog_migrate/d8e250c4b3c69b02308c8e46b429e80c.jpeg)
于是我改搜关键字把MZ改成PE,结果妈的好气啊,C#有个关键字叫TYPE。里面带着PE两个字,我日。搜索这玩意是要爆炸的节奏,改变思路,在游戏刚刚启动的时候。
断点下在mono_type_get_object 的下图位置
![8cd94fdca083238a0a301d0559f10de7.png](https://i-blog.csdnimg.cn/blog_migrate/06d594348503381066ad60e0968bc8aa.jpeg)
计算出来的v34是一个class,通过class获取image地址,一般都会调用到Assembly-CSharp.dll的class,然后这个Assembly拥有几乎所有导入类的引用。只要找到这个reference数组,就可以顺藤摸瓜。找到其余的dll.
数组地址:
![a29af168d40187340c942805ddf55477.png](https://i-blog.csdnimg.cn/blog_migrate/8a7155f8a5aa0f02115629e836e5e028.jpeg)
这是个Assembly地址,可以利用这些地址取出MonoImage,然后MonoImage的 8号位跟12号位就是data的地址跟长度
附带公式,Assembly找Image = 地址+64
查看Image地址的内存情况
做个试验:
取0xC7FD2140 + 64 = 0xC7FD2180
![8eb8ee3d9c9790f28e74536cf5d34d52.png](https://i-blog.csdnimg.cn/blog_migrate/8997631055171e6a0e0056f7d7ea80f2.jpeg)
这个0xC7F5E180就是 Image的地址,查看地址中的值:
![609ee18bc629f47f09ae2ef9a21d0982.png](https://i-blog.csdnimg.cn/blog_migrate/d2638e1a3896aaffcb43999a6cf3da46.jpeg)
8号跟12号位是地址跟长度,验证下data的内存情况:
![714dff7f5fdadf20ca897c1e9ae8223b.png](https://i-blog.csdnimg.cn/blog_migrate/4265dc49af585b2f2f764ef56f95e3db.jpeg)
没错是我们想找的数据结果
编写dump脚本
auto fp, dexAddress;
fp = fopen("C:fist.dll", "wb");
for ( dexAddress=0xC6E00000;dexAddress < 0xC6E00000+0x4A3600;dexAddress++ )
fputc(Byte(dexAddress), fp);
然后把PE表头重新写回去
public static void AddPE() {
string path = EditorUtility.OpenFilePanel("", "", "*");
byte[] PEHeader = {
0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68,
0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F,
0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20,
0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
int len = 0;
byte[] datas = ReadFile(path);
for(int i = 0,imax = datas.Length;i<imax;i++){
if (datas[i] != 'P') {
len++;
}
else {
break;
}
}
byte[] dest = new byte[PEHeader.Length + datas.Length - len];
Array.Copy(PEHeader, dest, PEHeader.Length);
Array.Copy(datas, len - 1, dest, PEHeader.Length - 1, datas.Length - len);
SaveFile(path, dest);
}
加上附录 MonoAssembly、MonoImage、MonoClass取成员变量的移位情况:
MonoImage* monoImage;
MonoClass* monoClass;
MonoAssembly* monoAssembly;
// 参照函数 mono_type_get_object
monoClass->image = *(monoClass + 36)
// 参照函数 mono_image_load_file_for_image
monoImage->assembly = *(monoImage + 664);
// 参照函数 mono_image_open_from_data_with_name
monoImage->araw_data = *(monoImage + 8);
monoImage->araw_data_len = *(monoImage + 12);
// 参照函数 mono_assembly_load_reference
monoImage->references = *(monoImage + 640);
// 参照函数 mono_assembly_open_full
monoAssembly->image = *(monoAssembly + 64);
结束语:总而言之,腾讯的安全SDK是我当前dump花时间最久的了,貌似这个套路也要花相当时间来把c#dll Dump出来, 不是什么IDA小白能搞出来的了....好吧,估计针对我这篇文章