潜水吾爱很久了,第一次发帖,有什么错误的欢迎指正!!!
这个文章是自己原创的,如有雷同纯属巧合!!
上面的check hardecoded 这个就不跟了,非常的简单 我们要跟的是下面那个 name/serial check
这个程序应该是用汇编写的,因为入口是push 0
BP GetWindowTextA 下这个断点可以跟踪到关键算法
[Asm] 纯文本查看 复制代码 004015E5 |. 8BEC mov ebp,esp
004015E7 |. 6A 20 push 0x20 ; /Count = 20 (32.)
004015E9 |. 68 42324000 push Splish.00403242 ; |Buffer = Splish.00403242
004015EE |. FF75 0C push [arg.2] ; |hWnd = 000102F0 (class='Edit',parent=000202E4)
004015F1 |. E8 34010000 call <jmp.&USER32.GetWindowTextA> ; \GetWindowTextA
004015F6 |. 85C0 test eax,eax ; 获取注册码长度
004015F8 |. 0F84 95000000 je Splish.00401693 ; 如果注册码码等于空则跳
004015FE |. A3 67344000 mov dword ptr ds:[0x403467],eax ; 注册码长度
00401603 |. 6A 0B push 0xB ; /Count = B (11.)
00401605 |. 68 36324000 push Splish.00403236 ; |name
0040160A |. FF75 08 push [arg.1] ; |hWnd = 000202E8 (class='Edit',parent=000202E4)
0040160D |. E8 18010000 call <jmp.&USER32.GetWindowTextA> ; \GetWindowTextA
00401612 |. 85C0 test eax,eax ; 获取name长度
00401614 |. 74 68 je short Splish.0040167E
00401616 |. A3 63344000 mov dword ptr ds:[0x403463],eax ; name长度
0040161B |. 33C9 xor ecx,ecx
0040161D |. 33DB xor ebx,ebx
0040161F |. 33D2 xor edx,edx
00401621 |. 8D35 36324000 lea esi,dword ptr ds:[0x403236] ; name
00401627 |. 8D3D 58324000 lea edi,dword ptr ds:[0x403258]
我们先看程序最后的比较, 它循环判断的次数是name的长度
[Asm] 纯文本查看 复制代码 004016A8 |> \8D35 4D324000 lea esi,dword ptr ds:[0x40324D] 指向name得出的结果Y
004016AE |. 8D3D 58324000 lea edi,dword ptr ds:[0x403258] 指向serial得出的结果T
004016B4 |. 33DB xor ebx,ebx
004016B6 |> 3B1D 63344000 /cmp ebx,dword ptr ds:[0x403463] ; 对比name长度
004016BC |. 74 0F |je short Splish.004016CD
004016BE |. 0FBE041F |movsx eax,byte ptr ds:[edi+ebx]
004016C2 |. 0FBE0C1E |movsx ecx,byte ptr ds:[esi+ebx]
004016C6 |. 3BC1 |cmp eax,ecx Y和T对比
004016C8 |. 75 18 |jnz short Splish.004016E2 不相等就挂
004016CA |. 43 |inc ebx ebx+1
004016CB |.^ EB E9 \jmp short Splish.004016B6
[Asm] 纯文本查看 复制代码 00401632 |> /0FBE041E /movsx eax,byte ptr ds:[esi+ebx] ; 逐个指向name
00401636 |. |99 |cdq
00401637 |. |F7F9 |idiv ecx ; name的16进制除以ecx ecx=10 49/10=4....9
00401639 |. |33D3 |xor edx,ebx edx和ebx异或
0040163B |. |83C2 02 |add edx,0x2 ; 余数+2
0040163E |. |80FA 0A |cmp dl,0xA
00401641 |. |7C 03 |jl short Splish.00401646 ; 少于A
00401643 |. |80EA 0A |sub dl,0xA ; dl-A
00401646 |> |88141F |mov byte ptr ds:[edi+ebx],dl ; 余数1
00401649 |. |43 |inc ebx
0040164A |. |3B1D 63344000 |cmp ebx,dword ptr ds:[0x403463] ; 循环name的长度次数
00401650 |.^\75 E0 \jnz short Splish.00401632
小结:
name指向每个字符串记为namestr
namestr÷10 余数记为X
xor edx,ebx 这里的ebx 每次自增1 ebx设为S
X 和 S+1 异或
X+2 =Y
如果Y少于10
则直接跳向
mov byte ptr ds:[edi+ebx],Y
否则
Y-10
↓
mov byte ptr ds:[edi+ebx],Y
例子:
name第一个为ASCII “1” hex数据是31 10进制就是49
49/10=4......9
9和0异或 还是等于9
9+2=11
11》10
∴ 11-10=1
S=S+1
最后1 给 [edi+ebx]
[Asm] 纯文本查看 复制代码 00401669 |> /0FBE041E /movsx eax,byte ptr ds:[esi+ebx] ; 逐个指向假码
0040166D |. |99 |cdq
0040166E |. |F7F9 |idiv ecx ; 假码的16进制除以ecx ecx=10 49/10=4....9
00401670 |. |88141F |mov byte ptr ds:[edi+ebx],dl ; 余数2
00401673 |. |43 |inc ebx
00401674 |. |3B1D 67344000 |cmp ebx,dword ptr ds:[0x403467] ; 循环假码的长度
0040167A |.^\75 ED \jnz short Splish.00401669
假码指向每个字符串记为 Serialstr
Serialstr÷10 余数记为 T
movsx byte ptr ds:[esi+ebx],T
所以要符合 Y=T 》》》注册成功
例子:
因为现在我们要计算得出Y=T
上面得出Y=1 所以T也是等于1
然后就有以下算式
10T+T=11
11/10=1....1
刚好符合,这个条件有很多
例如: 51/10=5....1
是吧,这个公式成立的条件有很多,自己发挥想象。。。
所以 51/10=5...1 这个 得出51 记住51是 10进制 转换成16进制是33 33是字符串 “3”
所以得出 namne 的1 对应 serial 的3
name :12345678
1 3 5 3 9 3 5 3 Y
3 + 7 ! c ! 7 ! T
所以
name:12345678
注册码为:3+7!c!7!
附上易语言源码,代码写的很挫,将就看着吧
最后附上 keygenme和算法的易语言源码
简单keygenme分析.zip
(618.17 KB, 下载次数: 151)
|