[Reverse] 御网杯 rerere

👁 0 views
📅 2026-5-30 ⏱ 1 min 🏆 御网杯

rerere - CTF REVERSE Writeup

题目信息

  • 题目名:rerere
  • 分类:REVERSE
  • 难度:初级(150分)
  • 描述:re re re re re re

环境

  • 文件:rerere.exe,一个 64 位 Windows PE 文件
  • 运行后提示 Input: ,输入任意内容输出 Wrong!

逆向分析

1. 识别程序结构

用 capstone 反汇编 .text 段,识别出三个关键函数:

  • 输入函数 0x14FB:读取用户输入(fgets,缓冲区在 [rsp+0x20],读取 0x40=64 字节),然后调用验证函数
  • 验证函数 0x1480:对输入逐字节校验
  • 主函数:调用输入函数,根据返回值打印 Correct!Wrong!

2. 分析验证算法(函数 0x1480)

关键反汇编代码:

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 字节的目标值

3. 提取数据

.rdata 段(VA=0x4000,文件偏移=0x2200)提取:

  • S-box(256字节,RVA 0x4060 → 文件偏移 0x2260)
  • 密钥(8字节,RVA 0x4048 → 文件偏移 0x2248):b9 cd ce 30 b8 61 4e aa
  • 期望输出(38字节,RVA 0x4020 → 文件偏移 0x2220)

4. 逆向求解

由于 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)

5. 结果

FLAG: flag{7fa6888d8465734047572ccf7a140b74}

6. 验证

输入该 flag 到程序,输出 Correct!,确认正确。


总结: 这是一个经典的 XOR + S-box 逆向题。程序将输入与循环密钥 XOR 后通过查找表变换,再与期望值比较。逆向只需反查查找表 + 异或即可还原输入。