吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 253|回复: 1
上一主题 下一主题
收起左侧

[原创] DMDE 许可证算法分析与通用注册机(win32/win64)

[复制链接]
跳转到指定楼层
楼主
73214 发表于 2026-11-1 11:43 回帖奖励
本帖最后由 73214 于 2026-11-2 18:13 编辑

【原创】DMDE 许可证算法分析与通用注册机(win32/win64)

附件:注册机完整源码(C++ 源文件 + manifest + 编译脚本)。DMDE 试用版请自行到官网下载:https://dmde.com/download.html(本文实测 4.5.0.849 beta win32/win64、4.4.4.842 win64、4.4.0.828 win32)。本文完整分析整条授权链,并说明注册机如何从目标程序里现场提取全部常量,而不是按版本硬编码。仅供学习研究,请支持正版。

1. 目标与保护概览

DMDE(Disk Editor and Data Recovery Software,磁盘编辑与数据恢复软件)采用纯离线的分层授权方案,没有加密狗,手动激活也不需要联网:

  • base64url 编码的许可证数据块,内含一条二进制记录
  • 数据块上有一层 RSA-2048 签名(唯一的非对称校验)
  • 数据块尾部有 CRC-32 校验
  • 由被授权人信息和机器码派生出的密钥材料
  • 自定义 base32 激活码,由四个建立在 SHA-1 和程序内置常量表之上的半字节方程把关

层次依次是:解析(结构 + 版本范围)、RSA 验签、CRC 校验、密钥材料派生、方程组、机器绑定。下文逐层分析。全程静态逆向(IDA + capstone 脚本)加动态确认(隐藏启动、内存扫描、WOW64 断点跟踪器、以及驱动真实对话框的 UI 自动化)。

实测版本:4.5.0.849 beta(win32、win64)、4.4.4.842(win64 GUI 和控制台)、4.2.4.818(win64)、4.4.0.828(win32)。除控制台版只验证了补丁与常量提取外,其余全部通过真实对话框流程激活成功。

2. 工具

  • IDA(win64 与 win32 两个库)
  • python + capstone,对 PE 做模式扫描
  • 一个小型 Win32 UI 驱动程序(EnumWindows / PostMessage),自动应答对话框、无头驱动手动激活流程
  • 一个支持 WOW64 的 int3 跟踪器(WOW64 下断点异常码是 0x4000001F 而不是 0x80000003,这点值得知道,我为此搭进去一下午)
  • ReadProcessMemory,观察活进程里的许可证结构体

3. 定位许可证解析函数

锚点是版本比较指令簇。解析函数用 cmp word ptr [reg+disp], imm16 成对校验记录里的版本字:

; 4.5.0.849 win64,解析函数 0x4C4830 内
4C4DD0  movzx rax, byte ptr [rax+10h]
4C4DD5  test  al, 10h                   ; 版本标志位
4C4DD8  je    reject
4C4DE2  movzx rax, byte ptr [rax+12h]
4C4DE7  cmp   al, byte ptr [rbp+7Eh]    ; 49
4C4E06  cmp   word ptr [rax+14h], 25Eh  ; >= 606
4C4E0C  jb    reject
4C4E16  cmp   word ptr [rax+14h], 260h  ; <= 608
4C4E1C  ja    reject
4C4E26  movzx rax, byte ptr [rax+10h]
4C4E2B  xor   al, 10h                   ; 掩码折回版本半字节

编码是 66 81 /7 带 ModRM 位移。解码 ModRM 而不是匹配固定字节序列,才能在每个版本上都找到这组比较(寄存器和记录偏移在版本和架构之间都会变)。持有这组比较的函数就是数据块解析函数。4.4.0.828 win32 上同一段代码位于 0x464020,记录偏移同样是 +14h。

4. 许可证数据块

许可证密钥文本是 base64url(字母表
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_,填充符 .)。
解码后的布局:

word 0        = 4                     数据块版本
word 2        = l2                    字符串区长度
bytes 4..l2   = 四个 NUL 结尾的字符串(name、str2、str3、str4),
                长度上限 512/200/255/31;NUL 后紧跟 0xFF 表示提前进入
                下一个字符串;l2-2 处的 word 必须为 0(扩展探测)
header2 @l2   = 44 字节:+0 是被授权人(12 字节),+18 是标志字,
                +28 的 qword -> cfg+1044,+40 的 dword -> cfg+1056
