|
对于16位DOS程序的逆向分析,特别是遇到`retf`指令后的定位问题,以下是详细解答和逆向步骤建议:
### 一、关于`retf`指令的定位方法
`retf`是远返回指令,会从栈中弹出**CS:IP**两个值作为返回地址。定位方法:
1. **静态分析栈操作**:
- 在`retf`前的代码中,观察`push`指令(尤其是`push cs`/`push offset`)
- 例如:
- push cs ; 将CS压栈
- push offset loc_1234 ; 将偏移地址压栈
- call sub_proc ; 调用子程序
- ...
- sub_proc proc far
- ...
- retf ; 此时会弹出CS和offset_loc_1234
复制代码
- 返回地址就是`push`的两个值组合(CS:offset)
2. **IDA交叉引用**:
- 在IDA中选中`retf`所在函数
- 按`Ctrl+X`查看交叉引用(Xrefs),找到所有`call`这个函数的位置
- 重点关注`call far ptr`指令(远调用)
3. **栈帧回溯**:
- 在函数开头找典型序言:
- 计算栈中参数/返回地址的位置:
返回地址IP = [bp+2]
返回段CS = [bp+4]
### 二、DOS程序逆向标准流程
#### 阶段1:前期准备
1. **运行程序观察行为**
- 在DOSBox中运行,记录输入/输出文件格式
- 尝试不同输入数据触发分支
2. **基础分析工具**
- IDA(静态反汇编)
- DOS调试器:DEBUG.EXE(动态跟踪)
- 二进制查看器:WinHex/HxD
#### 阶段2:关键功能定位
1. **定位文件I/O**
- 搜索`int 21h`中断:
- 文件打开:`mov ah, 3Dh`
- 文件读取:`mov ah, 3Fh`
- 文件关闭:`mov ah, 3Eh`
- 示例代码特征:
- mov dx, offset filename ; 文件名指针
- mov al, 0 ; 只读模式
- mov ah, 3Dh ; 打开文件
- int 21h
复制代码
2. **定位核心算法**
- 搜索浮点指令(Pascal常用):
- `FADD`/`FSUB`/`FMUL`/`FDIV`
- `FLD`/`FSTP`
- 搜索数据转换指令:
- `AAM`/`AAD`(BCD运算)
- `CBW`/`CWD`(符号扩展)
#### 阶段3:动态调试技巧(DEBUG.EXE)
1. **关键断点设置**:
- -g 程序入口点 ; 先运行到入口
- -b CS:IP ; 在文件读取函数设断点
- -g ; 执行到断点
复制代码
2. **绕过输入阻塞**:
- 在文件读取函数后断点
- 手动修改AX寄存器为文件句柄
- 提前准备输入文件到虚拟磁盘
#### 阶段4:Pascal程序特征
1. **函数识别**:
- 标准序言:`push bp` + `mov bp,sp`
- 参数访问:[bp+4]起(16位near call)
2. **运行时库函数**:
- 文件操作:`Assign`/`Reset`/`Rewrite`
- 数学函数:`Sqrt`/`Sin`等(搜索`call far ptr`到固定地址)
### 三、针对你的任务建议
1. **优先破解文件格式**
- 用不同数据生成输入文件
- 对比输出文件变化
- 逆向解析比逆向算法更简单
2. **分模块逆向**
- 主流程 → 文件读取 → 数据解析 → 计算核心 → 结果输出
复制代码
从两端(文件I/O)向中间(算法)推进
3. **实用技巧**:
- 在IDA中标记所有`int 21h`调用
- 对文件读写函数重命名(如`FileRead`)
- 记录浮点寄存器状态变化(`ST(0)-ST(7)`)
> 逆向本质:通过**数据流跟踪**(输入→处理→输出)和**控制流还原**(函数调用链)重建逻辑。遇到复杂算法时,先用黑盒测试推测数学关系,再验证反汇编结果。
建议从文件读取函数向后追踪,重点关注数据如何从文件缓冲区传递到计算模块。Pascal程序通常有清晰的模块边界,坚持每天分析2-3个函数,很快就能掌握全貌!
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 |
|