一道CTF解题之旅
字数 949 2025-08-15 21:30:57
CTF解题教学:nsPack壳脱壳与异或加密逆向分析
1. 题目概况
- 来源:攻防世界Reserve:040
- 难度:★★★
- 保护措施:nsPack压缩壳
- 程序类型:Win32控制台程序
- 加密方式:异或加密
2. 脱壳过程详解
2.1 侦壳
使用侦壳工具确认程序使用了nsPack压缩壳。
2.2 使用OllyDbg(OD)脱壳
-
初始加载:
- 使用OD载入程序
- 观察压缩壳标志性指令
pushad - 按F8单步两步,注意只有ESP寄存器发生变化
-
ESP定律脱壳法:
- 在ESP所在的内存地址下硬件访问断点
- 按F9运行程序
- 程序会在
popfd指令处停下(与前面的pushad对应) - 观察下方的
jmp指令,这是跳回程序原始入口点(OEP)的指令
-
Dump内存:
- 到达OEP后,右键选择"dump内存"
- 点击"获取EIP作为OEP"
- 重要:记录修正后的地址,后续修复导入表需要
-
修复导入表:
- 使用导入表修复工具
- 选择之前保存的脱壳文件
- 按照工具指引完成修复
2.3 脱壳总结
脱nsPack压缩壳的三个关键步骤:
- 找到OEP地址
- dump内存
- 修复导入表
3. 逆向分析
3.1 IDA静态分析
-
输入验证:
- 输入字符串长度必须大于0x2A(42)字节
-
加密方式:
- 使用异或加密
- 加密后需要再次异或相同值才能解密
3.2 OD动态调试
- 关键数据:
- 异或使用的密钥字符串:"this_is_not_flag"
- 比较的密文字符串:正好0x2A(42)字节
4. 解题脚本
void DecodeCTF40() {
char Str[] = {
0x12, 0x04, 0x08, 0x14, 0x24, 0x5C, 0x4A, 0x3D, 0x56, 0x0A,
0x10, 0x67, 0x00, 0x41, 0x00, 0x01, 0x46, 0x5A, 0x44, 0x42,
0x6E, 0x0C, 0x44, 0x72, 0x0C, 0x0D, 0x40, 0x3E, 0x4B, 0x5F,
0x02, 0x01, 0x4C, 0x5E, 0x5B, 0x17, 0x6E, 0x0C, 0x16, 0x68,
0x5B, 0x12
};
char keyStr[] = "this_is_not_flag";
int keyCount = 0;
for(int i = 0; i <= 0x2A; ++i) {
keyCount = i % 16;
Str[i] ^= keyStr[keyCount];
printf("%c", Str[i]);
}
}
脚本解析:
- 密文数据:42字节的加密数据
- 密钥:"this_is_not_flag"(16字节)
- 解密逻辑:
- 循环处理每个密文字节
- 使用
i % 16循环使用密钥的每个字符 - 密文字节与密钥字符异或得到明文
- 直接输出解密结果
5. 关键知识点总结
-
nsPack壳特征:
- 标志性指令
pushad - 使用ESP定律是最有效的脱壳方法
- 标志性指令
-
脱壳三要素:
- 准确找到OEP
- 完整dump内存
- 正确修复导入表
-
异或加密特点:
- 可逆性:A ^ B ^ B = A
- 密钥循环使用:当密钥比明文短时,通常会循环使用
-
CTF解题技巧:
- 静态分析与动态调试结合
- 注意程序对输入长度的验证
- 识别加密模式(本例为简单的异或加密)