安卓学习思路方法总结(七)
字数 1931 2025-08-09 13:33:35

ARM架构安卓动态调试与静态分析教程

环境搭建与准备

调试环境配置

  1. 连接真机调试

    • 上传IDA中的android_server到安卓设备
    • 切换root权限运行程序:adb shell su -c "/data/local/tmp/android_server"
    • 端口转发:adb forward tcp:23946 tcp:23946
  2. 安装APK

    • 使用命令:adb install C:\javandk1.apk
    • 如果已安装可跳过此步骤
  3. 启动调试模式

    • 挂起程序:adb shell am start -D -n com.example.javandk1/.MainActivity
    • 使用DDMS查看进程状态(变红色表示已挂起)
  4. IDA连接

    • 启动IDA Debugger
    • 搜索并选择目标安卓程序
    • 设置断点后按F9运行
  5. 附加jdb调试器

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

ARM指令集基础

关键概念

  1. 条件码表:ARM指令可条件执行,根据条件码决定是否执行

  2. 三级流水线:ARM处理器采用取指、译码、执行三级流水线

  3. 数据存储格式

    • 小端模式:低位在前,高位在后
    • 大端模式:高位在前,低位在后
    • ARM通常采用小端模式
  4. 寄存器与内存

    • 32位系统可处理4GB内存(2^32)
    • 一个字节=8位,四个字节=32位
    • 一个十六进制数=4位,两个十六进制数=1字节

