【作者】ryOsUkE
转载请注明出处来自看雪论坛,以及本文的完整性,谢谢!
应用ECC进行软件加密的方法很多,前面已经介绍了一些,今天再通过一个例子来研究一把ECC的加密应用。CrackMe见附件。
【分析】
随便输入一些东西,根据错误提示来到下面
004010EF push ebx
004010F0 push ebp
004010F1 mov dword ptr [esi+234], 10 ; IOBASE=0x10
004010FB call 00401C40 ; A=mirvar(0);
00401100 push ebp
00401101 mov ebx, eax ; A
00401103 call 00401C40 ; B=mirvar(0);
00401108 mov ebp, eax ; B
0040110A push ebp ; B
0040110B push ebx ; A
0040110C push 00410860 ; 输入的serial key
00401111 push esi ; miracl*
00401112 call 00401300 ; first test
=================================================================================================
先进入00401300 看看里面到底干了什么
00401300 sub esp, 84
00401306 push ebx
00401307 push ebp
00401308 push esi
00401309 push edi
0040130A push 0
0040130C call 00401C40 ; a=mirvar(0)
00401311 push 0
00401313 mov ebp, eax ; a
00401315 call 00401C40 ; b=mirvar(0)
0040131A mov ebx, eax ; b
0040131C push 0
0040131E mov [esp+38], ebx
00401322 call 00401C40 ; c=mirvar(0)
00401327 mov esi, eax
00401329 push 0
0040132B mov [esp+30], esi
0040132F call 00401C40 ; d=mirvar(0)
00401334 mov edi, eax
00401336 push 0
00401338 mov [esp+38], edi
0040133C call 00401C40 ; e=mirvar(0)
00401341 push 0
00401343 mov [esp+28], eax
00401347 call 00401C40 ; f=mirvar(0)
0040134C push 0
0040134E mov [esp+30], eax
00401352 call 00401C40 ; g=mirvar(0)
00401357 mov [esp+38], eax
0040135B mov eax, [esp+B4] ; call的第一个参数miracl*
00401362 push 0040F348 ;c3ceab06781ecf3b69ea2103
00401367 push ebx
00401368 mov dword ptr [eax+234], 10 ; IOBASE=0x10
00401372 call 00404A40 ; cinstr(b,40f348)
00401377 push 0040F32C ;7dc79e80d9cbbd7db291643c
0040137C push edi
0040137D call 00404A40 ; cinstr(d,40f32c)
00401382 mov ecx, [esp+3C] ; e
00401386 push 0040F310 ;4a2bee4544261d982d959675
0040138B push ecx ; e
0040138C call 00404A40 ; cinstr(e,40f310)
00401391 push 0040F2F4 ;27ab8cb1f847bbbc412caa33
00401396 push esi ; c
00401397 call 00404A40 ; cinstr(c,40f2f4)
0040139C mov edx, [esp+D8] ; sn
004013A3 add esp, 3C
004013A6 xor eax, eax
004013A8 lea ecx, [edx+2]
004013AB mov dl, [ecx]
004013AD add ecx, 5
004013B0 mov [esp+eax+30], dl ; 从第3个字节,每隔4个,共12个,放到esp+0x30
004013B4 inc eax
004013B5 cmp eax, 0C
004013B8 jl short 004013AB
004013BA mov edi, [esp+9C]
004013C1 or ecx, FFFFFFFF
004013C4 xor eax, eax
004013C6 push ebp ; a
004013C7 repne scas byte ptr es:[edi]
004013C9 not ecx ; ecx是sn的长度
004013CB lea eax, [esp+34] ; 保存的12个字节
004013CF dec ecx
004013D0 push eax
004013D1 push 0C
004013D3 mov byte ptr [esp+48], 0
004013D8 mov esi, ecx
004013DA call 00404670 ; bytes_to_big(12,esp+0x30,a)
004013DF mov ecx, [esp+20] ; f
004013E3 mov edi, [esp+2C] ; c
004013E7 push ecx ; f
004013E8 push ebx ; b
004013E9 push ebp ; a
004013EA push edi ; c
004013EB call 00403740 ; powmod(c,a,b,f)
//计算f=c^a mod b 这时的a是esp+0x30的12个字节
004013F0 push ebp
004013F1 push esi
004013F2 call 00401BC0 ; a=sn size
004013F7 mov edx, [esp+40] ; g
004013FB push edx ; g
004013FC push ebx ; b
004013FD push ebp ; a
004013FE push edi ; c
004013FF call 00403740 ; powmod(c,a,b,g)
//计算g=c^a mod b 这时的a是serial key的长度
00401404 mov eax, [esp+58] ; d
00401408 mov ecx, [esp+48] ; f
0040140C push eax ; d
0040140D push ecx ; f
0040140E call 00402A90 ; compare(f,d)
//比较f,d 不等就出错
//这里实际上就是DLP问题了
//7dc79e80d9cbbd7db291643c=27ab8cb1f847bbbc412caa33^a mod c3ceab06781ecf3b69ea2103
//很容易用Pohlig-Hellman算法解决这个DLP问题
//a=2D2D2D2D2D2D2D2D2D2D2D2D 就是说serial key中有12个'-',从第三位开始,每隔4位
00401413 add esp, 3C
00401416 test eax, eax
00401418 jnz 00401531
0040141E mov edx, [esp+10] ; e
00401422 mov eax, [esp+1C] ; g
00401426 push edx ; e
00401427 push eax ; g
00401428 call 00402A90 ; compare(g,e)
//同样也是DLP问题
//解决得到serial key的长度是0x3E
0040142D add esp, 8
00401430 test eax, eax
00401432 jnz 00401531
00401438 mov ecx, [esp+98] ; miracl* call的参数1
0040143F sub esi, 0C ; sn长度去掉0xc 去掉12个'-'
00401442 xor edi, edi
00401444 mov dword ptr [ecx+234], 24 ; IOBASE=0x24 这里改成36进制'0'-'9' 'A'-'Z'
0040144E xor ecx, ecx
00401450 cmp esi, edi
00401452 mov [esp+18], edi
00401456 jle short 004014BB
00401458 mov eax, esi
0040145A cdq
0040145B sub eax, edx
0040145D sar eax, 1
0040145F dec eax
00401460 mov [esp+28], eax
00401464 mov edx, ecx
00401466 and edx, 80000003
0040146C jns short 00401473
0040146E dec edx
0040146F or edx, FFFFFFFC
00401472 inc edx
00401473 jnz short 0040147D
00401475 test ecx, ecx
00401477 je short 0040147D
00401479 inc dword ptr [esp+18]
0040147D mov eax, ecx
0040147F cdq
00401480 idiv dword ptr [esp+28]
00401484 test edx, edx
00401486 jnz short 0040149A
00401488 mov edx, [esp+9C]
0040148F lea eax, [edi+ecx]
00401492 mov dl, [edi+edx]
00401495 inc edi
00401496 mov [esp+eax+30], dl
0040149A mov eax, [esp+18]
0040149E mov ebx, [esp+9C]
004014A5 add eax, ecx
004014A7 lea edx, [edi+ecx]
004014AA inc ecx
004014AB mov al, [eax+ebx+3]
004014AF cmp ecx, esi
004014B1 mov [esp+edx+30], al
004014B5 jl short 00401464
004014B7 mov ebx, [esp+2C]
004014BB xor edi, edi
004014BD mov byte ptr [esp+esi+30], 0
004014C2 test esi, esi
004014C4 jle short 004014ED
004014C6 movsx ecx, byte ptr [esp+edi+30]
004014CB push ecx
004014CC call 00409A10
004014D1 add esp, 4
004014D4 cmp al, 41
004014D6 mov [esp+edi+30], al
004014DA jl short 004014E0
004014DC cmp al, 5A
004014DE jle short 004014E8
004014E0 cmp al, 30
004014E2 jl short 00401531
004014E4 cmp al, 39
004014E6 jg short 00401531
004014E8 inc edi
004014E9 cmp edi, esi
004014EB jl short 004014C6
004014ED mov eax, esi
004014EF cdq
004014F0 sub eax, edx
004014F2 lea edx, [esp+30]
004014F6 sar eax, 1
//上面是把serial key的同两位交错放到一个串中
//比如12-1234-5678-1234-5678-1234-5678-1234-5678-1234-5678-1234-5678
//交错后1123456781234567812345678和2123456781234567812345678
004014F8 push edx ;交错后的前一半字符串
004014F9 lea esi, [esp+eax+34]
004014FD mov eax, [esp+A4]
00401504 push eax ;A
00401505 mov byte ptr [esi], 0
00401508 call 00404A40 ; cinstr(A,前一半)
0040150D mov ecx, [esp+A4]
00401514 mov eax, [esp+AC]
0040151B push esi ;交错后的后一半字符串
0040151C push eax ;B
0040151D mov dl, [ecx+1]
00401520 mov [esi], dl
00401522 call 00404A40 ; cinstr(B,后一半)
//注意A,B是call 00401300,传进来的参数
00401527 add esp, 10
0040152A mov esi, 1
0040152F jmp short 00401533
00401531 xor esi, esi
00401533 mov ecx, [esp+98]
0040153A push ebp
0040153B mov dword ptr [ecx+234], 10
00401545 call 004024F0 ; mirkill
0040154A push ebx
0040154B call 004024F0 ; mirkill
00401550 mov edx, [esp+28]
00401554 push edx
00401555 call 004024F0 ; mirkill
0040155A mov eax, [esp+30]
0040155E push eax
0040155F call 004024F0 ; mirkill
00401564 mov ecx, [esp+20]
00401568 push ecx
00401569 call 004024F0 ; mirkill
0040156E mov edx, [esp+28]
00401572 push edx
00401573 call 004024F0 ; mirkill
00401578 mov eax, [esp+34]
0040157C push eax
0040157D call 004024F0 ; mirkill
00401582 add esp, 1C
00401585 mov eax, esi
00401587 pop edi
00401588 pop esi
00401589 pop ebp
0040158A pop ebx
0040158B add esp, 84
00401591 retn
至此分析完first check部分,key的格式形如:
12-1234-5678-1234-5678-1234-5678-1234-5678-1234-5678-1234-5678
好了,下面进入ECC部分
=================================================================================================
00401117 add esp, 18
0040111A test eax, eax
0040111C jnz short 0040113B
0040111E push eax
0040111F push edi
00401120 mov [4108C8], eax
00401125 call 00401230
0040112A add esp, 8
0040112D push 0
0040112F push 0040F1D4 ; lamer !!! :)
00401134 push 0040F1A8 ; man,, you did't even past the first check..
00401139 jmp short 00401173
0040113B push ebp ;B
0040113C push ebx ;A
0040113D push esi ;miracl*
0040113E call 004015A0
=================================================================================================
004015A0就是ECC部分了,F7进入后
004015A0 sub esp, 18
004015A3 push ebx
004015A4 push ebp
004015A5 push esi
004015A6 push edi
004015A7 push 0
004015A9 mov dword ptr [4108C4], 0
004015B3 call 00401C40 ; r=mirvar(0)
004015B8 push 1
004015BA mov [esp+24], eax
004015BE call 00401C40 ; a=mirvar(1)
004015C3 push 0
004015C5 mov [esp+2C], eax
004015C9 call 00401C40 ; b=mirvar(0)
004015CE push 0
004015D0 mov [esp+34], eax
004015D4 call 00401C40 ; p=mirvar(0)
004015D9 push 0
004015DB mov ebp, eax
004015DD call 00401C40 ; modn=mirvar(0)
004015E2 push 0
004015E4 mov edi, eax
004015E6 call 00401C40 ; xG=mirvar(0)
004015EB push 0
004015ED mov esi, eax
004015EF call 00401C40 ; xQ=mirvar(0)
004015F4 mov ebx, eax
004015F6 mov eax, [esp+48] ; miracl*
004015FA push 0040F3A8 ;acc00cf0775153b19e037ce879d332bb
004015FF push ebp ; p ECC中的素数
00401600 mov dword ptr [eax+234], 10 ; IOBASE=0x10
0040160A call 00404A40 ; cinstr(p,"ACC00CF0775153B19E037CE879D332BB")
0040160F push edi ; modn
00401610 push 1
00401612 push ebp ; p
00401613 call 00406B90 ; incr(p,1,modn)
//modn是用来进行模运算的一个大数,实际上就是这个椭圆曲线的阶
00401618 push 0040F384 ; 18650a0922fc3ec0b778347b20ee6619
0040161D push esi ; xG
0040161E call 00404A40 ;cinstr(xG,18650A0922FC3EC0B778347B20EE6619)
//xG是G点的横坐标
00401623 push 0040F364 ; d85fa1c5bc8982485acd9fa9b1bebec
00401628 push ebx ; xQ
00401629 call 00404A40 ; cinstr(xQ,D85FA1C5BC8982485ACD9FA9B1BEBEC)
//xQ是Q点的横坐标
0040162E mov ecx, [esp+64] ; b
00401632 mov edx, [esp+60] ; a
00401636 add esp, 40
00401639 push 1
0040163B push ebp
0040163C push ecx
0040163D push edx
0040163E call 00404D60 ; ecurve_init(a,b,p,1)
//这个ecc就是y^2=x^3+x mod p
00401643 call 00404F50 ; G=epoint_init()
00401648 mov [esp+20], eax ; G
0040164C call 00404F50 ; p2=epoint_init()
00401651 mov [esp+24], eax ; p2
00401655 call 00404F50 ; p3=epoint_init()
0040165A mov [esp+3C], eax ; p3
0040165E call 00404F50 ; Q=epoint_init()
00401663 mov [esp+28], eax ; Q
00401667 mov eax, [esp+40] ; A
0040166B push edi
0040166C push eax ; A
0040166D call 00402A90 ; compare(A,modn)
00401672 add esp, 18
00401675 test eax, eax
00401677 jge 00401770 ; A不能大于等于modn
0040167D mov ecx, [esp+34]
00401681 push edi ; B
00401682 push ecx
00401683 call 00402A90 ; compare(B,modn)
00401688 add esp, 8
0040168B test eax, eax
0040168D jge 00401770 ; B不能大于等于modn
00401693 mov edx, [esp+10]
00401697 push edx
00401698 push 0
0040169A push esi
0040169B push esi
0040169C call 00405060 ; epoint_set(xG,xG,0,G)
//设置G点
004016A1 mov eax, [esp+28]
004016A5 push eax ; Q
004016A6 push 1
004016A8 push ebx
004016A9 push ebx
004016AA call 00405060 ; epoint_set(xQ,xQ,1,Q)
//设置Q点
//呵呵,这里Q=k*G,k是破解的关键
//用schoof算法很容易得到ECC的阶,就是modn
//再用Pollard-rho算法计算这个k
//k=1212121255555ABCDEFABCDEF9999999
004016AF mov ecx, [esp+34] ; p2
004016B3 mov edx, [esp+30] ; G
004016B7 mov eax, [esp+54] ; B
004016BB push ecx ; p2
004016BC push edx ; G
004016BD push eax ; B
004016BE call 004062F0 ; ecurve_mult(B,G,p2)
004016C3 mov ecx, [esp+58] ; p3
004016C7 mov edx, [esp+44] ; Q
004016CB mov eax, [esp+5C] ; A
004016CF push ecx ; p3
004016D0 push edx ; Q
004016D1 push eax ; A
004016D2 call 004062F0 ; ecurve_mult(A,Q,p3)
004016D7 mov ecx, [esp+64] ; p3
004016DB mov edx, [esp+4C] ; p2
004016DF push ecx ; p3
004016E0 push edx ; p2
004016E1 call 004055B0 ; ecurve_add(p2,p3) p3=p2+p3
004016E6 mov eax, [esp+6C] ; p3
004016EA add esp, 40
004016ED push esi ; f
004016EE push esi ; f
004016EF push eax ; p3
004016F0 call 00405300 ; epoint_get(p3,f,f)
004016F5 mov ecx, [esp+3C] ; A
004016F9 push esi ; f
004016FA push esi ; f
004016FB push ecx ; A
004016FC call 00406B20 ; subtract(A,f,f)
00401701 push edi ; modn
00401702 push edi ; modn
00401703 push esi ; f
00401704 call 004072D0 ; divide(f,modn,modn)
00401709 mov edx, [esp+40] ; r
0040170D push edx ; r
0040170E push esi ; f
0040170F call 00402A90 ; compare(f,r)
00401714 add esp, 2C
00401717 test eax, eax
00401719 jge short 00401726 ; 大于0跳转
0040171B push esi ; f
0040171C push edi ; modn
0040171D push esi ; f
0040171E call 00406960 ; add(f,modn,f) 保证f大于0
00401723 add esp, 0C
00401726 xor eax, eax
00401728 mov [4107C8], eax
0040172D mov [4107CC], eax
00401732 mov [4107D0], eax
00401737 mov [4107D4], eax
0040173C push eax
0040173D push 004107C8
00401742 push esi
00401743 push 32
00401745 mov [4107D8], eax
0040174A call 004047F0 ; big_to_bytes(0x32,f,0x4107c8,0)
0040174F mov ecx, [4107C8] ; 头4个字节DWORD
00401755 add esp, 10
00401758 xor ecx, 46434846
0040175E cmp ecx, 6B040512
//6B040512^46434846=2D474D54 "TMG-" 也就是说头4字节的DWORD=0x2D474D54才成功
00401764 jnz short 00401770
00401766 mov dword ptr [4108C4], 004107CC
00401770 mov edx, [esp+10]
00401774 push edx
00401775 call 00405020
0040177A mov eax, [esp+18]
0040177E push eax
0040177F call 00405020
00401784 mov ecx, [esp+34]
00401788 push ecx
00401789 call 00405020
0040178E mov edx, [esp+24]
00401792 push edx
00401793 call 00405020
00401798 mov eax, [esp+2C]
0040179C push eax
0040179D call 004024F0
004017A2 mov ecx, [esp+34]
004017A6 push ecx
004017A7 call 004024F0
004017AC mov edx, [esp+3C]
004017B0 push edx
004017B1 call 004024F0
004017B6 push ebp
004017B7 call 004024F0
004017BC push edi
004017BD call 004024F0
004017C2 push esi
004017C3 call 004024F0
004017C8 push ebx
004017C9 call 004024F0
004017CE mov eax, [4108C4]
004017D3 add esp, 2C ; (initial cpu selection)
004017D6 pop edi
004017D7 pop esi
004017D8 pop ebp
004017D9 pop ebx
004017DA add esp, 18
004017DD retn
ECC部分也已经分析完了,破解的关键就是那个"TMG-",头4个字节一定要是这个
=================================================================================================
00401143 push eax
00401144 push edi
00401145 mov [4108C8], eax
0040114A call 00401230
0040114F mov eax, [4108C8]
00401154 add esp, 14
00401157 test eax, eax
00401159 push 0
0040115B je short 00401169
0040115D push 0040F19C ; good job!
00401162 push 0040F17C ; yeah you did it. key is good.
00401167 jmp short 00401173
00401169 push 0040F16C ; error in key
0040116E push 0040F154 ; bad key, try again..
00401173 push edi
00401174 call [<&user32.MessageBoxA>] ; user32.MessageBoxA
0040117A push ebx
0040117B call 004024F0
00401180 push ebp
00401181 call 004024F0
00401186 add esp, 8
00401189 call 00402510
0040118E pop ebx
0040118F pop edi
00401190 pop esi
00401191 xor eax, eax
00401193 pop ebp
00401194 retn 10
【破解】
破解这个crackme,首先得构在一个"TMG-"开头的大数r,后面用随机数填充。
随便构造大数A1,B1,计算P=A1*Q+B1*G,得到P.x,那么真正的A就是r+P.x,这个很好理解,剩下来就是找B
很明显
A*Q+B*G=A1*Q+B1*G
=>B*G=A1*Q+B1*G-A*Q 这里由于已经解决了Q=key*G的问题,所以
=>B*G=A1*key*G+B1*G-A*key*G
=>B=A1*key+B1-A*key
B=A1*key+B1-A*key是在modn下的运算,找到A,B后再把它们还原成serial key就可以了,具体就注册机代码。
谢谢你看到这里。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课