甲方IOS二进制入门记录
字数 1619 2025-08-25 22:59:03
iOS二进制安全入门教程
工具准备
核心工具列表
- dumpdecrypted: 用于对苹果加密的App进行砸壳
- class-dump: 导出MachO文件中ObjC类及方法定义
- CydiaSubstrate: 将第三方动态库注入进程
- Cycript: 使用JavaScript语法编写ObjC方法
- Theos: 越狱插件开发工具
- IDA: 反汇编、反编译工具
- Hopper: OSX反汇编、反编译工具
- Debugserver + LLDB: 动态调试器组合
ARM指令基础
寄存器与指令集
ARM是RISC架构,数据在内存和CPU之间移动只能通过L/S指令完成:
ldr: 把数据从内存移到CPUstr: 把CPU的数据转移到内存
寄存器用途
| 寄存器 | 用途 |
|---|---|
| R0-R3 | 用于函数参数及返回值的传递,超过4个参数时其他参数存在栈中 |
| R7 | 栈帧指针,指向母函数与被调用子函数在栈中的交界 |
| R13(SP) | 栈顶指针 |
| R14(LR) | 存放函数的返回地址 |
| R15(PC) | 指向当前指令地址 |
常用指令
ADC: 带进位的加法ADD: 加法AND: 逻辑与B: 分支跳转BL: 带返回的分支跳转BX: 带状态切换的分支跳转CMP: 比较值,结果存在程序状态寄存器BEQ/BNE: 结果为0/不为0则跳转LDR/LDRB/LDRH: 加载数据到寄存器MOV: 传送值/寄存器到另一个寄存器STR/STRB/STRH: 存储寄存器值到内存PUSH/POP: 堆栈操作
LLDB调试技巧
基本命令
image list -o -f: 查看进程在虚拟内存中相对模块基地址br s -a [addr]: 设置断点breakpoint delete <breakpoint>: 删除断点s/n: 源代码级单步执行si/ni: 汇编级单步执行(si进入函数,ni不进入)c: 继续执行p: 输出寄存器值register read --all: 读取所有寄存器内容
高级用法
- 在Object-C类所有函数设置断点:
breakpoint set -r '
\[ClassName .* \]
$'
2. **查看堆栈**:
```bash
bt // 查看堆栈
frame select <framenum> // 选择特定帧
- 内存操作:
memory read <start_address> <end_address> // 读取内存值 malloc_info -s <address> // 查看堆信息
Hopper与地址转换
地址转换公式
偏移后模块基地址 = 偏移前模块地址 + ALSR偏移
- 偏移前地址从Hopper查看
- ALSR偏移从LLDB获取
使用示例
- 在Hopper中找到方法偏移地址(如
0x14B6A66) - 获取ASLR偏移(如
0x30000) - 计算实际地址:
0x14B6A66 + 0x30000 = 0x14E6A66 - 在LLDB中设置断点:
br s -a 0x14E6A66
Cycript使用指南
基本操作
-
连接进程:
cycript -p <pid> -
查看UI层次:
[[UIApp keyWindow] recursiveDescription].toString() -
查看对象信息:
[#0x18b1c070 _ivarDescription].toString()
高级功能
-
查找类实例:
choose(ClassName) -
调用方法:
[#0x166b4fb0 show] // 调用实例方法 [ClassName classMethod] // 调用类方法 -
打印对象属性:
function tryPrintIvars(a){ var x={}; for(i in *a){ try{ x[i] = (*a)[i]; } catch(e){} } return x; }
调试流程
远程调试设置
-
端口映射:
iproxy 1234 1234 -
启动debugserver:
debugserver *:1234 -a <pid> -
LLDB连接:
process connect connect://localhost:1234
debugserver签名
- 获取ldid和ent.xml
- 签名:
ldid -Sent.xml debugserver - 上传到iOS设备
Objective-C运行时分析
方法调用原理
[person sayHello] 实际转换为:
objc_msgSend(person, @selector(sayHello))
函数原型:
id objc_msgSend(id self, SEL _cmd, ...)
方法返回值
- 单个返回值存储在R0寄存器
- 多个返回值通过栈返回
实用技巧
IDA命名约定
sub_xxx: 地址xxx处的子例程loc_xxx: 地址xxx处的指令byte_xxx: 位置xxx处的8位数据word_xxx: 位置xxx处的16位数据dword_xxx: 位置xxx处的32位数据
栈帧分析
- SP(stack pointer): 栈顶指针
- BP(base pointer): 栈基址指针
- 栈向下生长,用于存储自动变量和函数调用上下文