一、题目背景
现代软件验证极少将私钥放在客户端,而是将 RSA 公钥以 PUBLICKEYBLOB 结构硬编码在程序数据段中,用于验证注册码(数字签名)。512 位的 RSA 凭个人电脑算力是无法爆破分解的,写注册机是死路一条。
实战中唯一的解法是:“偷梁换柱”——自己生成一对 RSA 密钥,在十六进制编辑器中找到官方公钥,将其 Patch(替换)成我们自己的公钥!
-
难度: ⭐⭐⭐⭐⭐(实战核心)
-
训练重点: 1. 识别 Windows
PUBLICKEYBLOB结构特征(RSA1魔数)。 2. 学会在二进制文件中进行数据段(.rdata)的十六进制替换。 3. 理解 OpenSSL 签名(大端序)与 Windows CryptoAPI(小端序)的字节序差异。
二、程序说明
-
平台: Win32 x86 / C++
-
目标: 程序要求输入授权目标
52XUEJISHU_VIP的 SHA-1 签名(128 字符的十六进制)。默认情况下,只有您(官方)有私钥能生成这串注册码。学员必须修改.exe文件替换公钥才能破解。
三、提示
第 1 步:认清 RSA 公钥的本质
不管公钥长什么样(PEM、DER 还是十六进制),在数学本质上,一个 RSA 公钥只包含两个数字:
E (Exponent / 指数):通常是固定的 65537(十六进制是 0x00010001)。
N (Modulus / 模数):两个大素数相乘的结果。因为您的密钥是 512 位,所以这个 N 刚好是 64 个字节长。
第 2 步:Windows 底层的“霸王条款” (PUBLICKEYBLOB)
在 Linux 或 OpenSSL 体系下,大家直接用上面的数据运算就行了。但是,Windows 的 CryptoAPI 极其傲娇,它不认识 PEM 字符串,它只认识一种叫做 PUBLICKEYBLOB 的内存结构。
这个结构是由微软在 wincrypt.h 中定死的,它分为三个部分,总长度刚好是 8 + 12 + 64 = 84 字节:
头部 1:BLOBHEADER (固定 8 字节)
告诉系统这是个什么玩意儿。
0x06:这是 PUBLICKEYBLOB(公钥块)。
0x02:版本号。
0x00 00:保留位。
0x00 00 24 00:代表 CALG_RSA_SIGN(用于签名的 RSA 算法)。
(对应了代码里的第 1 行)
头部 2:RSAPUBKEY (固定 12 字节)
定义 RSA 的具体参数。
0x52 0x53 0x41 0x31:魔数 "RSA1"(这四个字节的 ASCII 码就是 R, S, A, 1)。如果是私钥,这里就是 "RSA2"。
0x00 0x02 0x00 0x00:密钥长度。0x0200 等于十进制的 512 位。
0x01 0x00 0x01 0x00:指数 E。也就是 65537。
(对应了代码里的第 2、3 行)
核心数据:Modulus N (64 字节)
这里放的就是公钥里提取出来的那个巨型数字 N。
第 3 步:万恶之源 —— 字节序倒排 (小端序)
代码里的 N 和第一步里提取的 N,有一个惊人的秘密:它们是完全倒过来的
原本提取的 N 的开头是:C3 94 87 FB ...
原本提取的 N 的结尾是:... 51 90 CA F7 7B
C++ 代码里 N 的开头是:0x7b, 0xf7, 0xca, 0x90, 0x51 ...
为什么会这样?
这就是实战中无数新手踩坑的地方:
网络协议和 OpenSSL(PEM格式)使用的是 大端序 (Big-Endian),高位字节在前面。
Intel CPU 和 Windows CryptoAPI 要求必须使用 小端序 (Little-Endian),低位字节在前面!
所以,从 PEM 转换到 C++ 代码的最终奥义就是:
把 PEM 里的 64 字节 N 提取出来,然后把它整个倒序(Reverse)过来,贴到 PUBLICKEYBLOB 的尾部!
下载
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END









暂无评论内容