常用指令解析

  1. LDR指令

    • 格式:LDR Rd, [Rn, #offset]
    • 功能:将内存地址Rn+offset处的数据加载到寄存器Rd
  2. STR指令

    • 格式:STR Rd, [Rn, #offset]
    • 功能:将寄存器Rd的值存储到内存地址Rn+offset
  3. MOV/MOVT指令

    • MOV:移动低16位
    • MOVT:移动高16位(T表示Top)
  4. ADD/SUB指令

    • ADD:加法运算
    • SUB:减法运算
  5. BLX/BL/BX指令

    • BLX:带链接和状态切换的跳转(会改变LR和PC,可能改变T标志)
    • BL:带链接的跳转(改变LR和PC)
    • BX:带状态切换的跳转(改变PC和T标志)
  6. STMFD/LDMED指令

    • STMFD(Store Multiple Full Descending):多寄存器存储,满递减堆栈
    • LDMED(Load Multiple Empty Descending):多寄存器加载,与STMFD对应

动态调试实战

调试流程

  1. 下断点

    • 在目标位置设置断点
    • 按F9运行到断点处
  2. 单步调试

    • F7:单步步入(进入函数调用)
    • F8:单步步过(不进入函数调用)
    • ESC:从当前函数返回
  3. 寄存器窗口观察

    • 观察PC(程序计数器)、LR(链接寄存器)、SP(栈指针)等关键寄存器变化
    • 注意T标志位变化(表示Thumb/ARM模式切换)
  4. 栈操作分析

    • 栈指针SP变化示例:
    原SP: FFEE2B60
    新SP: FFEE2B5C (60-4)
    计算过程:6×16+0=96 → 96-4=92 → 92/16=5余12 → 5C
    

调试示例分析

  1. 第一条指令

    • LDR R0, [R3]
    • 将R3指向的内存值加载到R0
    • 执行后:R0=F54BC000, R3=00000001
  2. 栈操作指令

    • STR LR, [SP, #var_4]!
    • 将LR的值存储到SP-4的位置,并更新SP
    • 栈变化:FFEE2B60 → FFEE2B5C
  3. 跳转指令

    • BLX R3
    • 带链接和状态切换的跳转
    • 会改变LR和PC,可能改变T标志位

静态so库分析

分析流程

  1. 加载so文件

    • 直接将so文件拖入IDA
    • 使用空格键在流程图和文本视图间切换
  2. 关键指令解析

    • 偏移量计算:

      LDR R2, =(aAge - 0x1288)
      

      双击aAge查看实际地址(如00002C34),然后计算偏移量

    • PC相对寻址:

      ADD R2, PC, R2
      

      计算当前PC值加上R2中的偏移量,得到实际地址

  3. 函数调用分析

    • 注意BLX/BL指令后的寄存器变化
    • 跟踪参数传递(通常R0-R3用于参数传递)

示例分析

  1. 字符串加载

    LDR R2, =(aAge - 0x1288)  ; aAge地址为00002C34
    ADD R2, PC, R2            ; PC+偏移量得到实际地址
    

    最终R2指向字符串"age"

  2. 方法调用

    BLX R3
    
    • 跳转到R3指向的地址
    • 调用后R0通常包含返回值

总结与技巧

  1. 调试技巧

    • 栈指针变化计算要熟练掌握十六进制运算
    • 注意T标志位变化对指令解码的影响
    • 重新下断点可按F9快速跳转到目标位置
  2. 分析技巧

    • 静态分析时注意PC相对寻址的计算
    • 跟踪字符串和方法的交叉引用
    • 结合动态调试验证静态分析结果
  3. 常见模式

    • 方法调用前通常会有参数设置(R0-R3)
    • 返回值通常存放在R0
    • 栈操作遵循满递减模式(STMFD/LDMED)

通过本教程,您应该掌握了ARM架构下的安卓应用动态调试和静态分析的基本方法,包括环境搭建、指令解析、寄存器观察和栈操作分析等关键技能。

ARM架构安卓动态调试与静态分析教程 环境搭建与准备 调试环境配置 连接真机调试 : 上传IDA中的 android_server 到安卓设备 切换root权限运行程序: adb shell su -c "/data/local/tmp/android_server" 端口转发: adb forward tcp:23946 tcp:23946 安装APK : 使用命令: adb install C:\javandk1.apk 如果已安装可跳过此步骤 启动调试模式 : 挂起程序: adb shell am start -D -n com.example.javandk1/.MainActivity 使用DDMS查看进程状态(变红色表示已挂起) IDA连接 : 启动IDA Debugger 搜索并选择目标安卓程序 设置断点后按F9运行 附加jdb调试器 : jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8600 ARM指令集基础 关键概念 条件码表 :ARM指令可条件执行,根据条件码决定是否执行 三级流水线 :ARM处理器采用取指、译码、执行三级流水线 数据存储格式 : 小端模式:低位在前,高位在后 大端模式:高位在前,低位在后 ARM通常采用小端模式 寄存器与内存 : 32位系统可处理4GB内存(2^32) 一个字节=8位,四个字节=32位 一个十六进制数=4位,两个十六进制数=1字节 常用指令解析 LDR指令 : 格式: LDR Rd, [Rn, #offset] 功能:将内存地址 Rn+offset 处的数据加载到寄存器Rd STR指令 : 格式: STR Rd, [Rn, #offset] 功能:将寄存器Rd的值存储到内存地址 Rn+offset 处 MOV/MOVT指令 : MOV:移动低16位 MOVT:移动高16位(T表示Top) ADD/SUB指令 : ADD:加法运算 SUB:减法运算 BLX/BL/BX指令 : BLX:带链接和状态切换的跳转(会改变LR和PC,可能改变T标志) BL:带链接的跳转(改变LR和PC) BX:带状态切换的跳转(改变PC和T标志) STMFD/LDMED指令 : STMFD(Store Multiple Full Descending):多寄存器存储,满递减堆栈 LDMED(Load Multiple Empty Descending):多寄存器加载,与STMFD对应 动态调试实战 调试流程 下断点 : 在目标位置设置断点 按F9运行到断点处 单步调试 : F7:单步步入(进入函数调用) F8:单步步过(不进入函数调用) ESC:从当前函数返回 寄存器窗口观察 : 观察PC(程序计数器)、LR(链接寄存器)、SP(栈指针)等关键寄存器变化 注意T标志位变化(表示Thumb/ARM模式切换) 栈操作分析 : 栈指针SP变化示例: 调试示例分析 第一条指令 : LDR R0, [R3] 将R3指向的内存值加载到R0 执行后:R0=F54BC000, R3=00000001 栈操作指令 : STR LR, [SP, #var_4]! 将LR的值存储到SP-4的位置,并更新SP 栈变化:FFEE2B60 → FFEE2B5C 跳转指令 : BLX R3 带链接和状态切换的跳转 会改变LR和PC,可能改变T标志位 静态so库分析 分析流程 加载so文件 : 直接将so文件拖入IDA 使用空格键在流程图和文本视图间切换 关键指令解析 : 偏移量计算: 双击aAge查看实际地址(如00002C34),然后计算偏移量 PC相对寻址: 计算当前PC值加上R2中的偏移量,得到实际地址 函数调用分析 : 注意BLX/BL指令后的寄存器变化 跟踪参数传递(通常R0-R3用于参数传递) 示例分析 字符串加载 : 最终R2指向字符串"age" 方法调用 : 跳转到R3指向的地址 调用后R0通常包含返回值 总结与技巧 调试技巧 : 栈指针变化计算要熟练掌握十六进制运算 注意T标志位变化对指令解码的影响 重新下断点可按F9快速跳转到目标位置 分析技巧 : 静态分析时注意PC相对寻址的计算 跟踪字符串和方法的交叉引用 结合动态调试验证静态分析结果 常见模式 : 方法调用前通常会有参数设置(R0-R3) 返回值通常存放在R0 栈操作遵循满递减模式(STMFD/LDMED) 通过本教程,您应该掌握了ARM架构下的安卓应用动态调试和静态分析的基本方法,包括环境搭建、指令解析、寄存器观察和栈操作分析等关键技能。