尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

【系列:CCG Crypto CrackMe 逆向全解析 · 第 11 篇(完结篇)】

【系列:CCG Crypto CrackMe 逆向全解析 · 第 11 篇(完结篇)】 导读前 10 篇我们完成了侦察、脱壳、算法识别、预言机验证和数据依赖分析每一步都在逼近真相但始终差最后一步把算法变成能用的 keygen。本篇补全最后的闭环——从 RSA 数学推导分解 64 位模数 N、计算私钥 d到 keygen 完整实现再到真实 GUI 里点击 Register 弹出 “Great / Successfully registered!”并用前导零证明本题多解的数学本质。系列收官全文无魔术每一步都有实证。这是整个系列的最后一篇。前 10 篇我们完成了侦察、脱壳、算法识别、预言机验证和数据依赖分析。每一步都在逼近真相但始终差最后一步把算法变成能用的 keygen。这一篇我们补全最后的闭环——从 RSA 数学推导到 keygen 完整实现再到 GUI 真实点击验证。数学推导从N到RSA私钥先回顾一下我们拿到的关键参数N 0xB80A90BF53C6C979 13261571204164536697 E 65537N 是 64 位的主要矛盾是分解它。工具跑分解很快结果是我们需要的两个素数因子p 3533507051 q 3753090347验证一下3533507051 × 3753090347 13261571204164536697 N完全吻合。有了 p 和 q欧拉函数就是PHI (p-1)*(q-1) 13261571196877939300注意这个数值是在纠正早期推导错误之后得到的最终正确值。私钥指数就是 E 在模 PHI 下的逆元RSA_D pow(E, -1, PHI) 164714877920238073从公开的 (N, E) 推出私钥 D靠的是 N 分解。这一步数学上没有任何悬念RSA 的安全性建立在大数分解困难之上而 64 位 N 对现代工具来说不过几秒的事。Keygen链路逐行拆解私钥到手keygen 就是流水线作业。完整链路如下M MD5(KCTF) 7a1ab1c6a2999f9797f5abd5b49fd9a0 M[0:8] → RC4(CONST_KEY) → d2e50dba45100b0f M[8:16] 97f5abd5b49fd9a0 (即 M2 10949847003367987616) D pow(M2, RSA_D, N) 5616897209861081805 Serial Base64(stage1 str(D)) 0uUNukUQCw81NjE2ODk3MjA5ODYxMDgxODA1第一段MD5(“KCTF”) 得到 32 个 hex 字符按 8 字节切成两段。第二段前 8 个字符交给固定密钥的 RC4 处理结果 d2e50dba45100b0f 拼在序列号前面。第三段后 8 个字符转成整数 M2 0x97f5abd5b49fd9a0。关键点来了——M2 10949847003367987616比 N 小满足 RSA 加密的输入条件。第四段私钥运算 pow(M2, RSA_D, N)得到 5616897209861081805。这一步在数学上是 RSA 签名在 CrackMe 验证逻辑里等价于解密。第五段Base64 编码拼接。stage1 和 D 的十进制字符串合并后整体编码得到最终 Serial。keygen.py 的核心逻辑就这几行。逐行解释后你会发现CrackMe 的算法还原到代码密度并没有想象中那么高。多解的数学形式前导零的秘密验证过程中我们发现一个有趣现象str(D) 前面补 0程序照样提示注册成功。数学上解释非常干净。设 D 是私钥运算的结果str(D) 是它的十进制表示。在前补 k 个 0得到的新字符串 S’ 0×k str(D)。关键点Base64 编码的是字符串的字节序列不是数值。补零改变了字节序列所以编码结果变了但补零不改变数值所以最终 Serial 在数学上与原值等价。实际测试三个变体全部通过验证pad‘’: 0uUNukUQCw81NjE2ODk3MjA5ODYxMDgxODA1pad‘0’: 0uUNukUQCw8wNTYxNjg5NzIwOTg2MTA4MTgwNQpad‘00’: 0uUNukUQCw8wMDU2MTY4OTcyMDk4NjEwODE4MDU三种编码完全不同但全部被程序接受。形式化表述设 f 为验证函数v ∈ V 为有效序列号集合。对任意 n ≥ 0有 f(Base64(stage1 0×n str(D))) 1。换言之{pad_k 0×k str(D)} 是一族无限多个互异但等价的合法输入。这就是本题多解的数学来源——不是漏洞是 Base64 编码层天然产生的等价类。GUI自动化同步与异步的生死线数学上解得完还要证明它在真实窗口里能跑通。这里踩了一个很典型的坑模态弹窗死锁。自动化的思路很直接FindWindowW 定位窗口FindWindowExW 拿控件句柄SendMessageW 写入文本再点 Register 按钮。窗口标题是 “CCG Crypto Crackme v1.0 — by blowfish”控件 ID 从反汇编确认Name0x3F0Serial0x3EF。关键抉择发生在点按钮这一步。一开始用 SendMessageW(BM_CLICK)程序直接卡死。原因很清晰SendMessageW 是同步的需要目标窗口处理完消息才返回而 Register 点击后会弹出模态对话框模态对话框内部有自己的消息循环导致外层窗口的消息处理被阻塞——你等我返回我等你的消息循环形成死锁。换成 PostMessageW(BM_CLICK) 就通了。PostMessageW 是异步的把消息丢进目标窗口的消息队列立刻返回不等待处理结果。配合 FindWindowW 轮询 “Great”/“Failed” 弹窗完美绕开死锁。SendMessageW(WM_SETTEXT) → 同步写入文本没问题 PostMessageW(BM_CLICK) → 异步点击避免模态死锁 FindWindowW 轮询结果弹窗 → 非阻塞等待GUI 验证的结果找到了 “Great / Successfully registered!” 弹窗。三层验证同一结论的三次证明到这一步我们有三个层次的证据相互独立指向同一个结论。第一层数学验证。pow(D, E, N) M2 成立。这证明 D 确实是 M2 的 RSA 签名/解密结果。密钥对构造无误私钥推导正确。第二层预言机验证。程序内部 Verify() 直接返回 1。这意味着不依赖任何外部推理程序自身的验证逻辑就接受了我们的序列号。这一层在第 9 篇完成。第三层GUI 真实点击验证。程序在真实窗口环境中弹出 “Great”。这不是模拟不是 hook是真实的消息驱动。三者的关系是层层递进数学证明理论上正确预言机证明算法上正确GUI 证明事实上正确。任何一层单独成立都有漏洞三层全过就说明没有漏洞。高亮一下第一层验证的细节pow(D, E, N) 的结果应该等于 M2。这里的 E 是公钥指数不是加密——这是签名校验的标准操作用公钥解密签名比对原文。系列全貌12篇逆向之旅回头看整个系列路径非常清晰侦察篇建立目标认知脱壳篇拿下保护层。算法识别篇定位核心逻辑预言机验证篇拿到程序内部的判定结果。数据依赖篇理清了输入输出间的关系。本篇完成数学补全把 keygen 从黑盒试探变成了白盒推导。从最初的二进制文件到最终的 GUI 弹窗确认——整个过程没有一步是魔术每一步都有实证支撑。说一下这 12 篇里最大的收获逆向工程的工作流是分层的。每一层解决一类问题层与层之间有明确接口。最重要的是每一层都要有验证手段否则前面的工作随时可能塌方。这次的 PHI 纠错就是一个教训——没有验证就永远不知道自己站在哪一层。写在最后Keygen 是整个逆向之旅的终点也是检验一切的试金石。从 2001 年作者 Blowfish 留下的这个 123,904 字节的二进制文件到最终在真实 GUI 里弹出 “Great / Successfully registered!”我们走完了完整的闭环侦察 → 脱壳 → 算法识别 → 预言机验证 → 数据依赖分析 → 数学推导 → 端到端确认。最终交付Name: KCTF Serial: 0uUNukUQCw81NjE2ODk3MjA5ODYxMDgxODA1验证方式crackme_crypto.exe运行时# 方法 1GUI 自动验证python verify_gui.py KCTF 0uUNukUQCw81NjE2ODk3MjA5ODYxMDgxODA1# 方法 2手动输入# Name 填 KCTFSerial 填上面的序列号点击 Register# 预期弹出 Great / Successfully registered!这个系列教会我们的远不止怎么破解一个老程序侦察永远比分析快——字符串和编译器元数据是不花力气的免费情报不要执着于标准做法——脱壳不一定要模拟执行ReadProcessMemory 更直接静态分析的结论必须有动态验证兜底——你永远可能在字节序、参数约定上出错最大的坑藏在理所当然的假设里——Verify() 用全局变量不用参数的陷阱正是被函数应该用参数这个假设蒙蔽的安全是相对的——64 位 RSA 在 2001 年也许够用现在几秒就能分解Happy reversing!参考文献与引用Rivest, Shamir, Adleman, “A Method for Obtaining Digital Signatures and Public-Key Cryptosystems” (1978)RSA 公钥加密与签名验证的原始论文Ronald Rivest, RFC 1321 - The MD5 Message-Digest Algorithmtools.ietf.org/html/rfc1321Microsoft Docs - SendMessage / PostMessagelearn.microsoft.com/windows/win32/winmsg——模态弹窗死锁的机理说明系列索引完第 1 篇PE 文件的物理事实——不猜测只解析第 2 篇字符串侦察——从 find() 命中到编译器身份识别第 3 篇BF2000 壳剖析上——节区伪装与 XOR 自解密第 4 篇BF2000 壳剖析下——反调试机制与放弃模拟第 5 篇不脱壳的脱壳法——ReadProcessMemory 实战第 6 篇算法指纹识别——从汇编中认出 MD5/RC4/RSA第 7 篇Verify() 完整调用流——6 个返回路径与参数陷阱第 8 篇预言机调试上——从进程崩溃到线程劫持第 9 篇预言机调试下——栈帧窥视与全局变量陷阱第 10 篇数据依赖图——为什么 Keygen 和 Verify 的顺序是反的第 11 篇RSA 数学推导与 Keygen 构造——破解闭环本文觉得有用点个关注持续获取逆向分析和安全技术干货。
返回列表