游戏安全实验室 首页 技术入门 查看内容

 阅读目录

Android平台IDA动态调试

发布于:2016-4-26 11:21   |    287298次阅读 作者: 管理员    |   原作者: TP   |   来自: 原创

在前面章节介绍过使用IDA Pro工具对Android应用程序的共享链接库so文件进行静态分析,然而在逆向分析过程中很多时候仅仅依靠静态分析是很难取得突破性进展的,此时就需要进一步结合动态分析来了解程序的执行流程。本章主要介绍使用IDA Pro工具对Android原生程序和原生动态链接库进行动态调试的方法。

一、启动动态调试

1.1 调试Android原生程序

调试Android原生程序可以采用远程运行调试的方法,笔者将IDA静态分析章节中的实例编译生成可执行原生程序DebugTest,使用adb push命令将DebugTest和IDA安装文件目录下dbgsrv子目录中的”android_server”复制到Android设备中,这里笔者将文件存储在/data/目录中。

在运行两个程序前,需要给DebugTest和android_server文件添加可读可写可执行的权限,在Android设备的root权限下输入如下命令给两个文件加上可执行权限。

chmod 777 /data/DebugTest

chmod 777 /data/android_server

然后在root权限下运行android_server文件,如下图1-1所示,会打印出以下内容,提示调试服务器已经启动并且监听了23946端口。

图1-1 运行android_server打印信息

此时打开另外的cmd命令提示符输入如下命令开启端口转发,即可以开始使用IDA对原生程序进行运行和调试。

adb forward tcp:23946 tcp:23946

启动IDA程序,打开一个空白工作界面,通过菜单栏的Debugger->Run->Remote ArmLinux/Android debugger选项会打开如下图1-2所示的对话框,在Application输入栏中输入远程运行调试的程序的路径和名称,在Directory输入栏中输入被调试程序的所在目录,若原声程序带参数,可在Parameters输入栏中输入参数。

图1-2 调试原生程序设置对话框

除此之外,用户还可以点击上图弹窗中的Debug options按钮,会打开如下图1-3所示的选项窗口,可在该窗口中设置一些事件断点、日志记录以及调试选项。设置完成后,点击OK按钮即可以开始原生程序进行动态调试。

图1-3 动态调试选项设置对话框

1.2 调试Android原生动态链接库

调试Android原生动态链接库一般采用远程附加进程的方法,在此之前同样需要先运行android_server和执行端口转发的命令,具体操作见1.1小节,另外还需要打开原生动态链接库所在的应用程序。本小节使用一个简单的应用程序(包含libDebugTest.so动态链接库)来作为实例进行调试。

启动IDA程序,打开一个空白工作界面,通过菜单栏的Debugger->Attach>Remote ArmLinux/Android debugger选项会打开如下图1-4所示的对话框,同样可点击Debug options按钮打开调试设置窗口来对调试选项进行设置。 

图1-4 远程附加进程调试设置对话框

点击OK按钮后,会弹出如下图1-5所示的Android设备的进程列表,在进程列表中选中需要附加的进程开始进行动态调试。

1-5 选择Android设备的进程列表附加

上述的远程附加调试方法一般发生在应用程序已经启动后,模块已经加载到内存地址空间中。此时若用户想对模块的.init_array段或JNI_OnLoad函数进行动态调试,依靠上面的远程调试方法是不可行的。下面介绍在应用程序加载模块前中断程序,此时通过IDA工具附加到进程上,就可以对模块的.init_array段或JNI_OnLoad函数进行动态调试。

首先依然是在root权限下启动android_server程序,然后开启端口转发。使用am命令以调试选项打开Android应用程序。

am start -D -n com.example.tencent.debugtest/.MainActivity

如下图1-6所示,应用程序启动后会提示Waiting For Debugger”,此时应用程序的执行流程已经中断,可以使用IDA工具附加到该进程上进行动态调试。

1-6 调试选项启动Android应用程序

使用IDA附加到被调试进程时,在调试选项中设置如下图1-7所示的调试选项,勾选Suspend on library load/unload”,表示在模块加载时中断程序,

1-7 IDA动态调试选项设置

