android逆向奇技淫巧二十二:ida栈回溯加密算法跟踪(未完待续)(七)

时间:2024-03-12 13:35:36

  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