IDA PRO 06 - 动态调试基础04

今早看了一个视频,深得我心,与我更系列文章几乎是一样的理由,不过我想的没有那么透彻。不同的人生阶段会有不同的想法,重新开启一个新的学习旅程对现在的我来说,是一个值得尝试的东西。曾有段时间觉得自己除了写代码,啥都不会,现在发现还能做点事情,输出的应该也算有点价值。
视频链接:www.bilibili.com/video/BV1SH...

本文讨论一下动态调试的一些其他技巧。

  • trace 使用
  • 调试fork进程
  • 调试 Android JNI 的 init_array 中的函数或JNI_OnLoad函数

Trace

trace 是用来记录一个进程在执行过程中发生的特定事件。这些事件会被记录到一个缓存区或者文件中。

我们以一个例子来讲解 trace 的作用,材料已经上传到了 p19。

首先,使用 IDA 打开目标文件,看其函数窗口,发现只有很少的几个函数:

这是因为该程序里面的花指令太多了,干扰了IDA的静态分析结果。对于花指令,有些文章有比较详细的介绍:

www.anquanke.com/post/id/208...

www.anquanke.com/post/id/236...

有时间的可以看看,毕竟搞破解的都是搞开发的玩剩下的,出题的总是要高于解题的。

这个程序里面的花指令多到IDA都分析不出来啥东西,我们一个个的去看肯定也不现实,那么根据文章中说的:花指令大致可以分为可执行花指令和不可执行花指令两类。所以我们可以先使用 Trace 来找出不可执行的花指令。

进入调试模式,在 start 方法最前面打上断点,打开菜单项 [Debugger] → [Tracing] → [Tracing Options] 配置 Trace 选项:

Trace buffer size,如果分析的程序较大,这个数值可以填大一些。

Trace text file,想要将Trace记录保存为文件,可以填入一个文件路径。

Highlight,这个一定要选上,它会将执行过的指令染色,非常的有用。

其他更细节的选项说明可以去查一下文档或者书籍,这里就不细说了。

Trace 的粒度:

第一个是指令级别的trace,就是记录的是每条指令的指令。

第二个是基本块的trace,基本块的概念 ollvm 里面有,可以找下文档。

第三个是函数级别的trace,仅仅记录函数的调用。

调试启动进程后,触发断点,这3个选项就可以选择了,我们选择指令trace,然后让程序继续运行,等待进入下一个断点或者程序结束,这里我们没有设置下一个断点,所以程序会运行直到结束或者等待输入之类的。

可以看到,有一片黄色出现了,这就表示这些指令是执行到了的指令。

由于指令 trace 会极大的损耗性能,因为它要监视每条指令,所以会等待的时间比较长。

等到进程出现这个界面的时候,说明程序运行了一段逻辑了,它要等待用户输入,我们可以先分析从程序开始到这里的 trace,后面的再说。

所以,我们停止调试,打开 trace 窗口看看,打开菜单项 [Debugger] → [Tracing] → [Tracing Window] 查看 Trace 记录:

这里有 18w 行指令,还是非常多的。所以一般我们是使用脚本来处理这些指令,但是我们还没有学习如何编写脚本,所以这里就只是简单介绍一下该怎么搞。

上图中,在 Address 这一行,我们右键,发现有个选项是默认勾选了的,如果是我们自己看,这个是有帮助的,但是如果要给 python 处理,这个地址的名字就很不方便,所以我们去掉勾选,看看效果:

这个时候,地址格式就统一了。

我们简单的观察一下这些指令,发现一个规律,就是这些指令基本可以分为一块一块的,每个块里面的指令会比较对称:

它的 push 与 pop 都是对称的,观察 rsp 寄存器的值也可以。花指令的一个原则,就是不干扰程序的正常运行。所以从这个方面入手,我们是要找出那些执行了也没啥乱用的指令块即可。

当然,我对花指令的研究也不深入,刚入行,这里也只是说了下我自己的看法。花指令的分析不在本系列范围内,所以暂不深入研究了。

将这些数据导出,可以直接右键 export trace to text file,以文本模式导出来,这样可以直接用 python 处理,比较方便。

