安装运行后检测绕过 
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的地址改了。
怪哦,这个好像dump的不多。
 
看到个WP脚本,牛了:
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 let  dump_so_name = "libil2cpp.so" function  dumpso ( ){     try {         let  modu=Process .getModuleByName (dump_so_name)         var  base_addr = modu.base          var  base_size = modu.size          if  (modu){             console .log ("name: "  +modu.name );             console .log ("base: "  +base_addr);             console .log ("size: "  +"0x" +base_size.toString (16 ));                                       var  file_path = "/data/data/com.com.sec2023.rocketmouse.mouse/"  + modu.name  + "_"  + modu.base  + ".so" ;             var  all_size = 0              var  range_arry = Process .enumerateRanges ("r" )             var  file_handle = new  File (file_path, "wb" );             range_arry.forEach (range  =>  {                 if  ( (parseInt (range.base ,16 ) >= parseInt (base_addr)) && (parseInt (range.base ,16 ) <= parseInt (base_addr) + base_size )){                                                               all_size += range.size                      var  libso_buffer = ptr (range.base ).readByteArray (range.size );                     file_handle.write (libso_buffer);                     file_handle.flush ();                     console .log (`[+] ${range.base} -${"0x"  + range.size.toString(16 )} -${range.protection} ` )                 }             })             file_handle.close ();             console .log ("[dump_size]:" , "0x"  + all_size.toString (16 ));             console .log ("[dump]:" , file_path);                      }else {             console .log ('[x] '  + dump_so_name +'not found' );         }     }catch (e){         console .log ("dump so error \t"  + e)     } }function  hook_dlopen ( ) {     var  dlopen = Module .findExportByName (null , "dlopen" );      Interceptor .attach (dlopen, {          onEnter : function  (args ) {              this .call_hook  = false ;              var  so_name = ptr (args[0 ]).readCString ();              if  (so_name.indexOf (dump_so_name) >= 0 ) {                  console .log ("dlopen:" , ptr (args[0 ]).readCString ());                  this .call_hook  = true ;              }            }, onLeave : function  (retval ) {              if  (this .call_hook ) {                 dumpso ();              }          }      });  }hook_dlopen ();
 
dump下来,然后把数据 patch到被加密的 .so文件中。
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 import  idc begin = 0x0000000002B6850  end = 0x0000000013CB778  data = idc.get_bytes(begin,end-begin) fp = open (r"F:/CTF/TXgame/2023腾讯游戏安全技术竞赛-安卓客户端安全-初赛题目/getdata" ,"wb" ) fp.write(data) fp.close()print ("finish" )import  idcimport  ida_bytes begin = 0x0000000002B6850  end = 0x0000000013CB778  fp = open (r"F:/CTF/TXgame/2023腾讯游戏安全技术竞赛-安卓客户端安全-初赛题目/getdata" ,"rb" ) data = fp.read()import  idc import  idaapidef  upc (begin,end ):     for  i in  range (begin,end):         idc.del_items(i)     for  i in  range (begin,end):         idc.create_insn(i)     for  i in  range (begin,end):         idaapi.add_func(i)     print ("Finish!!!" ) begin = 0x0000000002B6850  end = 0x000000000C4E42C  upc(begin,end)
 
Zygisk-Il2CppDumper 
去年打的是UE4,复现就搁置了。今年按照规律可能是Unity,复现复现。
改用Zygisk-Il2CppDumper了,看起来dump的还顺利:
好用, 就是每次都要编译一个(
image-20250326171242570 
 
ida分析dump的libil2cpp 
用新东西修完之后,使用Il2CppDumper可以直接dump出相关文件
1 Il2CppDumper.exe  .\libil2cpp.so  .\global -metadata.dat <output-directory> 
 
把ida_with_struct_py3,il2cpp.h script.json全部导入ida中,即可恢复libil2cpp.so的大部分符号
getFlag 
查看dump.cs 可以看到相关符号地址:
不难发现:
1 2 private  Void CollectCoin(Collider2D coinCollider )  { }
 
在ida里面查看附近:
image-20250327161329160 
 
找Coin相关的:
image-20250327161502228 
 
存在比较,hook修改即可:
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 function  inline_hook ( ) {     var  soAddr = Module .findBaseAddress ("libil2cpp.so" );     var  target = soAddr.add (0x4653cc );     Memory .patchCode (target,4 ,function (code ){         var  writer = new  Arm64Writer (code, {pc :target});         var  res = hexToBytes ("1F000071" );         console .log (res);         writer.putBytes (res);         writer.flush ();         console .log (hexdump (target, {             offset : 0 ,             length : 64 ,             header : true ,             ansi : true ,         }));     }) }function  hexToBytes (str ) {     var  pos = 0 ;     var  len = str.length ;     if  (len % 2  != 0 ) {         return  null ;     }     len /= 2 ;     var  hexA = new  Array ();     for  (var  i = 0 ; i < len; i++) {         var  s = str.substr (pos, 2 );         var  v = parseInt (s, 16 );         hexA.push (v);         pos += 2 ;     }     return  hexA; }inline_hook ()
 
得flag
image-20250327161623705 
 
分析注册机 
根据命名寻找一下,发现smallkeyboard类
image-20250327161818373