yonkies_crackme2 writeup 及代码复用(编译成动态链接库)的技巧
字数 1562 2025-08-30 06:50:12
yonkies_crackme2 逆向分析与代码复用技术详解
1. 程序概述
yonkies_crackme2 是一个包含AES加密算法的逆向分析题目,主要考察对标准加密算法的识别能力和二进制层面的代码复用技巧。
2. 主程序分析
2.1 主函数结构
主函数逻辑清晰:
- 使用
fgets从文件中读取一行输入 - 调用
FUN_00401280进行正则表达式匹配 - 调用
FUN_00401312从正则匹配结果中提取数据 - 调用
CheckNameKey函数进行用户名和密钥的校验
2.2 关键校验函数 CheckNameKey
2.2.1 密钥预处理
- 将输入的密钥字符串转换为16进制字节串
2.2.2 密钥初步校验
- 检查前12字节的和:
- 和的低8位必须等于key[15]
- 和的高8位必须等于key[14]
2.2.3 固定随机数生成
srand(0x12345678); // 固定种子
生成的固定随机数序列:
[0xE9,0x3F,0x0D,0xA1,0x96,0x95,0x31,0x04,0x49,0x2D,0x9E,0x61,0x83,0xCF,0x09,0x6F]
2.2.4 AES解密过程
FUN_00408d24: AES密钥扩展函数FUN_0040a1b6: AES解密函数
2.2.5 解密后数据校验
解密后的16字节数据结构:
| 字段 | 长度 | 说明 |
|---|---|---|
| username hash | 4 | 用户名通过FUN_00401000计算的hash值 |
| feature | 2 | 16位特性标志,每bit代表一个特性 |
| magic | 2 | 固定值0x1979 |
| 序列号 | 4 | 任意值,仅展示 |
| 填充 | 4 | 用于满足密钥校验条件 |
3. 密钥生成(Keygen)实现
3.1 密钥生成思路
- 构造16字节明文数据
- 使用固定密钥进行AES加密
- 暴力尝试填充字段,使加密结果满足校验条件
3.2 C语言实现注意事项
- 架构问题:32位程序在64位系统上运行需要i386子系统
- AES库更新:需要添加
aes_ni.h支持硬件加速 - ASLR问题:32位程序在amd64架构下可能需要关闭ASLR
3.3 Python实现方案
3.3.1 代码复用技术
将FUN_00401000编译为32位共享库(.so),通过以下方式调用:
- 使用32位Python通过ctypes加载
- 64位Python通过subprocess调用32位Python获取结果
3.3.2 实现步骤
- namehash.asm:将目标函数编译为共享库
section .text
global function
function:
; 函数汇编代码
ret
编译命令:
nasm -f elf32 namehash.asm -o namehash.o
gcc -m32 -shared namehash.o -o libnamehash.so
- namehash.py:32位Python调用库
from ctypes import CDLL, c_char_p, c_uint32
lib = CDLL('./libnamehash.so')
lib.function.restype = c_uint32
def get_name_hash(username):
return lib.function(c_char_p(username.encode()))
- keygen.py:主程序
import subprocess
def get_name_hash_32bit(username):
cmd = ['python3.4', 'namehash.py', username]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
return int(proc.stdout.read())
# 其余AES加密和校验逻辑
4. 二进制代码复用技术深入
4.1 适用条件
- 函数代码只使用寄存器和栈变量
- 无外部变量访问或远程调用
- 明确知道函数参数和返回值类型
4.2 实现方案比较
方案1:直接二进制加载
- 优点:同一进程内调用,效率高
- 缺点:需要处理重定位,仅适合简单算法
方案2:进程注入
- 优点:通用性强
- 缺点:受操作系统和架构限制
4.3 实践建议
- 优先考虑将目标函数编译为共享库
- 跨架构时使用进程间通信
- 复杂函数建议重写而非复用
5. 总结
通过分析yonkies_crackme2,我们学习了:
- AES标准算法的识别技巧
- 二进制层面的代码复用方法
- 跨架构编程的解决方案
- 密钥生成器的实现思路
关键点:
- 注意标准算法的特征常数
- 代码复用要考虑架构兼容性
- Python的subprocess是解决跨架构问题的有效工具
6. 参考资源
- Brian Gladman's AES实现
- NASM汇编器文档
- Python ctypes官方文档