1. 逆向分析入门:攻防世界Replace题解
作为一个刚接触逆向工程的新手,我最近在攻防世界平台上尝试了一道名为"Replace"的题目。这道题虽然难度不高,但涵盖了逆向分析中的几个关键知识点,包括脱壳、静态分析和动态调试。下面我将详细记录解题过程,希望能给同样入门逆向的朋友一些参考。
1.1 初始文件分析
拿到题目文件后,我首先用file命令查看文件类型:
bash复制$ file Replace
Replace: PE32 executable (console) Intel 80386, for MS Windows
这是一个32位的Windows控制台程序。接着用Detect It Easy工具检查,发现程序使用了UPX加壳:
提示:UPX是一种常见的可执行文件压缩工具,加壳后的程序会在运行时解压自身代码。逆向分析前通常需要先脱壳。
1.2 UPX脱壳过程
使用UPX官方工具可以轻松脱壳:
bash复制$ upx -d Replace
脱壳后再次检查,确认已经是可分析的PE文件。用IDA Pro加载程序,可以看到清晰的函数调用关系。
2. 关键算法逆向分析
2.1 主逻辑定位
在IDA中搜索字符串引用,很快定位到关键函数sub_401090。这个函数负责验证用户输入:
c复制int __cdecl sub_401090(int a1)
{
// 输入处理逻辑
// ...
if ( (v11 + v12) ^ 0x19 == byte_4021A0[v13] )
return 1;
return 0;
}
2.2 算法逆向
核心验证逻辑可以简化为:
- 将输入字符两两一组处理
- 每组第一个字符转换为16进制高4位(v11)
- 每组第二个字符转换为16进制低4位(v12)
- 计算(v11 + v12) XOR 0x19
- 结果与预设数组byte_4021A0比较
用Python表示这个算法:
python复制def transform(a, b):
v11 = (ord(a) - 48) if a.isdigit() else (ord(a) - 87)
v12 = (ord(b) - 48) if b.isdigit() else (ord(b) - 87)
return (16 * v11 + v12) ^ 0x19
2.3 数据提取
在IDA中查看byte_4021A0数组:
python复制encrypted = [
99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43,
# ... 省略部分数据 ...
191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22
]
3. 逆向脚本编写
3.1 爆破思路
由于算法是可逆的,我们可以:
- 遍历所有可能的输入字符组合(ASCII 32-127)
- 计算transform(a,b)
- 检查结果是否在encrypted数组中
3.2 Python实现
python复制encrypted = [...] # 完整数组见上文
def find_possible_chars():
possible = {}
for c in encrypted:
for a in range(32, 128):
for b in range(32, 128):
if transform(chr(a), chr(b)) == c:
if c not in possible:
possible[c] = []
possible[c].append((a, b))
return possible
3.3 优化方案
上述方法时间复杂度较高(O(n^3)),可以优化:
- 预计算所有字符对的transform结果
- 建立结果到字符对的映射表
python复制from collections import defaultdict
reverse_map = defaultdict(list)
for a in range(32, 128):
for b in range(32, 128):
res = transform(chr(a), chr(b))
reverse_map[res].append((a, b))
4. 完整解题脚本
结合题目中的list1和list2数组,最终解题脚本如下:
python复制list1 = [50, 97, 52, 57, 102, 54, 57, 99, 51, 56, 51, 57, 53, 99, 100, 101, 57, 54, 100, 54, 100, 101, 57, 54, 100, 54, 102, 52, 101, 48, 50, 53, 52, 56, 52, 57, 53, 52, 100, 54, 49, 57, 53, 52, 52, 56, 100, 101, 102, 54, 101, 50, 100, 97, 100, 54, 55, 55, 56, 54, 101, 50, 49, 100, 53, 97, 100, 97, 101, 54]
list2 = [97, 52, 57, 102, 54, 57, 99, 51, 56, 51, 57, 53, 99, 100, 101, 57, 54, 100, 54, 100, 101, 57, 54, 100, 54, 102, 52, 101, 48, 50, 53, 52, 56, 52, 57, 53, 52, 100, 54, 49, 57, 53, 52, 52, 56, 100, 101, 102, 54, 101, 50, 100, 97, 100, 54, 55, 55, 56, 54, 101, 50, 49, 100, 53, 97, 100, 97, 101, 54]
list3 = [...] # 完整数组见上文
flag = ''
for i in range(35):
v8 = list1[2 * i]
v9 = v8 - 87 if v8 < 48 or v8 > 57 else v8 - 48
v10 = list2[2 * i]
v12 = v10 - 87 if v10 < 48 or v10 > 57 else v10 - 48
v4 = (16 * v9 + v12) ^ 25
flag += chr(list3.index(v4))
print(flag)
5. 逆向工程经验分享
5.1 常见问题排查
-
脱壳失败:
- 确保使用正确版本的UPX工具
- 某些修改版UPX需要特殊参数
-
IDA分析错误:
- 32位程序要用IDA 32位版本加载
- 遇到识别错误的函数可以手动创建
-
脚本运行报错:
- 检查Python版本(建议3.6+)
- 确保所有数组数据完整复制
5.2 效率优化技巧
-
使用Cython加速:
- 对计算密集型部分用Cython重写
- 可以获得10-100倍性能提升
-
多进程处理:
- 将爆破任务分配到多个CPU核心
- Python的multiprocessing模块简单易用
-
算法优化:
- 避免重复计算,多用查表法
- 减少不必要的循环嵌套
5.3 逆向学习建议
-
从简单题目入手:
- 先掌握基础PE结构
- 熟悉常见加密算法特征
-
工具链配置:
- IDA Pro + Hex-Rays
- x64dbg动态调试
- Python分析环境
-
社区资源:
- 多看writeup学习思路
- 参加CTF比赛积累经验
这道Replace题目虽然简单,但涵盖了逆向分析的完整流程。通过这次实践,我对Windows PE文件结构、UPX脱壳、静态分析和Python脚本编写都有了更深入的理解。逆向工程最重要的是耐心和细心,有时候一个字节的差异就会导致完全不同的结果。建议新手在学习过程中多动手实践,遇到问题时善用调试工具观察程序实际行为