安卓app的动态调试

2023-10-18

调试环境

IDA版本:7.0

  • 进入IDA软件的数据路径 ida.app/Contents/MacOS/dbgsrv
    注意: 根据so文件目录判断目标文件位数,v7a - 32位,v8是64位。使用不同的位数的ida进行调试

  • 将文件夹内对应位数的android server文件传入手机

adb push android_server /data/local/tmp/
  • 进入手机,运行android server
# 进入手机 - 多台设备使用时使用-s参数设备名
adb shell
# 切换管理员 - 才能进入tmp目录
su
# 进入android server所在目录
cd /data/local/tmp/
# 给予android server最高权限
chmod 777 android_server
# 运行android server 指定端口需要携带参数-p且无空格,例如`-p23456`
./android_server
  • 将android server端口转发(需要使用新端口)
# 将PC上的23946与手机23946建立转发
# 参数中前者为local(PC端口) 后者为remote(手机端口)
adb forward tcp:23946 tcp:23946

# 查看已转发端口
adb forward --list
# 取消转发(填写PC端口)
adb forward --remove tcp:11111
adb forward —-remove-all

以上准备工作完成后便可通过IDA进行调试
一般情况下会将android server进行重命名,并自定义端口号运行。防止app进行进程名与默认端口号检测

动态调试

动态调试分为 Debug调试 与 普通调试。其中IDA调试栏选项的attach与run分别对应 附加进程 与 新建进程

Debug调试

脱壳或反调试时常用此方法

  • 挂起程序

    • 手机打开目标程序
    • 依次打开 IDA -> Go -> Debugger -> Attach -> Remote ARMLinux/Android debugger
    • 填写监听地址。由于端口转发到本机,Host填写127.0.0.1,Port填写转发到主机的端口后点击OK,弹出手机进程列表
    • 选择目标程序的运行进程,点击OK,完成进程附加
  • 加载目标SO文件

    • 依次打开 Debugger -> Debugger options...
    • 勾选三项
      • Suspend on process entry point (进程入口点挂起)
      • Suspend on thread start/exit (创建与退出线程时挂起)
      • Suspend on library load/unload (加载与卸载库时挂起)
    • 启动程序,图形按钮 或 快捷键F9
    • 等待目标so库加载请求的弹窗,关闭后在Module窗口中搜索目标so库,在目标so中搜索目标函数或JNI_Onload,双击后下断点。再F9运行

普通调试

  • 挂起程序

    • 通过jadx-gui打开app,在 Resources -> AndroidManifest.xml(配置清单)中查找make launch(搜索LAUNCHER),找到activity中的android:name=,得到app的包名+类名
    • 使用命令挂起程序
    adb shell am start -D -n <packageName>/.<className>
    
    • 执行完成后手机弹窗 Waiting For Debugger
  • 得到程序端口:打开DDMS窗口,debug图标(红色的bug)会出现在目标进程前,记录目标程序运行的端口号<port>

ddms
  • 依次打开 IDA -> Go -> Debugger -> Attach -> Remote ARMLinux/Android debugger。填写监听地址 127.0.0.1+转发端口

  • 选择目标程序的进行进程。勾选三项后F9让程序进入运行状态,此步骤与Debug调试一致

  • 目标程序跳过ddms断点继续运行,此处端口为ddms端口

jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1 port=<port>

此时ddms窗口中红色debug图标变为绿色,且ida可正常弹窗即将加载的so库,跳过弹窗使其正常加载。如需调试JNI_OnLoad或静态注册函数Java_*,先在函数中F2下断点后再F9运行

问题:

  • 打不开DDMS的办法
    • adb shell ps 得到进程PID<pid>
    • adb forward tcp:xxx jdwp:<pid>
    • 执行jdb
  • 调试时触发反调试或其他原因导致崩溃时重新调试
    • 从挂起程序开始
    • adb shell am start -D -n ...
    • 重新启动IDA并附加
    • 勾选三项后F9
    • 查看ddms中app端口是否变化
    • 进行放手操作jdb -connect ...