调试 fork 进程

在上一篇课程中,我们调试过一个目标apk(blackbox.apk),还分析过它的 Java_com_pandaos_idacourse_MainActivity_enc函数,它的反汇编代码有这样的一段:

scss 复制代码
if ( !fork() )
  {
    __android_log_print(3, "pandaos", "try DEBUG ME!");
    init();
    init();
    init();
    init();
    init();
    init();
    init();
    init();
    init();
    init();
    init();
    __android_log_print(3, "pandaos", "tell me special_key.");
    exit(0);
  }

这个目的就很明显了,是想让我们找出子进程里面生成的 special_key。那么我们该如何调试这个子进程呢?看代码逻辑,这个子进程执行了一个循环就结束了,根本没有机会 attach 上去。

这个有一个技巧,就是将子进程的第一行指令 patch 为一个死循环,等断点附加上去之后,再将指令还原继续运行即可。

我们来操作一下,先看看子进程要执行的第一条指令:

arduino 复制代码
.text:00000000000170D0 78 71 00 94                   BL              .__android_log_print

这行指令的意思就是跳转到__android_log_print 里面去执行。我们要将这行指令改为一个死循环要如何做呢?

在 arm 指令集里面,跳转指令有2种常用的:

css 复制代码
B
BL

B指令是ARM中最基本的跳转指令,它的使用方法如下:

css 复制代码
B label

表示跳转到 label 所指向的位置,我们看一个例子:

我们可以利用这个指令来做一个死循环,看了一下指令的十六进制表示,没有发现B指令的操作符是啥,有点奇怪。

BL指令跟B不同:在跳转之前,会先将当前指令的下一条指令地址保存到LR寄存器中,然后才跳转到标号执行。这样做的好处是:当我们想从标号地方返回时,可以直接将LR寄存器中的返回地址赋值给PC,程序就可以返回到原来的程序中继续执行了。我们并不想更改寄存器,所以不用BL。

有了跳转指令基础,我们就可以 patch 了,首先在 fork 这里加上断点,然后附加上进程,修改函数调用为死循环:

使用了,keypatch 插件后,我们就不用自己计算偏移了,只需要填目标地址就好了。

点击 patch,再看看伪代码,发现变成了死循环:

我们让程序继续运行,这样fork出来的进程就会进入死循环,这个时候,我们退出主进程的调试(Detach from process),重新附加到子进程上:

可以看到,这个时候就出现了两个进程,28827 就是子进程,我们先附加上去,再给循环加上断点:

有需要的可以进行指令还原,但是这里不需要,所以我们直接 set ip,让进程执行下面的 init 代码:

按 F8 步过所有 init 调用,看看 special key 的值:

发现全部是 0,这样谜题就解出来了。

调试 Android JNI 的 init_array 中的函数或JNI_OnLoad函数

这里我们需要借助 frida,因为 frida 有一个 pause 模式,这个模式就是让 app 启动,没有完全启动,因为此时它还没加载自己的任何库。

由于app自己的库是有 linker 进行加载的,其 init_array 段也是 linker 主动调用的(有兴趣的可以翻翻源码),所以我们可以先找到 linker 中对应的函数,加上断点就能调试到 so 加载的时候执行的 init_array 函数。

我们先使用 frida,让 app 进入暂停模式:

我是用的是 15.2.2 版本,所以默认就是进入暂停模式,frida 还提示我们,使用 %resume 可以让程序继续,这个时候我们看app窗口就是一个白屏了。

我们使用 ida 附加到进程,在 modules 窗口找到 linker:

点进去,找到它的 call_array 函数:

这里可以对比android的源码来看,其中v11的调用是会触发 so 加载时的 init_array 方法的调用。

我们在这里加上断点:

在so加载时执行的 init 函数里面也加上断点:

断点加好了之后,在 frida 里面输入%resume ,让程序继续运行,就能断点到 init 函数里面了:

可以看到,确实进入了该函数。

相关推荐
崔庆才丨静觅33 分钟前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60611 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了1 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅2 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅2 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment2 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅3 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊3 小时前
jwt介绍
前端
爱敲代码的小鱼3 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax