rerere.exe,一个 64 位 Windows PE 文件Input: ,输入任意内容输出 Wrong!用 capstone 反汇编 .text 段,识别出三个关键函数:
0x14FB:读取用户输入(fgets,缓冲区在 [rsp+0x20],读取 0x40=64 字节),然后调用验证函数0x1480:对输入逐字节校验Correct! 或 Wrong!关键反汇编代码:
0x1480: push rbx
0x1481: test edx, edx ; edx = 输入长度
0x1483: jle 0x14ed ; 长度<=0则返回1(正确)
0x1485: movsxd rdx, edx
0x1488: mov r8d, 0 ; r8 = 循环计数器 i
0x148e: lea r11, [rip+0x2bcb] ; r11 = S盒/查找表 (256字节)
0x1495: lea r10, [rip+0x2bac] ; r10 = 密钥 (8字节)
0x149c: lea r9, [rip+0x2b7d] ; r9 = 期望输出 (38字节)
; 循环体:
0x14c0: mov rax, r8 ; rax = i
0x14c3: and eax, 7 ; rax = i % 8
0x14c6: movzx eax, byte[r10+rax] ; eax = key[i%8]
0x14cb: xor al, byte[rcx+r8] ; al = input[i] ^ key[i%8]
0x14cf: movzx eax, al
0x14d2: movzx ebx, byte[r9+r8] ; bl = expected[i]
0x14d7: cmp byte[r11+rax], bl ; lookup[input[i]^key[i%8]] == expected[i] ?
0x14db: jne 0x14f4 ; 不等则返回0(错误)
0x14dd: add r8, 1 ; i++
0x14e1: cmp r8, rdx
0x14e4: jne 0x14c0
算法总结:
expected[i] = lookup[ input[i] XOR key[i%8] ]
其中:
key 是 8 字节的循环密钥lookup 是 256 字节的 S-box 查找表expected 是 38 字节的目标值从 .rdata 段(VA=0x4000,文件偏移=0x2200)提取:
b9 cd ce 30 b8 61 4e aa由于 S-box 是一个 256→256 的映射(双射),可以构建逆查找表:
data = open('rerere.exe','rb').read()
key = list(data[0x2248:0x2248+8])
expected = list(data[0x2220:0x2220+38])
lookup = list(data[0x2260:0x2260+256])
# 构建逆查找表
reverse = {}
for v in range(256):
r = lookup[v]
if r not in reverse:
reverse[r] = []
reverse[r].append(v)
# 逆推 flag
flag = ''
for i in range(38):
kb = key[i % 8]
eb = expected[i]
for v in reverse[eb]:
c = v ^ kb
if 32 <= c <= 127: # 可打印字符
flag += chr(c)
break
print('FLAG:', flag)
FLAG: flag{7fa6888d8465734047572ccf7a140b74}
输入该 flag 到程序,输出 Correct!,确认正确。
总结: 这是一个经典的 XOR + S-box 逆向题。程序将输入与循环密钥 XOR 后通过查找表变换,再与期望值比较。逆向只需反查查找表 + 异或即可还原输入。