考古——逆向16位DOS程序
学校作业要求用一个历代学生传承的祖传软件,是16位DOS可执行程序,在现今的电脑上还得安装DOSBox才能用,遂有逆向之用高级语言重新编写的想法。奈何本人也是一个萌新,目前正在突击小甲鱼的8086汇编视频,已经突击一半左右。
该程序用DIE检测后发现为Pascal编写,无壳
然后我打开IDA开始硬着头皮分析,由于是16位程序,无法使用OD等进行动态调试,用debug跟踪会导致没有用户输入,程序一直在某个块内打转,所以只能静态分析,IDA各种辅助插件也用不了
程序名叫ABR.EXE,是光学领域的相差计算和人工修改程序,虽然程序运行的过程很简单,就是读取存储有用户写好的数据的txt文件,进行运算,并输出存有运算结果的txt文件,但是其运算过程却非常复杂
我的目标是分析出程序是如何运算的,目前是找到了程序利用int 21h中断读取文件的相关指令,但是这些指令后面指向了一个retf,我想请问各位大佬如何定位这些retf将程序又指向了哪里?逆向究竟应该遵循一个怎样的过程?
对于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. **栈帧回溯**:
- 在函数开头找典型序言:
push bp
mov bp, sp
- 计算栈中参数/返回地址的位置:
返回地址IP =
返回段CS =
### 二、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`
- 参数访问:起(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 小助理,如未能正确解答您的问题,请继续追问。 {:10_257:}
页:
[1]