安装运行后检测绕过
adb安装,打开发现:
image-20240326145930896
楽,估计是检测到了什么。
猜基本都是什么frida、idaserver什么的,先进shell重命名一下:
image-20240326150345827
再开发现还是会,个人觉得是这个android_server64
(ida远程调试服务器)被检测到了,删除后发现能够正常运行,不过我自己把ida_server放在子文件夹下没有被抓到(
image-20240326150610784
算是先过了一开始的检测,能够运行了。
用jadx对包体进行分析
image-20240326150858235
发现是使用Unity3D
包名:com.com.sec2023.rocketmouse.mouse
入口点:com.unity3d.player.UnityPlayerActivity
不过此前自己是没有逆向过Unity制作的安卓游戏的,上来直接挑战这个,楽
解压看so
image-20240326151240788
Unity的游戏都有着libil2cpp.so,github上有个开源的项目Il2CppDumper 可以获取实现获取符号表
解压进入目录中,拿到libil2cpp.so
与global-metadata.dat
。 libil2cpp.so
: \lib\armeabi-v7a\libil2cpp.so
global-metadata.dat
: \assets\bin\Data\Managed\Metadata\global-metadata.dat
我去,着IL2CppDumper还有调用选择文件的API,不用自己手写文件路径,好评。
不过和复现的WP一样是失败了:
image-20240326152711549
跑010模板也对的上,应该是没有加密的:
image-20240326152920430
至于libil2cpp.so,反编译也是依托:
image-20240326153239591
符号表除了一些API之外,剩下的就是纯乱,但是运行的时候不可能会这样的,准备使用frida把它自解密后的数据dump下来
dump数据
在开启frida_server之后,又出现一样的heck detect的提示,盲猜是检测了frida端口,关掉进程之后又能运行,尝试换端口启动
./frs16 -l 0.0.0.0:27041
能跑起来来了
根据多个师傅的WP,dump内存的方法多种多样,复现就是为了学习,全部做一遍:
gg修改器 dump
起点:
image-20240326161127735
终点
image-20240326161044469
再用IL2CppDump看看:
好!
能从exe目录下得到
image-20240326205619243
但是dump下来的文件没有导入导出函数的符号
而 il2cpp 符号的脚本又是针对于 dump 文件的
所以修复一下dump的文件头之类的
.....修不懂。。
挖个坑,自己PE没看完呢
Fallw1nd师傅那个dump下来怪怪的,接着这边了
修复dump数据
首先是先将每个program_table的每一个p_offset改成p_vaddr
同时也将每一个p_filesz改成p_memsz(因为原先是进行了加固,现在这个是在内存中dump下来的,现在对应的段已经解压到内存的对应地址)
image-20240403235731355
然后注意最后一个表,这个表的结尾地址就是SECTION_HEADER的开头,所以SECTION_HEADER本来就应该是0x13BC000+63352 = 0x13CB778,所以填到文件的地址
image-20240404000021360
修改完按 program_table 按一下 F5 就会重新分析了,也可以看到一片空白的 section_header:
image-20240404000107492
直接将原版的复制到dump下来的(Ctrl+shift+C Ctrl+shift+V)
再 F5 刷新
刷新后,发现section header table乱码,和旁边的完全不同
image-20240409213702661
这部分的值是根据header的e_shtrndx的值,去寻找section header对应的块,再去寻找对应的符号:
image-20240409213901334
这里的值是26,指的是section_table_element[26]
ection_header_table->section_table_element[26]
中s_offset
的值决定了section的名称将从1199370h
去索引
image-20240409214010117
就是分析的data块,section的所有名称都在这个地方,把原来的复制过去就行,再F5刷新一下就行
image-20240409214135598
但是模板还是没分析出来,接下来就要修复section的偏移:
节(section) 的位置和大小由节头表(secion_header_table)中这两个成员决定
s_addr
如果此 section 需要映射到进程空间,此成员指定映射的起始地址;如不需映射,此值为 0
s_offset
此 section 相对于文件开头的字节偏移量.如果 section 类型为 SHT_NOBITS
,表明该 section 在文件中不占空间,这时 sh_offset 没什么用
修正 节(section) 的偏移有两条规则
如果s_addr为0,无需修改s_offset
如果s_addr不为0,则将s_addr的值复制给s_offset
修正完成后,按下F5
重新运行模板ELF.bt
,可以发现section的名称已经恢复,同时也有了dynamic_symbol_table
image-20240409214517506
然后就可以丢到ida分析了
Frida hook dlopen
看懂了Fallw1nd师傅的脚本。。至福
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 function WriteMemToFile (addr, size, file_path ) { Java .perform (function ( ) { var prefix = '/storage/emulated/0/dump/' var mkdir = Module .findExportByName ('libc.so' , 'mkdir' ); var chmod = Module .findExportByName ('libc.so' , 'chmod' ); var fopen = Module .findExportByName ('libc.so' , 'fopen' ); var fwrite = Module .findExportByName ('libc.so' , 'fwrite' ); var fclose = Module .findExportByName ('libc.so' , 'fclose' ); var call_mkdir = new NativeFunction (mkdir, 'int' , ['pointer' , 'int' ]); var call_chmod = new NativeFunction (chmod, 'int' , ['pointer' , 'int' ]); var call_fopen = new NativeFunction (fopen, 'pointer' , ['pointer' , 'pointer' ]); var call_fwrite = new NativeFunction (fwrite, 'int' , ['pointer' , 'int' , 'int' , 'pointer' ]); var call_fclose = new NativeFunction (fclose, 'int' , ['pointer' ]); call_mkdir (Memory .allocUtf8String (prefix), 0x1FF ); call_chmod (Memory .allocUtf8String (prefix), 0x1FF ); var fp = call_fopen ( Memory .allocUtf8String (prefix + file_path), Memory .allocUtf8String ('wb' )); if (call_fwrite (addr, 1 , size, fp)) { console .log ('[+] Write file success, file path: ' + prefix + file_path); } else { console .log ('[x] Write file failed' ); } call_fclose (fp); }); } function HookLibWithCallback (name, callback ) { var dlopen = Module .findExportByName ('libdl.so' , 'dlopen' ); var detach_listener = Interceptor .attach (dlopen, { onEnter : function (args ) { var cur = args[0 ].readCString (); console .log ('[+] dlopen called, name: ' + cur); if (cur.indexOf (name) != -1 ) { this .hook = true ; } }, onLeave : function ( ) { if (this .hook ) { console .log ('[+] Hook Lib success, name:' , name); callback (); detach_listener.detach (); } } }); } function LogModule (module ) { console .log ('Module name: ' + module .name ); console .log ('Module base: ' + module .base ); console .log ('Module size: ' + module .size ); } function TraverseModules (mode, {name = '' , name_array = []} ) { if (mode == 'all' ) { var modules = Process .enumerateModules (); for (var i = 0 ; i < modules.length ; i++) { var module = modules[i]; } return modules; } else if (mode == 'single' ) { var module = Process .getModuleByName (name); LogModule (module ); return module ; } else if (mode == 'multiple' ) { var modules = Process .enumerateModules (); var target_modules = []; for (var i = 0 ; i < modules.length ; i++) { var module = modules[i]; if (name_array.indexOf (module .name ) != -1 ) { LogModule (module ); target_modules.push (module ); } } return target_modules; } } function DumpIL2CPP ( ) { var libil2cpp = TraverseModules ('single' , {name : 'libil2cpp.so' }); WriteMemToFile (libil2cpp.base , libil2cpp.size , 'libil2cpp.so' ); } function main ( ) { HookLibWithCallback ('libil2cpp.so' , DumpIL2CPP ); } main ();
根据自己的情况把dump的地址改了,不知道为什么我这边有root权限但是搞不到里面的文件,只能这样子保存然后dump下来
怪哦,这个好像dump的不多。
ida分析dump的libil2cpp
将 dump 文件载入 ida 之后,最好是 Rebase 一下,因为是运行态文件,可能有些内存值已经被重定位,因此 Rebase 之后可能得到更多符号, Rebase 的值就是 dump 文件的载入地址,文件名上就有,比如我的是 0x7495598000