【文章标题】: bundy's keygenme #1分析
【文章作者】: HappyTown
【软件名称】: bundy's keygenme #1
【下载地址】: 附件内
【加壳方式】: 无
【保护方式】: math
【编写语言】: VC6
【使用工具】: OD
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
希望你先自己动手分析一下,否则,可能阅之亦是无味。
00401260 /$>push esi
00401261 |.>mov esi, dword ptr [esp+8]
00401265 |.>push 10 ; 0x10
00401267 |.>push 100 ; 0x100
0040126C |.>mov dword ptr [40D84C], esi
00401272 |.>call <mirsys>
00401277 |.>mov dword ptr [40D580], eax
0040127C |.>push 0
0040127E |.>mov dword ptr [eax+238], 10 ; mip->IOBASE = 16
00401288 |.>call <mirvar>
0040128D |.>push 0
...
004012C9 |.>push 0
004012CB |.>mov dword ptr [40D594], eax
004012D0 |.>call <mirvar>
004012D5 |.>push 0
004012D7 |.>mov dword ptr [40D578], eax
004012DC |.>call <mirvar>
004012E1 |.>push 1
004012E3 |.>mov dword ptr [40D57C], eax
004012E8 |.>call <mirvar> ; a
004012ED |.>mov dword ptr [40D584], eax
004012F2 |.>mov eax, dword ptr [40D574]
004012F7 |.>push 0040C144 ; ASCII "8FD312A230FE4096F59566AAC6D6229FBBCAA08B23835F78A77B7DF4C9FA723A15E5FB6D5B555670313B2AE346402217FEF2C60896460804999516B1502AEF51"
004012FC |.>push eax ; b
004012FD |.>call <cinstr>
00401302 |.>mov ecx, dword ptr [40D58C]
00401308 |.>push 0040C138 ; ASCII "9F0A32E3"
0040130D |.>push ecx ; c
0040130E |.>call <cinstr>
00401313 |.>mov edx, dword ptr [40D590]
00401319 |.>push 0040C12C ; ASCII "9F2F8283"
0040131E |.>push edx ; d
0040131F |.>call <cinstr>
...
我们输入:
name: happy
serial: 87654321-22222222
0040110E .>push ecx
0040110F .>push 0040D598 ; ASCII "happy"
00401114 .>push ebp
00401115 .>call <bytes_to_big>
0040111A .>mov edx, dword ptr [40D578]
00401120 .>push 0040D5D8 ; ASCII "61BA19A2"
00401125 .>push edx ; sn_1
00401126 .>call <cinstr>
0040112B .>mov ecx, dword ptr [40D594]
00401131 .>lea eax, dword ptr [esi+40D5D9]
00401137 .>push eax ; "22222222"
00401138 .>push ecx ; sn_2
00401139 .>call <cinstr>
0040113E .>mov eax, dword ptr [40D578]
00401143 .>mov edx, dword ptr [40D58C]
00401149 .>push eax ; sn_1
0040114A .>push eax ; sn_1
0040114B .>push edx ; c:9F0A32E3
0040114C .>call <multiply> ; sn_1 = c * sn_1 = 541D498FF430F843
00401151 .>mov eax, dword ptr [40D588]
00401156 .>mov ecx, dword ptr [40D574]
0040115C .>mov edx, dword ptr [40D578]
00401162 .>push eax ; e
00401163 .>mov eax, dword ptr [40D570]
00401168 .>push ecx ; b: 8FD312A2...502AEF51
00401169 .>push edx ; sn_1: 541D498FF430F843
0040116A .>push eax ; name: 68 61 70 70 79
0040116B .>call <powmod> ; e = (name ^ sn_1) mod b = 60B4B812...EFCD381A
00401170 .>mov ecx, dword ptr [40D57C]
00401176 .>mov edx, dword ptr [40D590]
0040117C .>mov eax, dword ptr [40D578]
00401181 .>push ecx ; f
00401182 .>push edx ; d: 9F2F8283
00401183 .>push eax ; sn_1: 541D498FF430F843
00401184 .>call <divide> ; f = sn_1 mod d = 5F2BF255
00401189 .>mov ecx, dword ptr [40D584]
0040118F .>mov edx, dword ptr [40D578]
00401195 .>add esp, 44
00401198 .>push ecx ; a: 1
00401199 .>push edx ; f: 5F 2B F2 55
0040119A .>call <compare>
0040119F .>add esp, 8
004011A2 .>test eax, eax
004011A4 .>jnz 004010A8
我们看一下上段代码的意思:
1> sn_1 = c * sn_1
2> e = (name ^ sn_1) mod b
3> f = sn_1 mod d
4> f ?= 1
整理如下:
A) e = (name ^ (c * sn_1)) mod b
B) 1 ?= (c*sn_1) mod d
如果 f != 1 ,那么,跳向错误。显然,我们先得通过B)这一步判断才能继续前行。
1 ?= (c*sn_1) mod d 不就是告诉我们 sn_1 是 c 模 d 的乘法逆元嘛,呵呵。
计算得: sn_1 = c^(-1) mod d = 61BA19A2。
我们重新输入:
name: happy
serial: 61BA19A2-22222222
0040110E .>push ecx
0040110F .>push 0040D598 ; ASCII "happy"
00401114 .>push ebp
00401115 .>call <bytes_to_big>
0040111A .>mov edx, dword ptr [40D578]
00401120 .>push 0040D5D8 ; ASCII "61BA19A2"
00401125 .>push edx ; sn_1
00401126 .>call <cinstr>
0040112B .>mov ecx, dword ptr [40D594]
00401131 .>lea eax, dword ptr [esi+40D5D9]
00401137 .>push eax ; "22222222"
00401138 .>push ecx ; sn_2
00401139 .>call <cinstr>
0040113E .>mov eax, dword ptr [40D578]
00401143 .>mov edx, dword ptr [40D58C]
00401149 .>push eax ; sn_1
0040114A .>push eax ; sn_1
0040114B .>push edx ; c:9F0A32E3
0040114C .>call <multiply> ; sn_1 = c * sn_1 = 3CB67A9D9F5A5EA6
00401151 .>mov eax, dword ptr [40D588]
00401156 .>mov ecx, dword ptr [40D574]
0040115C .>mov edx, dword ptr [40D578]
00401162 .>push eax ; e
00401163 .>mov eax, dword ptr [40D570]
00401168 .>push ecx ; b: 8FD312A2...502AEF51
00401169 .>push edx ; sn_1: 3CB67A9D9F5A5EA6
0040116A .>push eax ; name: 68 61 70 70 79
0040116B .>call <powmod> ; e = (name ^ sn_1) mod b = 3088B09D...7E9E5949
00401170 .>mov ecx, dword ptr [40D57C]
00401176 .>mov edx, dword ptr [40D590]
0040117C .>mov eax, dword ptr [40D578]
00401181 .>push ecx ; g
00401182 .>push edx ; d: 9F2F8283
00401183 .>push eax ; sn_1: 3CB67A9D9F5A5EA6
00401184 .>call <divide> ; f = sn_1 mod d = 1; g = sn_1 / d = 61A331B7
00401189 .>mov ecx, dword ptr [40D584]
0040118F .>mov edx, dword ptr [40D578]
00401195 .>add esp, 44
00401198 .>push ecx ; a: 1
00401199 .>push edx ; f: 1
0040119A .>call <compare>
0040119F .>add esp, 8
004011A2 .>test eax, eax
004011A4 .>jnz 004010A8
004011AA .>mov eax, dword ptr [40D578]
004011AF .>mov ecx, dword ptr [40D574]
004011B5 .>mov edx, dword ptr [40D57C]
004011BB .>push eax ; h
004011BC .>push ecx ; b: 8FD312A2...502AEF51
004011BD .>mov ecx, dword ptr [40D594]
004011C3 .>push edx ; g: 61A331B7
004011C4 .>mov edx, dword ptr [40D588]
004011CA .>push ecx ; sn_2: 22222222
004011CB .>push eax ; 1
004011CC .>push edx ; e = 3088B09D...7E9E5949
004011CD .>call <powmod2> ; h = (e ^ 1) * (sn_2 ^ g) mod b = 83633937...59B6B217
004011D2 .>mov eax, dword ptr [40D570]
004011D7 .>mov ecx, dword ptr [40D578]
004011DD .>push eax ; name
004011DE .>push ecx ; h
004011DF .>call <compare> ; h ?= name
整理一下,我们需要:
((name ^ 3CB67A9D9F5A5EA6) * (sn_2 ^ g)) mod b = name
那么,得:
(sn_2 ^ g) mod b = (name * ((name ^ 3CB67A9D9F5A5EA6)^(-1))) mod b
显然这是一个RSA的问题,分解b,求得g对应的私钥即可轻松算出sn_2。
Wow,b是512位。显然我们在有生之年分解不了它。
但作者说: There is a solution! 看来我们得另找其它方法了。
从新整理一下验证的思路:
1> (c * sn_1) mod d = 1
2> ((name ^ (c * sn_1)) * (sn_2 ^ ((c * sn_1)/d))) mod b = name
在2>中,(c * sn_1) 和 (c * sn_1)/d之间是什么关系?
聪明的你可能已经猜出来了。我们换个方式来表达这种关系:
c * sn_1 = k*d + 1
也就是说 (c * sn_1)/d = k,那么2>转化为:
((name ^ (k*d + 1)) * (sn_2 ^ k)) mod b = name
我们令 sn_2 = name ^ x,那么则应该有:
((name ^ (k*d + 1) * (name ^(x*k)) mod b = name
即:
(name ^ (k*d + x*k + 1)) mod b = name
也就是说,需:
(name ^ (k*d + x*k)) mod b = 1
令 x = -d 则可满足上式的要求。此时:
sn_2 = name ^ (-d) mod b = (name ^ d) ^ (-1) mod b
也就是说,sn_2 为 (name ^ d) 模 b 的乘法逆元。
好了,问题已经得到了解决。给出一组可用的注册码:
name: happy
serial: 61BA19A2-1128D238DD8B63219451910D20BED9324CD9541859B1755D441AAB7E37F7C89FAB57D96BF8699580748555C585058FD32233579EDB845521776D0B900A8A26F0
注册机及其源代码在附件中一并给出。
事实上,前面那个RSA的思路自身就很有问题,3CB67A9D9F5A5EA6 虽然在本程序中是个固定的数,但因为它是偶数,所以,它既不可能是私钥也不可能是公钥,这是RSA算法自身所要求的,因此,就算b是128位,那种做法也是不能求得sn_2的。
--------------------------------------------------------------------------------
【经验总结】
在06年的时候就为这个程序伤过不少脑筋,今日终得其解。
呜呼,美哉,美哉。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪软件安全论坛, 转载请注明作者并保持文章的完整, 谢谢!
2007年12月17日 4:10:52
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
上传的附件: