
一个 Windows XP / Windows Server 2003 VLK 密钥生成器。该工具允许你基于 Raw Product Key 生成 有效的 Windows XP 密钥,而 Raw Product Key 可以是随机的。
Raw Product Key (RPK) 以 9 位数字 XXX-YYYYYY 的形式提供,并且仅在生成 Windows XP 密钥时才需要。

前往 Releases 标签页,从那里下载最新版本。
这个项目还没有死——我会尽我所能把它做出来。
一般来说,阻碍我们为每个版本(EVERY EDITION)和每个构建(EVERY BUILD)生成有效的 Windows XP 密钥的唯一因素,是缺少从 pidgen.dll 中的公钥对应生成的私钥。网上没有广泛可用的椭圆曲线离散对数函数代码,只有关于如何实现它的模糊信息。
随着时间推移,这个问题已经_部分_解决了。
BINK 资源没有以任何方式编码,数据只是按顺序写入资源。sk00ter 还在 MDL 论坛上完整解释了 BINK 格式。 利用社区先前关于这个主题的知识,我用 Python 3 编写了一个 BINK Reader。该文件在本仓库中公开,点击这里查看源代码。
截至 2023 年 5 月 28 日,离散对数求解仍是研究中最少被探索的领域。然而,我的朋友 nephacks 确实在互联网最黑暗的角落找到了那个难以捉摸的工具来解决这个难题。 它叫 ECDLP(椭圆曲线离散对数问题)Solver,作者是 Mr. HAANDI。由于在网上找它极其令人沮丧,我将其重新上传到了我的网站。你可以在此下载该工具。
该求解器 0.2a 版本自带的 ReadMe 文件本身已经足够好,所以任何有脑子的人都能把它配置好。然而,它不是开源的,因此将其集成到我的 keygen 中被证明是不可能的。
在理想情况下,keygen 会要求你提供从 pidgen.dll 中提取的 BINK 资源,然后将其解包为以下部分:
pubX; pubY)genX; genY)a; b)p知道这些部分后,keygen 将使用 Schoof 算法暴力破解生成元阶 genOrder,然后求解私钥 privateKey,并利用计算出的 genOrder 来使用最优的 Pollard's Rho 算法。毫无疑问,只要我们有可用的算法,借助现代计算能力,我们可以在 20 分钟内破解任何私钥。
一旦 keygen 完成对正确私钥的暴力破解,任务就归结为实际生成密钥,而这正是这个 keygen 所做的。 为了让你有更清晰的认识,我可以提供理想 keygen 的流程。被划掉的是我的 keygen 已经实现的部分:
genOrder, privateKey)我们需要使用一个随机的 Raw Product Key 作为基础,生成形式为 AAAAA-BBB-CCCCCCS-DDEEE 的 Product ID。
操作系统系列常量 AAAAA 对于每个 Windows XP 系列都不同。例如,SP3 的该值为 76487。
BBB 和 CCCCCC 部分本质上对 Raw Product Key 进行编码。例如,如果第一部分等于 XXX,第二部分等于 YYYYYY,则 Raw Product Key 将被编码为 XXX-YYYYYY。
选择校验位 S 是为了让所有 C 位数之和加上它后成为一个能被 7 整除的数。
公钥索引 DD 让我们知道哪个公钥被用于成功验证产品密钥的真实性。
例如,Professional 密钥为 22,VLK 密钥为 23。
每次都会使用一个随机数 EEE 来生成不同的安装 ID。
产品密钥本身(不要与 RPK 混淆)的形式为 FFFFF-GGGGG-HHHHH-JJJJJ-KKKKK,使用 Base-24 编码,字母表为 BCDFGHJKMPQRTVWXY2346789,以排除任何容易混淆的字符,例如 I 和 1 或 O 和 0。
根据字母表容量公式,密钥最多可以包含 114 位信息。 $$N = \log_2(24^{25}) \approx 114$$
基于该计算,我们将 114 位的产品密钥解包为 4 个有序分段:
| Segment |
|---|
为简单起见,我们将 Upgrade 和 Serial 分段合并为一个名为 Data 的分段。按照这种逻辑,我们将能够通过将 Data 右移来提取 RPK,并通过左移位来将其装回,因为我检查过的大多数先验有效的产品密钥的 Upgrade 位都设置为 1。
微软在 Windows Server 2003 中重新设计了产品密钥格式,加入了一个后端服务器认证密钥,这实际上是一种安全的许可证验证方法,因为没有人能够猜到他们在私有服务器上使用了哪种验证算法。除了增加在线验证机制外,他们还将整体运算从 384 位提高到 512 位,并将签名标量提高到 62 位信息。
然而,如果我们在生成密钥时不考虑在线激活,我们仍然可以生成有效的密钥,从而通过操作系统的安装过程。这正是代码所做的——它生成一个随机的 10 位认证密钥。如今这已经完全不重要了,因为激活服务器已经关闭,Server 2003 被视为废弃软件(abandonware),正如整个项目不应被视为盗版一样。
椭圆曲线密码学(ECC)是一种公钥密码系统。这类系统依赖于具有挑战性的“单向”数学问题——一个方向容易计算,而“另一个”方向难以求解。它们有时被称为“陷门”函数——容易掉进去,却难以逃出来。[5]
ECC 依赖于求解以下形式的方程 $$y^2 = x^3 + ax + b$$
一般来说,密码学中利用的椭圆曲线有两种特殊情况——F2m 和 Fp。它们只有细微差别。两条曲线都定义在有限域上,Fp 使用一个大于 3 的素数参数,F2m 假定 $p = 2m$。微软在其算法中使用了后者。
有限域 Fp 上的椭圆曲线由以下部分组成:
F17 上的椭圆曲线看起来像这样:

该曲线由上图蓝色点组成。在实践中,密码学中使用的“椭圆曲线”是“方形矩阵中的点集”。
上述曲线是“教学用”的。它提供的密钥长度非常小(4-5 位)。在现实世界中,开发人员通常使用 256 位或更长的曲线。
由于这是一个公钥密码系统,微软必须在其 Windows XP 版本中共享公钥,用于校验输入的产品密钥。它存储在 pidgen.dll 中,以 BINK 资源的形式存在。第一组 BINK 数据用于验证零售密钥,第二组分别用于 OEM 密钥。
适用于 Windows 98 和 Windows XP 的 BINK 资源结构如下:
每个分段都用不同的颜色标记,BINK 头部值是相同的。

Windows Server 2003 和 Windows XP x64 的实现方式有所不同:
以下是我为 C 语言版 BINK Reader 制作的结构原型:```c typedef struct _EC_BYTE_POINT { CHAR x[256]; // x-coordinate of the point on the elliptic curve. CHAR y[256]; // y-coordinate of the point on the elliptic curve. } EC_BYTE_POINT;
typedef struct _BINKHDR { // BINK version - not stored in the resource. ULONG32 dwVersion;
// Original BINK header.
ULONG32 dwID;
ULONG32 dwSize;
ULONG32 dwHeaderLength;
ULONG32 dwChecksum;
ULONG32 dwDate;
ULONG32 dwKeySizeInDWORDs;
ULONG32 dwHashLength;
ULONG32 dwSignatureLength;
// Extended BINK header. (Windows Server 2003+)
ULONG32 dwAuthCodeLength;
ULONG32 dwProductIDLength;
} BINKHDR;
typedef struct _BINKDATA { CHAR p[256]; // Finite Field order p. CHAR a[256]; // Elliptic Curve parameter a. CHAR b[256]; // Elliptic Curve parameter b.
EC_BYTE_POINT G; // Base point (Generator) G.
EC_BYTE_POINT K; // Public key K.
} BINKDATA;
typedef struct _BINKEY { BINKHDR header; BINKDATA data; } BINKEY;
In case you want to explore further, the source code of `pidgen.dll` and all its functions is available within this repository, in the "pidgen" folder.
### 还原私钥
如果我们想为 Windows XP 生成有效的产品密钥,就必须使用 `pidgen.dll` 附带的公钥来计算相应的私钥,
这意味着我们必须反向求解这一单向 ECC 任务。
根据 BINK 中的密钥判断,曲线阶在 Windows XP 中为 **384 位**,在 Server 2003 / XP x64 中为 **512 位**。
使用最有效的 Pollard's Rho 算法(渐近复杂度为 $O(\sqrt{n})$)时,计算难度在 Windows XP 上至少为 $O(2^{168})$,在 Windows Server 2003 上为 $O(2^{256})$,但幸运的是,
为了减少匹配产品密钥的数量,微软将 Windows XP 中签名的值限制为 55 位,将 Windows Server 2003 中限制为 62 位,从而将难度降低到更易于管理的 $O(2^{28})$ / $O(2^{31})$。
如前所述,目前只有一个公共工具能满足我们的需求,那就是 Mr. HAANDI 编写的 ECDLP 求解器。<br>
要计算私钥,我们需要向该工具提供位于 BINK 资源中的公共 ECC 值,以及基点 `G(Gx; Gy)` 的阶 `genOrder`。
基点的阶可以使用 SageMath 计算。
**以下是我用于还原 Windows 98 私钥的基本算法:**
1. 使用 **SageMath** 计算基点的阶。在 SageMath 中执行以下命令:
1) `E = EllipticCurve(GF(p), [0, 0, 0, a, b])`,其中 `p`、`a` 和 `b` 是 BINK 资源中以十进制表示的椭圆曲线参数。
2) `G = E(Gx, Gy)`,其中 `Gx` 和 `Gy` 是 BINK 资源中以十进制表示的基点坐标。
3) `K = E(Kx, Ky)`,其中 `Kx` 和 `Ky` 是 BINK 资源中以十进制表示的公钥坐标。
4) `n = G.order()`,`n` 将是计算出的基点阶。**即使在最新的构建版本上,计算也可能需要一些时间。**
5) 使用 `factor(n)` 对阶进行因式分解。微软在点的阶上使用了素数,因此如果它返回的是该数字本身,这完全正常。
6) 将计算出的阶的因子保存到某处。
7) `-K` 将给出公钥在射影平面内的逆元,坐标为 `(x : y : z)`。将 `y` 坐标保存到某处,生成正确的私钥需要用到它。
2. 使用 **ECDLP Solver v0.2a** 计算私钥。
1) 该工具附带一个模板任务 `job_template.txt` 和一个 ReadMe 文件。要使用它,有必要了解该工具的工作原理。
2) 从 BINK 资源中插入所有公共椭圆曲线值,**不包括 `Ky` 坐标**。要生成正确的私钥,**必须使用之前在 SageMath 中计算出的逆坐标 `-Ky`**。
3) 插入基点阶 `n` 的因子并指定因子数量。很可能就是 `1`,因为微软主要使用素数作为其生成元的阶。
4) 运行工具 `<arch> ECDLP Solver.exe <job_name>.txt`,等待它为您计算出私钥 `k = %d`。
**以下是一个 Windows XP 任务 `job_xp.txt` 的示例,该任务可为 ECDLP Solver 生成正确的私钥。**```pascal
GF := GF(22604814143135632990679956684344311209819952803216271952472204855524756275151440456421260165232069708317717961315241);
E := EllipticCurve([GF|1,0]);
G := E![10910744922206512781156913169071750153028386884676208947062808346072531411270489432930252839559606812441712224597826,19170993669917204517491618000619818679152109690172641868349612889930480365274675096509477191800826190959228181870174];
K := E![14399230353963643339712940015954061581064239835926823517419716769613937039346822269422480779920783799484349086780408,17120082747148185997450361756610881166187863099877353630300913555824935802439591336620545428308962346299700128114607];
/*
FactorCount:=1;
61760995553426173
*/
以及它的 ECDLP 求解器输出:

重要说明:
请注意,我无法使用我逆向出的私钥生成正确的 Windows XP x64 密钥,即使使用 Ky 坐标代替通常的 -Ky 也不行。
出于某种原因,我也未能使用 SageMath 计算出 Windows Server 2003 的基点阶。我在 i7-12700K 上给了它 12 小时的计算时间,但它仍然卡在计算中。
其余工作都在这个密钥生成器的代码中完成。
0x40000/0x62A32,结果恰好是 0.64884,约 65%。我“三分之二”的估计准确得令人难以置信。BBB 部分设置为 640 且 CCCCCC 部分不为零时,生成“更好”密钥的几率最大。我将在后续版本中向参考文献添加更多有价值的阅读材料。
了解 Windows XP 激活的基础知识:
了解椭圆曲线密码学:
公开讨论:
如果你要展示或分叉此软件,请注明 Endermanch、z22 和 MSKey 的贡献。
只要保持开源,你可以随意按照自己的喜好修改它。依据 GNU 通用公共许可证 v3.0 授权。
欢迎任何贡献或提问。
| 位数 | 含义 |
|---|
| AAAAA | 操作系统系列常量 |
| BBB | 渠道 ID |
| CCCCCC | 序列号 |
| S | 校验位 |
| DD | 公钥索引 |
| EEE | 随机三位数 |
| 容量 |
|---|
| 数据 |
|---|
| Upgrade | 1 bit | 升级版本标志 |
| Serial | 30 bits | Raw Product Key (RPK) |
| Hash | 28 bits | RPK 哈希 |
| Signature | 55 bits | 针对 RPK 哈希的椭圆曲线签名 |
| Segment | 容量 | 数据 |
|---|
| Upgrade | 1 bit | 升级版本标志 |
| Channel ID | 10 bits | RPK 的 BBB 部分 |
| Hash | 31 bits | RPK 哈希 |
| Signature | 62 bits | 针对 RPK 哈希的椭圆曲线签名 |
| Auth Key | 10 bits | 后端认证值 |
| Offset | Value |
|---|
0x0000 | BINK ID |
0x0004 | BINKEY 结构的大小(字节)(实践中始终为 0x16C) |
0x0008 | 头部长度(实践中始终为 7) |
0x000C | 校验和 |
0x0010 | 数字编码日期 - BINKEY 版本(实践中始终为 19980206) |
0x0014 | ECC 曲线阶大小(实践中始终为 12) |
0x0018 | 哈希长度(实践中始终为 28) |
0x001C | 签名长度(实践中始终为 55) |
0x0020 | 有限域阶 p |
0x005C | 曲线参数 a |
0x0098 | 曲线参数 b |
0x00D4 | 基点 x 坐标 Gx |
0x0110 | 基点 y 坐标 Gy |
0x014C | 公钥 x 坐标 Kx |
0x0188 | 公钥 y 坐标 Ky |
| Offset | Value |
|---|
0x0000 | BINK ID |
0x0004 | BINKEY 结构的大小(字节) |
0x0008 | 头部长度(实践中始终为 9) |
0x000C | 校验和 |
0x0010 | 数字编码日期 - BINKEY 版本(实践中始终为 20020420) |
0x0014 | ECC 曲线阶大小(实践中始终为 16) |
0x0018 | 哈希长度(实践中始终为 31) |
0x001C | 签名长度(实践中始终为 62) |
0x0020 | 后端认证值长度(实践中始终为 12) |
0x0024 | Product ID 长度(实践中始终为 20) |
0x0028 | 有限域阶 p |
0x0068 | 曲线参数 a |
0x00A8 | 曲线参数 b |
0x00E8 | 基点 x 坐标 Gx |
0x0128 | 基点 y 坐标 Gy |
0x0168 | 公钥 x 坐标 Kx |
0x01A8 | 公钥 y 坐标 Ky |