record @l2+44 = 66 字节(见下)
sig @-256     = RSA-2048 签名
最后 4 字节   = 前面全部内容的 CRC-32(poly 0xEDB88320)

66 字节的记录:

+0   word  size = 66
+2   word  number          -> cfg+972
+4   char  magic[8]        "w3ha.606"
+12  dword 自由
+16  dword 版本标志位      0x10 win64 GUI,0x20 win64 控制台,0x01 win32
+18  word  49
+20  dword 版本号          接受 606..608,高字是有效期代码(0 = 永久)
+24  qword nonce
+32  qword 自由            -> cfg+976/980
+40  qword 自由            -> cfg+1116
+48  dword 自由            -> cfg+1124
+52  14 字节 template      28 个半字节,低位在前

+16 处的字节是解析函数测试的版本标志位。两个架构上指令对相同,掩码不同:

; 4.4.4.842 win64
4C1376  movzx rax, byte ptr [rax+10h]
4C137B  test  al, 10h
4C137E  je    reject

; 4.4.0.828 win32
46458C  test  byte ptr [eax+10h], 1
464590  je    reject

版本比较之后,同一个掩码会被折进版本半字节(xor al, 10h / xor al, 1),所以"括住"版本比较的 test/xor 指令对是一个稳定的提取锚点。

一个值得记录的版本差异:4.4.0.828 上对话框报的 "Inappropriate license key (wrong version)" 是 RSA 阶段之后一切解析失败的总 catch-all。版本标志位写错和真正的版本不匹配显示同一句话,在这版上这条报错对定位失败检查点毫无用处。

5. RSA 校验与补丁

签名校验是一个独立函数,由解析函数直接调用。观察过的每个版本里,它都紧贴在解析函数体下方:

  • 4.5.0.849 win64:0x4C4720(解析函数 0x4C4830)
  • 4.4.4.842 win64:0x4C0A90(解析函数 0x4C0BC0)
  • 4.4.0.828 win32:0x463F48(解析函数 0x464020,经一次 .itext E9 跳板)

它对签名块做哈希并与内置公钥比对,返回布尔值。win32(FPC 编译)的函数头:

463F48  push ebp
463F49  mov  ebp, esp
463F4B  add  esp, 0FFFFFE74h
...
463FEC  cmp  dword ptr [ebp-14h], 14h   ; SHA-1 摘要长度 20
463FF0  jne  46400Dh
...
46400D  mov  al, [ebp-0Dh]
464013  ret

FPC 的调用约定把布尔返回值放在 AL 里、裸 ret 返回,所以三个字节的补丁在两个架构上通用:

B0 01 C3    ; mov al, 1 ; ret

签名是唯一的非对称校验。其余部分(CRC-32、CRC-16、方程组、解析遍历)全部照常满足而不是绕过,因此对打过补丁的程序来说,伪造的许可证与真许可证没有区别。

通用定位方法:在解析函数体里扫描 E8 rel32 调用,找目标函数结束地址落在解析函数起点下方 0x400 以内、且函数体内含 SHA-1 长度常量 0x14(cmp eax/reg/mem, 14h 或 imm32 14 00 00 00)的那个。win32 版本带增量链接,调用可能落到 .itext 跳板(单条 E9 jmp)上,需要跟一跳。

6. 密钥材料

激活校验从许可证结构体里读两个缓冲区:

k986  (cfg+986, 40 字节) = zeros(8) || 被授权人(12) || vars80(8)
                            || le16(606) || le16(0) || nonce(8)
key40 (cfg+1076, 40 字节) = 机器码(8) || k986[8..40]

vars80 = SHA1(MD5(被授权人12 || number_le16 || salt5))[0..7],其中 salt5 = 18 E3 20 A1 44,是 .text 里的 5 字节二进制常量。它通过 .data 里的一对指针找到:两个连续指针,第二个指向第一个之后 6 字节(win64)或 8 字节(win32,字符串对齐不同)处,两者都指向 5 字节、NUL 结尾、至少两个字节最高位为 1 的字符串。前面 6/8 字节处的兄弟字符串属于标志路径。

; 4.4.0.828 win32
45F178  C5 C1 D9 75 98 00 .. 00   ; 标志路径盐值
45F180  18 E3 20 A1 44 00 .. 00   ; 许可证盐值
6773CC  dd 45F178, 45F180         ; 指针对,间距 8

解析函数把记录版本拷到 cfg+984,然后用一个编译期常量(606)覆盖密钥材料里 cfg+1014 处的版本字。生成时必须用这个字,不能用记录版本:

4C1498  mov word ptr [rax+3F6h], 25Eh   ; 4.4.4 win64

结构体偏移在 win32 和 win64 上完全一致:结构体是字节数组,架构不移动任何东西。magic 在 +1060,number 在 +972,k986 在 +986,版本在 +984,密钥版本字在 +1014,key40 在 +1076。

7. 半字节方程组

激活码解码器是自定义 base32,字母表 123456789ABCDEFGHYJKLMNPQR0TZVWX,按位低位在前消费,每 5 个字符插一个 -。解码器的容错:小写折叠,I->Y、U->Z、O/S->0,字母表之外的字符跳过。

解码出 15 字节 = 13 字节载荷 + LE 的 CRC-16。载荷是 26 个半字节(低位在前)。CRC-16:反射多项式 0xA001,初值 0xFFFF,异或输出 0xFFFF,覆盖 key40 || payload13。

令 H(t, key) = SHA1(le32(t) || key) 前 4 字节按 LE dword 读取。校验在 26 个半字节 N 和 28 元视图 V = N || [0,0] 上跑四个方程:

eqA: XOR(N[0..25])                  == (XOR H(t, key40), t 取遍 T1, & 0xF) ^ 0xF
eqB: XOR(N[i], 0x3577CAF 的第 i 位) == (XOR H(t, key40), t 取遍 T2, & 0xF) ^ 5
eqC: XOR(V[0..27])                  == (XOR H(t, k986),  t 取遍 T3, & 0xF) ^ 0xC
eqD: XOR(V[i], 0xE9D4FED 的第 i 位) == (XOR H(t, k986),  t 取遍 T4, & 0xF) ^ 9

eqA/eqB 跑在激活码校验里(手动激活),eqC/eqD 跑在许可证解析里(记录里的 template 半字节)。按位选择的循环很好认:1 << i 移位后与掩码立即数做 test:

; 4.4.0.828 win32,eqB
462F5F  mov  esi, 1
462F64  shl  esi, cl
462F66  test esi, 3577CAFh
462F6C  je   @skip
462F6E  movzx ecx, byte ptr [eax]    ; 运行时半字节缓冲区
462F71  xor  ebx, ecx

四张表紧跟在方程函数后面,是非零 dword 连续段,中间以零分隔:

T1 = 8A417373 0AFA4AAE E23719AA B451AEA4 7C862632   (5 个 dword,eqA/eqB 函数之后)
T2 = 9CC08591 263F668B 707C27D2 16BD9EAA            (4 个 dword)
T3 = 7B347482 D2A33A04 D28B439E E71A7C30            (4 个 dword,eqC/eqD 函数之后)
T4 = D72C8085 6DB3EA40 26C87890 E8F90944 180A085A   (5 个 dword)

这些值在检查过的所有版本里(4.2.4 到 4.5.0,win32 和 win64)完全相同。注册机仍然每次从二进制里读出来:win64 上从 .pdata 给出的函数边界之后开始找;win32 没有展开表,从掩码循环的收尾 ret 之后开始找。给想复刻 win32 扫描的人提个醒:掩码指令后遇到的第一个 C3 通常不是 ret,而是收尾阶段 mov eax, ebx 的 ModRM 字节。要把每个 C3 候选都试一遍,用 dword 连续段的形状来定夺。

求解:eqA 和 eqC 的系数全为一,所以搜索 nonce 直到两个右边相等;剩下两个方程在 GF(2) 上对选定的四个半字节线性解出。

8. 机器绑定

key40 的开头 8 字节是机器码。填充时机各版本不同:4.4.4 在普通启动时就计算;4.5.0 在许可证安装时计算;4.4.0 在启动对话框全部应答完之后,靠内置免费版许可证填入。同一台机器上三种情况的值完全相同。

注册机不维护"版本到绑定方式"的表,而是运行时直接决定:往目标目录丢一个探测用 license.key(这个数据块与机器无关),隐藏启动目标,自动应答启动对话框(语言选择、旧版本提示、许可协议:只点 OK/Yes/Continue/Ignore/Accept,复选框只在未勾选时点),在内存里扫描许可证结构体(magic w3ha. + +14 处标志字 31 00 + +24 处可打印的被授权人),然后按多数表决读出 magic+16 处的头槽。全零也是合法答案,走同一条路径。

