1、上次通过hook registerNativeMethod找到了metasec种唯一注册的jni函数,本想着通过trace call来看看到底这个函数层层调用了哪些函数,结果trace出来的结果完全是错的(用hook到的地址调用findModuleByAddress确认哪个so,直接报异常!),stalker trace call的代码:
function trace_entry(tatgetAddr){ //var addr_1094d = targetSo.add(0x1094c+1); Interceptor.attach(tatgetAddr, { onEnter: function(args){ console.log("enter tatgetAddr===================================================================="); this.pid = Process.getCurrentThreadId(); Stalker.follow(this.pid,{ events:{ call:true, ret:false, exec:false, block:false, compile:false }, onReceive:function(events){ var all_events = Stalker.parse(events); console.log("on Received:",all_events.length); for(var i=0;i<all_events.length;i++){ //console.log(all_events[i]); var type=all_events[i][0]; if(type=="call"){ var addr1 = all_events[i][i]; try{ var module1=Process.findModuleByAddress(addr1); if(module1!=null&&module1.name=="libmetasec_ml.so"){ var addr2=all_events[i][2]; var module2=Process.findModuleByAddress(addr2); console.log("call:",module1.name+"!"+addr1.sub(module1.base),module2.name+"!"+addr2.sub(module2.base)); } }catch(error){ console.log("exception error:",error); console.log(all_events[i]); } } } }, onCallSummary:function(summary){ } }); },onLeave: function(retval){ Stalker.unfollow(this.pid); console.log("retval:"+retval); console.log("leave tatgetAddr===================================================================="); } }); } function main(){ var targetSo = Module.findBaseAddress(\'libmetasec_ml.so\'); //var targetSo = new NativePointer(0x4200000); var tatgetAddr = targetSo.add(0x1096C+1); //var tatgetAddr = targetSo.add(0x6221c+1); trace_entry(tatgetAddr); } setImmediate(main);
其他app的trace是ok的,这里不行,大概率有反frida的跟踪;
console.log(\'called from:\n\' +Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join(\'\n\') + \'\n\')
用上面这个hook sub_6221c(就是调用base64码表的关键函数)的结果如下:
sub_6221c called from:
0xb4cc14a3 libmetasec_ml.so!0x6c4a3
0xb4cc14a3 libmetasec_ml.so!0x6c4a3
0xb4c8a0d3 libmetasec_ml.so!0x350d3
0xb4c8bcf0 libmetasec_ml.so!0x36cf0
太少了,根本找不出啥!无奈只能老老实实继续用ida在sub_6221c下断点,自己在栈上和LR上回溯;这里也看出一点:frida的trace在x音这里失效了,估计是有反调试吧!
自己用ida根据栈回溯时遇到的问题:(1)x86有ebp作为栈帧,ebp+4就是返回地址;但arm没有,只能自己在栈上挨个找!如果栈上的地址在代码中是BL或BLX的下一行,就可以确认是函数调用关系了!如果不是在BL或BLX后面,可能是个局部变量或参数,暂时就不管了! (2)ida有些地址反编译失败,栈上有的地址在debug view时只能看到一堆“数据块”,如下(这种块太多了,这里只贴部分):
text:00034DE9 46 08 46 byte_34DE9 DCB 0x46, 8, 0x46 ; DATA XREF: sub_2F9A0+14↑o .text:00034DE9 ; sub_2F9A0+1E↑o ... .text:00034DEC 10 47 D0 E9+ DCD 3922741008, 1753362688, 4031727128, 3045112139, 553707984 .text:00034DEC 00 31 82 68+ DCD 4158473744, 3179346797, 1174713616, 4158482464, 1616967697 .text:00034DEC 18 46 4F F0+ DCD 3037773072, 1746945540, 4212848602, 3171967072, 1174713616 .text:00034DEC 4B B9 80 B5+ DCD 4220842046, 3171967008, 3922769280, 1175462144, 4286904302 .text:00034DEC D0 E9 00 21+ DCD 3037773184, 1746945540, 4267767802, 3171971360, 3922769280 .text:00034DEC 10 46 DD F7+ DCD 1175462144, 4219009018, 3044064640, 1747338756, 4158397744 .text:00034DEC 6D FB 80 BD+ DCD 1753284583, 2970100992, 3178262821, 4518150, 4292802524 .text:00034DEC 10 B5 04 46+ DCD 671115392, 620871624, 3178262821, 536930768, 22343936
刚开始没太在意,觉得应该是ida解析出错(有可能是故意加花指令“误导”IDA的),直到有一次又遇到signal报错:C18C31CC: got SIGSEGV signal (Segmentation violation) (exc.code b, tid 21480);我已经挂起了其他线程,这个signal是谁、怎么发出来的了?难道还有其他进程给主进程发signal?好在这里提示了报错的地址,用这个地址减去metasec_ml的基址,得到0x351CC的偏移,刚好在上面这个数据块内部;尝试继续用C或P,果然能正常识别成代码!猜测这里是故意让ida不识别,或则把这段内存设置成不可执行;一旦检测到ida在调试,想办法让代码跳转到这里(代码内部有很多间接跳转,也就跳转地址放在寄存器,这样一来跳转地址就不用写死了,可根据实际情况决定跳转位置,也能防止IDA的交叉引用功能查询,绝啊!),产生异常报错! 程序退出也是操作系统的行为,自生并未直接调用exit这类的函数,逆向人员不容易捕捉!
2、这里继续用ida栈回溯,我个人的一些心得和技巧:
(1)栈上凡是标记了红框框这种的建议去源码看看,凡是在BL或BLX代码下一行的都是函数调用,建议下断点尝试!
(2)寄存器重点监控两类:malloc和heap!原因很简单:数据要么存在stack,要么存heap,要么存操作系统的数据段;stack存的都是参数、返回地址、局部变了,函数调用一旦结束,这部分空间就释放了,没法继续使用;操作系统数据段存的都是全局变量和static变量,所以这4个字段肯定存在heap上!所以建议重点关注执行heap内存的寄存器,和保存malloc分配地址的寄存器!
(3)根据上面的一些小技巧,不停地在栈上回溯,挨个查找、下断点调试(这里纯粹就是体力活了),找到几个新的地址:
- R1指向的地址包含了X-Argus和X-Gorgon两个字段,代码偏移:0x14204
有时还能一次性出4个字段:
在这附近,有时候还能一次集齐5个字段:偏移0x1424C
这里看代码更清晰:R1来自栈上,很有可能是C1A5D24C这里函数执行后保存在栈上sp+0x5c的!
- R1指向的地址包含了X-Gorgon,代码偏移:0xD20C
这里也能找到X-Argus:
X-Tyhon也出现了:
- R1指向的地址包含了X-Argus,代码偏移:0xD022
同样的偏移,R1指向了X-Ladon;从代码看,地址来自传入的R1;
执行完 BLX unk_C1A50690后,R0也指向了X-Tyhon:
继续往上根据函数调用关系找R1:发现来自R0;偏移:0x35008;这里的代码看起来是不是有点奇怪了:
- 每段代码都是push开头、pop结尾,经过多次调试观察,每段代码都被执行过,这里感觉有点像VMP的handler;
- R2指向的是函数代码入口,很有可能是通过BLX R2跳转到这里的!通过寄存器的间接调用,可以防止在IDA通过xrefs查找调用关系,这是一绝啊!这该怎么继续回溯了?看栈上我标红的地址,从这里开始继续回溯!
果然是通过BX R2跳转的!这里的offset:C1A7DDE8-C1A49000=0x34DE8;IDA在这里还标注了引用关系,顺着这个继续回溯!
这里有点像VMP的入口,根据不同的R2跳转到不同的地址(就是上面0x35008附近的代码,每段代码除了BL跳转的地址不同,其他完全一样)
下面就是通过BX R2跳转到不同的地址:
接着BX R2的代码回溯(ida已经标注了):这里多出取了PC的值,R1和R2指向了比较奇怪的字符串,R4和R6指向了代码地址,这么做的动机暂时不明! 先记下offset: C1A7DD56-C1A49000=0x34D56
其他重要偏移:0xD20E, 函数执行完后R1指向了X-argus:
偏移:0xD220,BL执行完R1就保存了X-argus的地址!
同样的地方R1保存了X-Ladon:
这几天通过栈回溯,找到了一些线索!但感觉还是没找到直接生成这些字段的代码;在目前找到的这些关键函数中,还是要想办法trace一下,或用unidbg执行试试,看看完整的代码是怎么执行的!
参考:
1、https://github.com/LeadroyaL/IDA_ARM_Unwind IDA ARM Unwind Plugin