欢迎光临
我们一直在努力

【系列:CORE CrackMe3 破解全记录 · 第 3 篇】

导读: 上一篇文章我们成功将 CRACKME3.EXE 脱壳得到 dumped.bin。现在面对 229KB 的二进制文件,从哪下手?对于破解来说,最关键的一步就是找到验证函数的位置。 本文演示如何通过字符串搜索和交叉引用精准定位 CRACKME3 的验证逻辑,还原完整的 7 步验证流程,并揭示最易踩坑的用户名拼接逻辑。

关注我不迷路,最近会抽时间把自己十几年学习的东西逐步分享出来。

1. 搜索关键字符串

解包后的 dumped.bin 是一个完整的内存映像。第一步是用 Python 搜索成功/失败消息等字符串:

with open('dumped.bin', 'rb') as f:
data = f.read()

keywords = [b"join CORE", b"Welcome", b"Better luck",
b"first threshold", b"%lx%lx%lx", b"Failed"]
for kw in keywords:
off = data.find(kw)
if off >= 0:
print(f"0x{0x400000+off:06x}: {kw.decode()}")

这就是 CRACKME3 破解分析的起点——这些对话框里的文字,在代码中一定有对应的引用。找到引用这些字符串的代码,就等于找到了验证函数。

脱壳确认成功,关键字符串一览:

地址字符串作用
0x422520 %lx%lx%lx 序列号 sscanf 格式串
0x422560 "… good enough to join CORE! …" 成功消息
0x4225a0 Welcome 成功标题
0x422540 "… Better luck next time …" 失败消息
0x4224c0 "… first threshold …" 格式错误
0x422500 Failed 失败标题

这些字符串会被代码引用(xref)。例如 0x422560(成功消息)一定被某条 push 指令引用——找到所有这些引用,就能圈定验证函数的位置。

2. 交叉引用定位验证函数

通过 IDA Pro 或直接搜索二进制中对这些地址的引用,发现所有交叉引用都落在 0x4020a0 ~ 0x402408 区间。

这就是我们要分析的验证函数(validation function)。

3. 验证函数完整 7 步流程

通过反汇编,还原出完整的验证逻辑:

验证函数 0x4020a0 ~ 0x402408:

① 读取输入
GetDlgItemText(姓名框) → [ebp-0x608]
GetDlgItemText(序列号框) → [ebp-0x414]

② 用户名拼接
tmp = name → reverse(tmp) → name += tmp × 3 次

③-④ 注册表查询(对结果无影响)
RegQueryValueExA("Product") → NOT_FOUND
RegQueryValueExA("Registered") → NOT_FOUND

⑤ MD5 哈希计算
sub_4014e0 初始化上下文
sub_401500 分组处理 64 字节块
输出 A/B/C/D 四个 32 位哈希值

⑥ 解析序列号
sscanf(serial_buf, "%lx%lx%lx", &s0, &s1, &s2)
返回值必须 = 3,否则弹 "first threshold" 错误

⑦ 变换 + 比较
sub_401ad0 两次调用(线性变换)
s0' == A 且 s1'' == B 且 s2' == C → 成功
否则 → 失败

在这里插入图片描述

┌────────────────────────────────────────┐
│ ① 读取姓名和序列号 │
└────────────────┬───────────────────────┘

┌────────────────────────────────────────┐
│ ② 用户名拼接(reverse + strcat × 3) │
└────────────────┬───────────────────────┘

┌────────────────────────────────────────┐
│ ③-④ 查注册表(均不存在,无影响) │
└────────────────┬───────────────────────┘

┌────────────────────────────────────────┐
│ ⑤ MD5 哈希(16 字节输入 → 4 个 dword)│
└────────────────┬───────────────────────┘

┌────────────────────────────────────────┐
│ ⑥ sscanf 解析序列号(%lx%lx%lx) │
└────────────────┬───────────────────────┘