调试JNI_OnLoad

  • 在右侧Modules窗口中搜索目标so文件
  • 双击查看so中的函数,找到JNI_OnLoad。在汇编指令区F2下断点
  • 取消三项勾选,使so正常运行不被非断点打断
  • F9运行

动态调试时修改寄存器

在条件判断时,常需要手动修改寄存器的值。例如 反调试检测、会员检测 等,不符合条件会触发分支逻辑

CMP RO 0
BNE sub_xxx

通过在 寄存器窗口双击 或 快捷键E 进行修改

动态调试时修改指令

由于# 三级流水线的存在, 需在程序执行到前三条处指令前就完成对目标指令的修改

  • hex窗口中找到目标指令: 在执行到前三条时通过PC定位目标指令(选中目标指令 -> hex窗口右键 -> Synchronize with -> IDA View-PC)
  • 修改指令: 在hex窗口中快捷键F2进行编辑。编辑完成后使用快捷键F2进行保存。常改为全0使其变成NOP
  • 指令机器码计算: 查询《ARM指令》进行计算 或 使用https://armconverter.com/ ,输入目标指令和目标指令地址

ARM指令共32位(4字节)从高位到低位依次查询ARM指令。以跳转指令B为例说明计算方式

  • 4位(32-28): 条件。指令是否含有条件,如BNE中的NE
  • 3位(27-25): 固定为101
  • 1位(24): 是否带链接,如BL中的L
  • 余下24位(23-0): 目标地址与该指令的相对偏移量(相差多少条指令),即 ( <目标地址> - PC ) / 4(单条指令4字节) 。由于# 三级流水线,PC值比当前执行的指令多两条指令(即指令地址+8)
00001BD0  0B 00 00 0A  BEQ loc_1c04
; 偏移量为(0x1c04 - (0x1BD0+8)) / 4 = 11条 = 1011
; 0000 101 0 000000000000000000001011 -> 0A00000B -> 0B 00 00 0A (小端存放)

关于IDA调试时的几点

  • 断点的实现:在断点处设置一个异常,调试器对其进行捕获,从而使程序暂停到断点处

  • 勾选三项后的弹窗:找不到so的map文件(找不到so的调试符号信息,详情搜索调试符号),点击取消即可,不影响后期调试

  • 寄存器或CPSR中的值若为黑色,则说明指令执行后对应空间内存储的值未发生改变。否则为蓝色

  • 调试快捷键

    • F2: 下断点
    • F4: 执行至光标处
    • F7: 单步执行
    • F9: 继续运行
    • 寄存器快捷键E - 修改寄存器值
    • Ctrl + N: 设置PC
  • 关于汇编代码区颜色:

    • 黑色:可识别(可Tab得到C语言伪代码)
    • 红色:不可识别
  • 代码区常用快捷键

    • Tab:得到伪代码
    • D:选中代码识别成数据
    • U:选中代码识别成未识别数据
    • P:选中代码识别成函数(代码块)
    • C:选中代码识别成指令(行代码)因此经常先转化成代码(C)再将多条代码转化成函数(P)

动态调试时的CPSR窗口

对IDA动态调试时常用CPSR标识位的说明

  • N : 计算结果是否为负数
  • Z : 计算结果是否为0
  • C : 数值运算时是否出现进位或错位
  • T : 当前是否为Thumb指令集

调试可执行程序

初始流程与调试apk一致,运行android_server,启动端口转发

  • 点击菜单栏 Debugger -> Run -> Remote ARMLinux/Android debugger

  • Application 填写可执行文件的路径绝对路径

  • Directory 填写可执行文件所在文件夹的绝对路径

  • Parameters 填写可执行文件的运行参数。没有参数留空

  • Hostname 127.0.0.1

  • Post android_server转发端口

  • 依次打开 Debugger -> Debugger options... ,勾选三项

更多内容查看后续IDA相关的文章