逆向新手也能懂:用Python脚本5分钟搞定BUUCTF的XOR逆向题
逆向新手也能懂:用Python脚本5分钟搞定BUUCTF的XOR逆向题
第一次接触CTF逆向题时,看到满屏的十六进制和反汇编代码,我的大脑就像被XOR加密过一样混乱。特别是那道经典的BUUCTF XOR题目,明明知道原理却不知从何下手。直到我发现了Python脚本这个"解密神器"——原来只需要5分钟,就能让复杂的逆向过程变得像搭积木一样简单。
1. 逆向工程中的XOR:从原理到实战
异或(XOR)这个在密码学中看似简单的运算符,却让无数逆向新手在BUUCTF的题目前折戟。它的魅力在于:加密和解密可以使用相同的操作。具体来说:
A ^ B = C C ^ B = A在逆向题目中,常见的套路是:
- 程序要求输入flag
- 对输入的每个字符进行某种XOR运算
- 将结果与预设的全局变量比较
理解这个模式后,我们就能用Python"以彼之道还施彼身"。比如下面这个典型的XOR链式加密:
# 加密过程示例 flag = "flag{this_is_test}" encrypted = [ord(flag[0])] for i in range(1, len(flag)): encrypted.append(ord(flag[i]) ^ encrypted[i-1])2. 逆向分析四步走:从IDA到Python
2.1 识别关键逻辑
用IDA打开题目文件后,在main函数中通常会看到这样的关键判断:
- 输入长度检查(比如必须33字节)
- 对输入的字符进行XOR运算
- 与全局变量(如global数组)比较
关键技巧:在IDA中双击global变量,按Shift+E可以导出十六进制数组,这是我们解题的"金钥匙"。
2.2 数据提取与转换
从IDA获取的原始数据通常是这样的形式:
0x66, 0x0A, 0x6B, 0x0C, 0x77, 0x26, 0x4F, 0x2E...我们需要将其转换为Python可处理的列表:
_global = [ 0x66, 0x0A, 0x6B, 0x0C, 0x77, 0x26, 0x4F, 0x2E, 0x40, 0x11, 0x78, 0x0D, 0x5A, 0x3B, 0x55, 0x11, 0x70, 0x19, 0x46, 0x1F, 0x76, 0x22, 0x4D, 0x23, 0x44, 0x0E, 0x67, 0x06, 0x68, 0x0F, 0x47, 0x32, 0x4F, 0x00 ]注意:最后一个字节通常是0x00,表示字符串结束符,处理时可能需要特殊考虑。
2.3 逆向脚本编写
根据正向加密的逻辑,逆向解密只需要"倒着来":
flag = chr(_global[0]) # 第一个字符不变 for i in range(1, len(_global)-1): # 忽略末尾的0x00 flag += chr(_global[i] ^ _global[i-1]) print(flag)为什么这样可行?因为:
- 加密时:
enc[i] = flag[i] ^ enc[i-1] - 解密时:
flag[i] = enc[i] ^ enc[i-1]
2.4 常见问题排查
新手常遇到的坑:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 输出乱码 | 数组长度不对 | 检查是否包含/排除了0x00 |
| 报错IndexError | 数组索引越界 | 确认range范围是否正确 |
| 部分字符错误 | 数据类型混淆 | 确保使用ord()/chr()转换 |
3. 进阶技巧:处理变种XOR题目
不是所有XOR题都这么"友好"。以下是几种变种及应对策略:
3.1 多轮XOR加密
有些题目会进行多次XOR运算,比如:
# 加密过程 for i in range(len(flag)): encrypted[i] = flag[i] ^ key[i%len(key)] encrypted[i] ^= 0x55解密时需要逆向操作顺序:
# 解密过程 for i in range(len(encrypted)): decrypted = encrypted[i] ^ 0x55 flag += chr(decrypted ^ key[i%len(key)])3.2 动态密钥XOR
密钥可能随时间或输入变化,例如:
// 伪代码 key = time() % 256; for(i=0; i<len; i++){ out[i] = input[i] ^ (key + i); }对应的Python解密:
# 假设已知key的生成逻辑 for i in range(len(encrypted)): flag += chr(encrypted[i] ^ (key + i))4. 实战演练:BUUCTF XOR题完整解
让我们用完整案例演示解题流程:
文件分析
- 使用file命令查看文件类型
- 用IDA Pro加载文件,搜索字符串"Success"定位关键代码
逻辑分析
- 发现输入长度需为33
- 每个字符与前一个字符异或
- 结果与global数组比较
数据提取
- 在IDA中定位global数组
- 导出十六进制值到Python列表
脚本编写
_global = [ 0x66, 0x0A, 0x6B, 0x0C, 0x77, 0x26, 0x4F, 0x2E, 0x40, 0x11, 0x78, 0x0D, 0x5A, 0x3B, 0x55, 0x11, 0x70, 0x19, 0x46, 0x1F, 0x76, 0x22, 0x4D, 0x23, 0x44, 0x0E, 0x67, 0x06, 0x68, 0x0F, 0x47, 0x32, 0x4F, 0x00 ] flag = chr(_global[0]) for i in range(1, len(_global)-1): flag += chr(_global[i] ^ _global[i-1]) print("Flag:", flag)结果验证
- 运行脚本获取flag
- 检查flag格式是否符合常见CTF规则(如以flag{开头)
在逆向工程中,XOR就像一把双刃剑——既是简单的加密手段,也是最容易破解的弱点之一。当我第一次用Python脚本成功还原出flag时,那种"原来如此"的顿悟感,正是CTF比赛最迷人的地方。