在IDA附加到Android应用程序的进程后,还需要使用如下所示的jdb命令来使应用程序恢复运行,由于前面已经在IDA的调试选项中设置模块加载时中断程序,程序恢复运行后加载模块就会中断,此时模块的.init_array段和JNI_OnLoad函数未执行,用户可以对其进行动态调试。

jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700

1.3 动态调试主界面

使用IDA工具远程运行原生程序后,会切换到如下图所示的调试界面,一般来说IDA Pro会中断在入口点处。而使用远程附加进程的方式调试原生动态链接库时,一般不会中断在动态链接库的领空,还需要在动态链接库的地址空间设置断点后使程序运行到动态链接库的领空。

如下图1-7所示,笔者将IDA动态调试的主界面分为了以下几个部分,熟悉IDA静态分析界面的读者在之前章节已经对一些窗口有了一些了解,这里仅动态分析过程中几个重要的窗口。

1-7 IDA动态调试主界面

① 反汇编窗口,显示反汇编代码,基本功能与IDA静态分析时反汇编窗口相同。在此需要注意的是,动态分析时IDA为解析效率考虑可能会将大部分代码识别成数据,此时可以使用快捷键C将当前地址处的数据解析成代码,或者在函数开始处使用快捷键P将从当前地址处解析成函数。

② 寄存器窗口,显示当前运行环境时寄存器的值。

③ 模块窗口,显示当前已经加载到内存中的模块路径和地址,我们可以在该窗口中定位到需要调试的模块地址。

④ 线程窗口,显示当前线程信息。

⑤ 十六进制窗口,与IDA静态分析中的十六进制窗口作用相似,可用于编辑内存数据和代码。

⑥ 栈窗口,显示当前栈的内容。

⑦ 输出信息窗口,输出窗口将输出你所执行的各种操作的状态。

二、动态调试常用功能

2.1 断点和运行

在IDA窗口中设置断点可通过在需要下断的地址处单击鼠标右键打开选项窗口,选择Add breakpoint,或者使用快捷键F2设置断点。设置断点后,再次单击鼠标右键打开选项菜单,如下图2-1所示,可以通过disable breakpoint选项来使断点不可用,通过Edit breakpoint来编辑断点,通过Delete breakpoint来删除断点。

图2-1 IDA断点右键菜单

如下图2-2所示为编辑断点的对话框,在该对话框中可以在Condition窗口中设置条件断点,即当满足一定条件时中断,点击Condition右侧的按钮可以打开IDC脚本编辑框,通过IDC脚本来控制断点。

2-2 编辑断点对话框

在程序运行到断点所在的地址处时,会自动中断,如果需要继续运行可以通过菜单栏的Debugger->Continue Process选项来使程序继续运行,或者通过快捷键F9来使程序继续运行。如果需要查看当前已经设置的所有断点,可以通过菜单栏的Debugger->Breakpoints->Breakpoint list选项打开断点列表窗口,也可以通过快捷键Ctrl + Alt + B来打开断点列表窗口。

2.2 单步调试

同PC端的其他调试器一样,IDA为Android应用程序提供了丰富的单步调试功能。单步步入调试可以通过菜单栏的Debugger->Step into选项,也可以通过快捷键F7”。 单步步过调试可以通过菜单栏的Debugger->Step over选项,也可以通过快捷键F8”。 运行到返回可以通过菜单栏的Debugger->Run until return选项,也可以通过快捷键Ctrl + F7”。 运行到光标处可以通过菜单栏的Debugger->Run to cursor选项,也可以通过快捷键F4”。

2.3 IDC脚本

在动态分析过程中经常需要使用IDC脚本,IDC语法可以参考官方文档使用IDC脚本可通过菜单栏的File->Script Command选项打开如下图2-3所示的对话框,在右侧的输入框中可以编辑IDC脚本,或者通过菜单栏的File->Script File选项来直接打开一个IDC文件。

图2-3 IDC脚本编辑对话框