这样读到的就是激活码校验实际使用的那个 key40,所以生成的激活码必然匹配目标程序将要校验的值。

9. 激活文件

acode.txt 把两半捆在一起:

activatekey=<激活码>\r\nLICDATA:<许可证密钥>\r\n

手动激活对话框的 Open... 一步完成:LICDATA: 之前的空白处截断激活码部分,先解析并安装许可证,再校验激活码。4.4.4 及更早版本只在换行符之后找 LICDATA:,新版本接受任意空白,所以文件统一用 CRLF。activatekey= 前缀在所有观察过的版本上都被接受,包括那些自身 ini 关键字是 activatecode[0]= 的版本。

激活成功后 DMDE 在 dmde.ini 里写入 activatecode[0]=<激活码>:<第二激活码>。第二激活码由 DMDE 自己生成,只依赖许可证和机器:同一份伪造许可证在 4.5.0 win64、4.2.4 win64、4.4.0 win32 上存下的第二激活码完全相同,与版本和架构无关。

10. 通用化的做法

注册机内部没有任何按版本硬编码的常量。所有常量在运行时通过锚点从目标程序提取,这些锚点在检查过的每个版本上都成立:

常量 锚点
版本范围 解析函数内的 66 81 /7 比较,与 magic 数字交叉验证
版本标志位 括住版本比较、立即数相等的 test/xor 对
密钥版本字 离版本比较最近的 66 C7 /0 存储
掩码 方程循环里对立即数的字节探测
T1..T4 方程函数之后的 dword 连续段
盐值 .data 指针对,间距 6(win64)/ 8(win32)
RSA 校验 解析函数下方含 SHA-1 长度 0x14 的 E8 调用目标
机器码 运行时探测头槽

win32 支持要点:PE32 镜像没有 .pdata,函数边界来自 .text 的调用目标;解析调用时跟一次 .itext 跳板;FPC 用 AL 返回布尔值、调用方清栈,补丁不用改。一遍扫描同时处理两种架构。

锚点失效时,工具会大声停下并打印它找到的候选(例如所有形状像版本比较的指令),而不是伪造错误的常量。有这份输出加上源码里的锚点逻辑,重新推导是个短活。

11. 验证

生成器在写出任何文件之前先验证自己的输出:

  • 按解析函数的方式重新遍历数据块(字符串遍历、边界、CRC-32)
  • 用提取的表和派生的密钥材料重算 template 与半字节方程
  • 重新解码激活码并重查 CRC-16
  • 把试用许可证种进一次隐藏启动,逐字节比对目标程序实际派生的 k986 与生成值

端到端结果:标题栏的 "[Not Activated]" 消失,结构体里是被伪造的被授权人、number、nonce 和机器码,dmde.ini 记录下激活,且第二激活码由 DMDE 自己生成。下图输出以演示参数 --device 0011223344556677 运行,机器码相关字段均为演示值。

12. 4.0.0 的边界

4.0.0.800 win64 检查过,未支持。数据块解析、magic、唯一接受的版本 606、盐值、结构体几何、RSA 锚点全部沿用,但半字节方程机制在整个镜像里不存在:没有掩码立即数,没有 T 表。它的激活码校验是更老的方案,需要单独推导。注册机对此明确报告,而不是瞎猜。

结束语

  • 从版本比较入手,其余一切都挂在解析函数上。
  • 常量靠推导,不要列表:同一个版本的两个架构,光版本标志位就不一样。
  • 凡是机器绑定的东西,运行时观察胜过静态猜测。
  • 对话框报错文本会跨版本撒谎;能报告"哪个分支拒绝了"的跟踪器,胜过读报错字符串。

仅供学习交流,试用程序请到官网下载,喜欢请支持正版。

DMDEKeygen.7z

174.92 KB, 下载次数: 26, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 2吾爱币 +2 热心值 +2 收起 理由
likesina + 1 + 1 我很赞同!
百年抉择 + 1 + 1 我很赞同!

查看全部评分

发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
likesina 发表于 2026-11-3 19:33
第一次听说这软件,下载下来看看,
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-11-4 01:43

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表