┌────────────────────────────────────────┐
│ ⑦ 变换后比较:s0'==A, s1''==B, s2'==C│
│ 全部相等 → Welcome 否则 → Failed │
└────────────────────────────────────────┘

4. 最易踩坑:用户名拼接逻辑

哈希函数计算的不是原始用户名,而是一段经过变换的字符串。汇编级还原如下:

; 复制 name 到 tmp
0x402151: lea esi, [ebp-0x220] ; tmp
0x402157: lea edi, [ebp-0x608] ; name
; 手动实现 strcpy(tmp, name)

; 反转 tmp
0x402168: lea eax, [ebp-0x220]
0x40216f: call sub_408d70 ; reverse(tmp)
; "KCTF" → "FTCK"

; name += tmp(追加反转后的结果)
0x402174: lea edi, [ebp-0x608] ; name
0x40218d: … strcat(name, tmp)
; "KCTF" + "FTCK" = "KCTFFTCK"

接着代码查询注册表值 “Product” 和 “Registered”——这两个值在正常的 Windows 系统中都不存在。查询失败后,tmp 缓冲区内容不变(仍是 “FTCK”),name 继续追加:

初始 name = "KCTF" len=4
tmp = reverse("KCTF") = "FTCK"

name += "FTCK" → "KCTFFTCK" len=8
RegQuery("Product") → NOT_FOUND
name += "FTCK" → "KCTFFTCKFTCK" len=12
RegQuery("Registered") → NOT_FOUND
name += "FTCK" → "KCTFFTCKFTCKFTCK" len=16

最终哈希输入: "KCTFFTCKFTCKFTCK"(16 字节)

在这里插入图片描述

关键注意: 哈希的输入是 "KCTFFTCKFTCKFTCK",不是 "KCTF"!如果在后续分析中搞错了这一步,计算出的序列号一定不对。

汇编验证

注册表查询失败时返回 2(NOT_FOUND),但代码并未检查返回值就直接继续执行——这是 C 风格代码中常见的"偷懒"写法:

0x4021d5: call RegQueryValueExA(…)
0x4021db: lea eax, [ebp-0x220] ; 不管返回值,直接追加
0x4021e1: push eax
0x4021e2: lea eax, [ebp-0x608]
0x4021e8: push eax
0x4021e9: call strcat ; name += tmp(始终是 "FTCK")

我们也可以在 PowerShell 中确认注册表值不存在:

reg query "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion" /v Product
# → 错误:系统找不到指定的注册表键或值


小结

破解 CRACKME3 的第二个关键节点已攻克。 我们已经:

  • 通过字符串搜索 + xref,定位 CRACKME3 验证函数在 0x4020a0~0x402408
  • 逆向还原了完整的 7 步验证流程:读输入→拼接→查注册表×2→MD5→sscanf→变换比较
  • 破解过程中最容易踩坑的发现:哈希的输入是 "KCTFFTCKFTCKFTCK"(16 字节),不是原始 "KCTF"
  • 注册表查询 “Product” 和 “Registered” 在正常系统上均不存在,不影响哈希输入

下篇预告:《MD5 哈希分析:标准算法背后的非标准细节》——CRACKME3 的哈希明明是标准 MD5,为什么算出的序列号在程序上全不对?一个导致所有前期工作白费的隐藏"quirk"即将揭晓。


参考文献与引用

  • Capstone 反汇编引擎:github.com/capstone-engine/capstone——用于验证 MD5 分组函数 sub_401500
  • pefile:github.com/erocarrera/pefile
  • IDA Pro 数据库:CRACKME3.EXE.i64——辅助反汇编与 xref 分析
  • Nolan Blender 分析(2000):fravia.accessroot.com/ccrack.htm——确认 CORE CrackMe3 的数学结构
  • 本系列上一篇:[Unicorn 模拟解包实战与代码分析]
  • 本系列下一篇:[MD5 哈希分析:标准算法背后的非标准细节]
赞(0)
未经允许不得转载:171主机测评 » 【系列:CORE CrackMe3 破解全记录 · 第 3 篇】
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址