Frida Stalker 是什么?

一、目标

在分析so中的算法时,Trace和Debug是常用的手段。

了解一些调试器原理的同学都知道,Trace和Debug需要修改原始代码加上个int 3,来激活调试器。

这样有些App可以依赖检测关键代码来判断是否被调试。

也许你会说,我们可以patch掉检测代码,上次飞哥遇到一个狠人app,B去检测A处的代码,C去检测B处的代码,D去检测C处的代码,…… 反正套娃了 5-6次,我就崩溃了。

还好有 Stalker

Stalker是基于动态重新编译的代码跟踪器。 它将代码指令复制到内存中的另一个位置,在该位置对其进行调整以适应新位置并包括其他跟踪指令。 如果应用程序在原始位置检查其代码,则会发现该代码是完整无缺的,因为它是被篡改的代码的副本。

二、步骤

Stalker Trace Cod

我们还是以上次分析的某小说App来演示 Stalker 的用法, http://91fans.com.cn/post/readbookone/

Stalker在ARM32下貌似不大好使,这里我们在ARM64下做的测试

1function trace_entry(baseAddr,tatgetAddr){ 2 Interceptor.attach(tatgetAddr, { 3 onEnter: function(args){ 4 console.log("enter tatgetAddr===================================================================="); 5 6 this.pid = Process.getCurrentThreadId(); 7 Stalker.follow(this.pid,{ 8 events:{ 9 // 暂时不需要这些 events 10 call:false, 11 ret:false, 12 exec:false, 13 14 block:false, 15 compile:false 16 }, 17 onReceive:function(events){ 18 }, 19 20 transform: function (iterator) { 21 var instruction = iterator.next(); 22 const startAddress = instruction.address; 23 // 从ida里面 找到 Java_com_baidu_searchbox_NativeBds_dae1 函数的 代码 在 0xE84 和 0x126C 之间 24 var isModule = startAddress.compare(baseAddr.add(0xE84)) >= 0 && startAddress.compare(baseAddr.add(0x126C)) < 0; 25 do{ 26 if (isModule){ 27 console.log(instruction.address.sub(baseAddr) + "\t:\t" + instruction); 28 } 29 iterator.keep(); 30 } while ((instruction = iterator.next()) !== null); 31 }, 32 33 onCallSummary:function(summary){ 34 35 } 36 }); 37 },onLeave: function(retval){ 38 Stalker.unfollow(this.pid); 39 console.log("retval:"+retval); 40 console.log("leave tatgetAddr===================================================================="); 41 } 42 }); 43}

需要解释的是 transform 函数, 其他的 events、 onReceive 和 onCallSummary 目前我们还用不到,它们可以做block 和 call之类的跟踪分析。

transform 遍历执行了当前的每一行汇编指令,默认显示的地址是实际内存地址,我们 instruction.address.sub(baseAddr) 减去了一个so的基地址,得到的就和ida中显示的地址一致了

main

加Hook

光显示指令没啥意思,指令看上去还没有ida好看呢。

但是这个是活的执行,我们可以加个hook,通过ida分析,感觉差不多 0xFB8的时候是计算key的长度。

key

所以我们在这里加个打印

1do{ 2 if (isModule){ 3 console.log(instruction.address.sub(baseAddr) + "\t:\t" + instruction); 4 5 if(instruction.address.sub(baseAddr) == 0xfb8){ 6 iterator.putCallout((context) => { 7 var string = Memory.readCString(context["x21"]); 8 console.log("#### key = " + string) 9 }) 10 } 11 } 12 iterator.keep(); 13} while ((instruction = iterator.next()) !== null);

这样就可以顺利的打印出本次aes算法中用的key了

10xfb4 : add x21, x21, x0, lsr #1 20xfb8 : mov x0, x21 30xfbc : ldr x22, [x8, #0x580] 40xfc0 : bl #0x7a751c55f0 5#### key = D0CD8B760CE07BC3 60xfc4 : mov x1, x0 70xfc8 : mov x0, x20 80xfcc : blr x22 90xfd0 : ldr x8, [x20]

更帅的Trace

我们现在掌握了打印指令和寄存器值的方法。不过这样打出来太不帅了,IDA的Trace只会打印被修改的寄存器的值。

还好有大佬已经写好了

https://github.com/bmax121/sktrace

先 把我们代码中 Stalker 部分注释掉,因为要干掉登录和vip,所以先启动我们的js

frida -U -l bqgst.js -f com.bqg.ddnoverl --no-pause

然后启动 sktrace

python sktrace.py -m attach -l libTxtFormatter.so -i Java_com_baidu_searchbox_NativeBds_dae1 com.bqg.ddnoverl

-l 指定so名称

-i 指定要Trace的函数名

最后跟的是包名或者app名称

10x7a2e289e9c add x29, sp, #0x50 ; x29=0x7a7bdb9d48->0x7a7bdb9c50 20x7a2e289ea0 mov x20, x0 ; x20=0x0->0x7c02192b70 30x7a2e289ea4 ldr x8, [x20] ; x8=0x79a1c49061b6ff43->0x7b3fe0e198 40x7a2e289ea8 mov x1, x2 ; x1=0x9e30a688->0x7a7bdb9d18 50x7a2e289eac mov x2, xzr ; x2=0x7a7bdb9d18->0x0 60x7a2e289eb0 mov x19, x3 ; x19=0x7cb23102a0->0x7a7bdb9d1c 70x7a2e289eb4 ldr x8, [x8, #0x548] ; x8=0x7b3fe0e198->0x7b3fbe20e0 80x7a2e289ebc ldr x8, [x20] ; x0=0x7c02192b70->0x7b522130f0, x1=0x7a7bdb9d18->0x7dee5ef7cc, x3=0x7a7bdb9d1c->0x10, x4=0x7a7bdb9d58->0x0, x8=0x7b3fbe20e0->0x7b3fe0e198, x11=0x40->0x522130f7, x12=0xb->0xffff00000eff, x13=0x380->0xafba2fb8, x16=0x7a2e289e94->0x7dd27ad7f8, x17=0x7cb23102a0->0x7dee554c78, x30=0x7deaefdc0c->0x7a2e289ebc 90x7a2e289ec0 mov x21, x0 ; x21=0x0->0x7b522130f0 100x7a2e289ec4 ldr x22, [x8, #0x580] ; x22=0x7abbab01b8->0x7b3fbe5504 110x7a2e2895f0 adrp x16, #0x7a2e29a000 ; x16=0x7dd27ad7f8->0x7a2e29a000, x30=0x7a2e289ebc->0x7a2e289ecc 120x7a2e2895f4 ldr x17, [x16, #0xfe8] ; x17=0x7dee554c78->0x7dee561980 130x7a2e2895f8 add x16, x16, #0xfe8 ; x16=0x7a2e29a000->0x7a2e29afe8

现在打出来的,就有ida Trace内味了。

同学们还可以模仿下sktrace的代码,搞个更趁手的兵刃出来。

三、总结

矛与盾的战斗是永不停息的,无痛hook,硬件断点应该是趋势。

一个趁手的调试器非常难得,一个能被Debug的App是藏不住秘密的。

ffshow

万事纷纷一笑中,渊明把菊对秋风

Tip:

: 本文的目的只有一个就是学习更多的逆向技巧和思路,如果有人利用本文技术去进行非法商业获取利益带来的法律责任都是操作者自己承担,和本文以及作者没关系,本文涉及到的代码项目可以去 奋飞的朋友们 知识星球自取,欢迎加入知识星球一起学习探讨技术。有问题可以加我wx: fenfei331 讨论下。

关注微信公众号: 奋飞安全,最新技术干货实时推送

点赞
收藏

评论区

加载中...

相关推荐

不能Hook的人生不值得 jsHook和模拟执行

一、目标李老板:奋飞呀,上次分析的那个App光能Debug还不够呀,网页中的js也用不了Frida,我还想Hook它的函数,咋搞呀?再有App可以RPC去执行签名,这个js我如何去利用呀?总不能代码都改成js去做请求吧?奋飞:老板呀,你一下提这么多要求,不是明摆着要我们加班吗?这次加班费可得加倍。二、步骤最简单易行的jsHookcon

frida调试不了怎么办?着急,在线等!

一、目标frida越来越流行,针对他的检测也越来越多了,什么特征串检测,TracerPid检测,双进程保护。搞的我们茶饭不思,啤酒都不香了。今天的目标是数字壳的调试,双进程保护。二、步骤侦测下火力fspawn模式启动App,提示:fridaUfcom.asiainfo.appltest.jsnopauseProcesscrashed

解决研发痛点SnoarQube代码检查实战

1.代码质量检查,想知道团队成员代码质量情况,团队人多后每个人的代码风格和代码水平不一通过sonar检测能做到代码基准的一个把控。2.master代码质量是基准,可以理解master分支的sonar检测是通过的,分支代码质量检查和master代码进行比对,我们是master上线。3.sonar检测后把结果发送通知给对应的开发和其TL,开发能及时知道自己开发代码是否有问题

appdbg: 一个伪装成调试器的虚拟机

一、目标现在的App都不安分,Java层去和Native挤眉弄眼,Native层又喜欢和Jave去暗通款曲。想安安静静的分析一个so太难了。有没有可能把App在Pc上都模拟执行起来,这样Native再去勾搭Jave层的时候就可以节省很多补环境的工作了。appdbg就是这样一个伪装成调试器的虚拟机。作者的介绍是:makeitpossibletorun

Dubbo 整合 Zookeeper 实现 微服务

搭建准备:zookeeper是一定要提前安装好的,并最先启动运行!另外,强烈推荐安装ZKUI和dubboadmin:zkui可以实时查看zk的最新配置,和检测节点变化时代码的实时同步更新dubboadmin可以检测你的provider或者consumer有没有正确连接上,和consumer是否正确调用到了providerdubb

Java PinBall 简单弹球小游戏【4】碰撞检测及边界检测

4.游戏中的碰撞检测(1)弹球游戏中的边界碰撞检测。这个原理大家应该很容易就想到了,用游戏元素的坐标值与整场景的大小来比较就可以判断出元素是否碰到边界了,为了丰富游戏框架,我制作了一个游戏边界碰撞检测器类。大家可以参考类:BorderCrossing,代码我就不贴到这里了。(2)游戏中的元素相互之间的碰撞检测。这里的碰撞包括但