IDC脚本的应用场景也十分广泛,最常用的就是Dump内存数据。在逆向分析过程中,经常遇到Android应用程序对dex文件进行了加密处理,在Native程序中对dex文件进行解密。逆向分析人员要获取到真正的dex文件,可以在解密dex文件的代码处中断,使用IDC脚本Dump已经解密的内存空间数据转储到文件中。如下所示为一个简单的IDC脚本,Dump内存地址0x40000000开始的0x1000长度的数据到C:\\dump.dex”文件中

static main(void) 

{

    auto fp, i;

    fp = fopen("C:\\dump.dex", "wb");

    BeginAddr = 0x40000000;   //  Dump内存起始地址

    EndAddr = 0x40000000 + 0x1000;     //  Dump内存结束地址

    for ( i= begin; i< end; i++ )

        fputc(Byte(i), fp);

}

三、修改数据

3.1 修改内存数据

修改内存数据需要在十六进制窗口中进行编辑,可先将反汇编窗口与十六进制窗口同步。如下图3-1所示,在反汇编窗口中点击鼠标右键弹出菜单,选中Synchronize with选项,在子菜单中可以选择反汇编窗口同步的窗口或寄存器,这里选择同步Hex View-1窗口,即与十六进制窗口同步。窗口同步后在反汇编窗口中跳转到指定地址十六进制窗口也会跟随着跳转到指定地址,方便我们对内存数据进行查看和编辑。

3-1 右键菜单同步窗口选项

在需要修改内存数据时,可以在十六进制窗口中跳转到需要修改的内存地址处,点击鼠标右键,如下图3-2所示,在弹出的菜单中点击Edit选项,即可以直接在十六进制窗口中进行编辑。

3-2 十六进制窗口编辑数据选项

修改数据完成后单击右键菜单,如下图3-3所示,在弹出的右键惨淡中点击Apply changes选项可保存对内存数据的修改。

3-3 十六进制窗口保存修改选项

3.2 修改寄存器

在动态分析过程中,经常遇到需要修改寄存器值的情况,IDA提供了方便地修改寄存器值的方法。在寄存器窗口中,在需修改的寄存器单击鼠标右键,会弹出如下图3-4所示的菜单,可以在右键菜单中选择对应的选项来对寄存器的值进行修改,例如可通过Modify value选项对寄存器的值进行修改,通过Zero value选项将对应寄存器的值设置为0,通过Toggle value选项对寄存器的值取反。

3-4 修改寄存器值的右键菜单

四、修改代码

在IDA动态调试时修改代码与修改数据的方法相似,在内存中代码也是以数据的方式存储,均需要在十六进制窗口对其进行编辑和修改,因此本小节不再重复介绍修改的方法,而是介绍部分在逆向分析过程中需要修改代码的场景。

4.1 NOP函数

在动态逆向分析过程中,经常遇到需要NOP程序的关键函数,通常有两种方法来修改函数的代码。第一种方法可以在调用函数的地址处进行修改,将调用函数的汇编指令修改成NOP指令。ARM汇编中并没有提供单独的NOP指令,但可以使用”movs r0,r0”指令来代替NOP指令,其对应的十六进制数值为”00 00 A0 E1”,在IDA中该指令会被识别成NOP指令。

第二种方法是在函数首部直接让函数返回,将函数头部的汇编指令修改成mov pc,lr”指令,表示直接返回,其对应的十六进制数值为0E F0 A0 E1,在IDA中会被识别成RET指令。

4.2 改变执行流程

在程序中一般伴随有很多条件语句,这些条件语句决定着程序的执行流程。在动态调试过程中我们可通过修改条件判断时寄存器值或者直接NOP条件判断语句来控制程序的执行流程。

五、小结

逆向人员在面对较为复杂的分析环境时,动态分析方法是必须要掌握的关键技术。而IDA Pro工具提供了便捷地调试Android应用程序的方法,掌握IDA工具调试Android应用程序也显得尤为重要


 *转载请注明来自游戏安全实验室(GSLAB.QQ.COM)

分享到:
踩1 赞0

收藏

上一篇:IDA静态分析介绍

下一篇:IOS平台GDB动态调试介绍

最新评论
引用 ╮( ̄▽ ̄")╭ 2017-12-19 18:25
哈哈哈

查看全部评论(1)

B Color Image Link Quote Code Smilies

发表评论