发布于2021-04-17 18:37 阅读(1973) 评论(0) 点赞(5) 收藏(2)
libmain.so这个是Unity启动的时候最开始加载的,先加载了libmain.so,才能继续加载其他相关的so
libmain.so会加载两个so,一个是libmono.so,另一个是libunity.so
libunity.so则是unity底层写的cpp
libmono.so 相当于负责加载解析dll文件运行,运行时主要工作框架如下
mini/main.c: main()
mono_main_with_options()
mono_main() --mini/driver.c
mini_init() --mini/mini.c
mono_assembly_open() --metadata/assembly.c
--mono_assembly_load_from_full() ------对文件名进行判断 是否已 file://开头
----mono_assembly_is_in_gac --判断是否在gac当中
----mono_assembly_open_from_bundle()
------mono_image_open_from_data_with_name() --image.c
--------do_mono_image_load()
main_thread_handler() // assembly(也就是bytecode)的编译执行
首先判断文件名是否为file://开头,之后依据文件名称判断是否在gac之中,最后打开bundle,然后在 mono 虚拟机上加载并且执行
其中较为重要的函数为mono_image_open_from_data_with_name,其中的第一个参数,包含了加载文件的二进制码。
一般获取Unity游戏源码,需要Hook mono_image_open_from_data_with_name获取第一个参数即可dump出加载的二进制码
unity3D游戏中Assembly-CSharp.dll 中存放着游戏的核心代码,看了一下发现被加密
由于加密无法分析C#代码,需要解密或者dump出源码。
Assembly-CSharp.dll是由 libmono.so 运行时读取然后在 mono 虚拟机上执行,关键函数为mono_image_open_from_data_with_name
因此IDA反编译libmono发现so被加密,用gg修改器dump出libmono.so的内存,比较原先机器码,发现为xor 0xd9加密
阅读源码发现字符串data-%p
依据关键字搜索dump出的内存,仔细查看反编译出的函数代码,并没有找到加密的地方。阅读源码向上溯源
mono_assembly_load_from_full->mono_assembly_open_from_bundle
在mono_assembly_open_from_bundle之中发现了奇怪的一处,0x194bf8应该是真正的mono_image_open_from_data_with_name
此处本应该指向mono_image_open_from_data_with_name,但是194bf8处的地址明显被Hook
此处为inline_hook的shellcode
调用一个导出函数g_tprt_pfn_array+0x68
可以大概得知此处是调用Assembly-csharp解密的地方。
借此发现Hook点还有很多都是和g_tprt_pfn_array导出函数有关,就不细看了
libmain.so这个是Unity启动的时候最开始加载的,先加载了libmain.so,才能继续加载其他相关的so
libmain.so会加载两个so,一个是libmono.so,另一个是libunity.so
看了一下libmain.so中并没有对libmono的.so进行解密就直接加载了,有点奇怪,因为libmono.so是被加密的。
去HOOK dlopen看了一下在libmain之前加载的so,发现第一个加载的就是libtprt.so
看到libtprt.so 网上查了一下,发现其是用来保护的
libtprt.so所有字符串都被加密了,函数偏移为0x8638,写个Frida来调用Hook该函数
该脚本用来Hook解密字符串函数,得到参数,返回结果,寄存器LR的值,方便定位关键点
这里需要在启动前注入,游戏启动时,frida无法注入。
因为是第一个加载的.so,所以需要先Hook dlopen函数,来获取Hook时机。
frida -U -f com.tencent.tmgp.cf --no-pause -l 2.js执行如下关键点
Java.perform(function(){
var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");
console.log(android_dlopen_ext);
if(android_dlopen_ext != null){
Interceptor.attach(android_dlopen_ext,{
onEnter: function(args){
var soName = args[0].readCString();
if(soName.indexOf("libtprt.so") != -1){
this.hook = true;
}
},
onLeave: function(retval){
if(this.hook) {
dlopentodo();
};
}
});
}
function dlopentodo(){
var soAddr = Module.findBaseAddress("libtprt.so");
var ptrTencentEncrypt_addr = soAddr.add(0x8639);
var file = new File("/sdcard/encrypt.txt","a+");
file.write("soaddr is :"+soAddr.toString()+"\n");
Interceptor.attach(ptrTencentEncrypt_addr,{
onEnter: function(args){
file.write("r0 is "+(this.context.r0).toString()+" ");
file.write("LR is "+(this.context.lr-soAddr).toString(16)+" ");
},
onLeave: function(retval){
file.write(retval.readCString()+"\n");
}
});
}
})
定位到几处解密出字符串Assembly-CSharp.dll关键点,发现部分为验证文件头MZ和进行CRC校验.
发现一个可疑函数函数偏移为0xe900,Hook参数前后的值,即可发现,此处为Assembly_csharp解密
同时0xe900上层调用0x3381正好是导出函数 g_tprt_pfn_array+0x68的值
其也是mono_image_open_from_data_with_name的Hook函数
仔细分析,发现其前0x1000个字符进行了AES解密算法 大小为0x1000
IV为 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11
key为36 64 34 33 35 66 32 36 08 09 0a 0b 0c 0d 0e 0f
AES部分验证如下
后0x1000个字节采用了xor 0x87
解密脚本如下
from Crypto.Cipher import AES
key = '\x36\x64\x34\x33\x35\x66\x32\x36\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'
iv = '\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11'
aes = AES.new(key, AES.MODE_CBC,iv)
dec = open('Assembly-CSharp.dll', 'rb')
b = dec.read()
data=""
for i in range(0,0x1000,0x10):
data+=aes.decrypt(b[i:i+16])
for i in range(0x1000,len(b)-0x1000,1):
data+=chr(ord(b[i])^0x87)
with open("dec.dll",'wb') as fp:
fp.write(data)
尝试用dump
Hook c#函数mono_image_open_from_data_with_name,依据第一个参数来获取加载的C# dll文件,第二个参数获取C#
dll文件的大小。第八个参数以此来获取加载的dll名称。脚本如下
Java.perform(function(){
var android_dlopen_ext = Module.findExportByName('libc.so', "dlopen");
console.log(android_dlopen_ext);
if(android_dlopen_ext != null){
Interceptor.attach(android_dlopen_ext,{
onEnter: function(args){
var soName = args[0].readCString();
if(soName.indexOf("libmono.so") != -1){
this.hook = true;
}
},
onLeave: function(retval){
if(this.hook) {
dlopentodo();
};
}
});
}
function dlopentodo(){
var soAddr = Module.findBaseAddress("libmono.so");
var ptrTencentEncrypt_addr = soAddr.add(0x194bfc);
Interceptor.attach(ptrTencentEncrypt_addr,{
onEnter: function(args){
var dllname=args[7].readCString();
if(dllname.indexOf("Assembly-CSharp.dll")!=-1){
console.log("begin write");
var file = new File(("/sdcard/ass_dde"),"a+");
var len=args[1]>>>0;
var buffer=Memory.readByteArray(args[0], len);
file.write(buffer);
}
},
onLeave: function(retval){
}
});
}
})
依据第八个参数来判断所需要替换的dll,之后读取本地文件,分配至内存,将原本dll内容替换为破解版的dll内容。这样即可实现CF外挂
核心代码如下
Interceptor.attach(func_addr,{
onEnter: function(args){
console.log("size is ",args[1]);
var dllname=args[7].readCString();
if(dllname.indexOf("Assembly-CSharp.dll")!=-1){
var openPtr = Module.getExportByName('libc.so', 'open');
var open_addr = new NativeFunction(openPtr, 'int', ['pointer', 'int']);
var dll=[0x2F,0x64,0x61,0x74,0x61,0x2F,0x6C,0x6F,0x63,0x61,0x6C,0x2F,0x74,0x6D,0x70,0x2F,0x32,0x2E,0x64,0x6C,0x6C,0x00];
var dll_addr = Memory.alloc(dll.length);
var mode_addr = Memory.alloc(0x10);
Memory.writeByteArray(dll_addr,dll);
console.log(dll_addr.readCString());
var fd = open_addr(dll_addr,4);
if(fd>0){
var new_dll=Memory.alloc(24257536);///24257536
var readPtr = Module.getExportByName('libc.so', 'read');
var read_addr = new NativeFunction(readPtr, 'int', ['int','pointer','int']);
var result=read_addr(fd,new_dll,24257536);
}
Memory.copy(args[0],new_dll,24257536); //替换C#脚本
}
},
onLeave: function(retval){
}
});
修改人物跳跃高度
修改人物移动速度
将修改后的代码放在/data/local/tmp/上,frida脚本会读取替换mono_image_open_from_data_with_name函数的第一个参数
原文链接:https://blog.csdn.net/qq_39268483/article/details/115795885
作者:phpNumOne
链接:http://www.phpheidong.com/blog/article/44531/7be28cc2ee17fe2a0344/
来源:php黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 php黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-4
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!