【破解作者】 农夫
【破解目标】 PYCG论坛的会员认证Crackme
【破解工具】 Olldbg1.10 、Peid0.92、UPXshell3.10
【破解平台】 win2000 sp4
【破解声明】 只供学习和交流,没有其他目的。不妥之处敬请原谅!
【破解内容】
1.用PEiD查看Key-Crackme2.exe文件,发现是UPX0.89.6-1.02/1.05-1.24 -> Markus & Laszlo的壳。
2.用UPXshell将其脱壳,双击解压文件可以运行,脱壳成功。
3.用OllyDbg将解压文件加载。
直接下断点:bp GetDlgItemTextA,按F9运行等到Key-Crackme2程序窗口弹出,在其上“DlgItem”框内输入
“abcdefgh”,下“DlgItem”框内输入“12345678”,按“CHECK”钮,OK,进入断点。按F8,直到程序返回到用户程序,
并且继续按F8直到取完两个“DlgItem”的数据。得如下程序段:
004012B1 |. 6A 40 push 40 ; /Count = 40 (64.)
004012B3 |. 68 38304000 push Key-Crac.00403038 ; |Buffer = Key-Crac.00403038 ;保存第一个“DlgItem”数据的BUFFER
004012B8 |. 6A 6A push 6A ; |ControlID = 6A (106.)
004012BA |. FF75 08 push dword ptr ss:[ebp+8] ; |hWnd
004012BD |. E8 08010000 call <jmp.&USER32.GetDlgItemTextA> ; \GetDlgItemTextA ;获取第一个“DlgItem”的数据字符。
004012C2 |. 83F8 00 cmp eax,0 ;检测是否有数据
004012C5 |. 74 18 je short Key-Crac.004012DF ;没有则去显示输入的提示
004012C7 |. 6A 40 push 40 ; /Count = 40 (64.)
004012C9 |. 68 38314000 push Key-Crac.00403138 ; |Buffer = Key-Crac.00403138 ;保存第二个“DlgItem”数据的BUFFER
004012CE |. 6A 6B push 6B ; |ControlID = 6B (107.)
004012D0 |. FF75 08 push dword ptr ss:[ebp+8] ; |hWnd
004012D3 |. E8 F2000000 call <jmp.&USER32.GetDlgItemTextA> ; \GetDlgItemTextA ;获取第二个“DlgItem”的数据字符。
004012D8 |. 83F8 00 cmp eax,0 ;检测是否有数据
004012DB |. 74 02 je short Key-Crac.004012DF ;没有则去显示输入的提示
004012DD |. EB 17 jmp short Key-Crac.004012F6
004012DF |> 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
004012E1 |. 68 62344000 push Key-Crac.00403462 ; |Title = "Key/CrackMe #2 "
004012E6 |. 68 00304000 push Key-Crac.00403000 ; |Text = " Please Fill in 1 more Char!!"
004012EB |. 6A 00 push 0 ; |hOwner = NULL
004012ED |. E8 FC000000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
004012F2 |. C9 leave
004012F3 |. C2 1000 retn 10
004012F6 |> 68 38304000 push Key-Crac.00403038 ; /String = "abcdefgh" <----;内存00403038处的内容,第一个“DlgItem”的数据
004012FB |. E8 30010000 call <jmp.&KERNEL32.lstrlenA> ; \lstrlenA ;取第一个“DlgItem”的字符串的长度
00401300 |. 33F6 xor esi,esi ;寄存器清零,准备开始计算。
00401302 |. 8BC8 mov ecx,eax ;长度(位数)放于计数器ECX
00401304 |. B8 01000000 mov eax,1 ;开始索引值为1
00401309 |> 8B15 38304000 /mov edx,dword ptr ds:[403038] ;取BUFFER里的双字字符到EDX
0040130F |. 8A90 37304000 |mov dl,byte ptr ds:[eax+403037] ;取BUFFER里的一个字节字符到DL
00401315 |. 81E2 FF000000 |and edx,0FF ;清除EDX的高位值,即只用DL的值
0040131B |. 8BDA |mov ebx,edx
0040131D |. 0FAFDA |imul ebx,edx ;EDX*EDX
00401320 |. 03F3 |add esi,ebx ;ESI+EDX*EDX
00401322 |. 8BDA |mov ebx,edx
00401324 |. D1FB |sar ebx,1 ;EDX/2
00401326 |. 03F3 |add esi,ebx ;ESI+EDX*EDX+EDX/2
00401328 |. 2BF2 |sub esi,edx ;ESI+EDX*EDX+EDX/2-EDX
0040132A |. 40 |inc eax ;地址索引值加1
0040132B |. 49 |dec ecx ;位数减1
0040132C |.^ 75 DB \jnz short Key-Crac.00401309 ;位数不为0则继续,直到ECX=0
0040132E |. 56 push esi ;计数完,计算值放于ESI
0040132F |. 68 38314000 push Key-Crac.00403138 ; ASCII "12345678" <---------;内存00403138处的内容,第二个“DlgItem”的数据
00401334 |. E8 4A000000 call Key-Crac.00401383 ;这个CALL里是计算第二个“DlgItem”数据的值,到下面一段程序401383处
00401339 |. 5E pop esi ;取出第一个“DlgItem”的数据的解码值
0040133A |. 3BC6 cmp eax,esi ;与第二个“DlgItem”的数据的解码值相比较
0040133C |. 75 15 jnz short Key-Crac.00401353 ;不相等则出错
0040133E |. 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL ;相等则注册成功!
00401340 |. 68 62344000 push Key-Crac.00403462 ; |Title = "Key/CrackMe #2 "
00401345 |. 68 B8344000 push Key-Crac.004034B8 ; |Text = " Good Job, I Wish You the Very Best"
0040134A |. 6A 00 push 0 ; |hOwner = NULL
0040134C |. E8 9D000000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
00401351 |. EB 13 jmp short Key-Crac.00401366
00401353 |> 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
00401355 |. 68 62344000 push Key-Crac.00403462 ; |Title = "Key/CrackMe #2 "
0040135A |. 68 86344000 push Key-Crac.00403486 ; |Text = " You Have Enter A Wrong Serial, Please Try Again "
0040135F |. 6A 00 push 0 ; |hOwner = NULL
00401361 |. E8 88000000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
00401366 |> EB 15 jmp short Key-Crac.0040137D
00401368 |> FF75 14 push dword ptr ss:[ebp+14] ; /lParam
0040136B |. FF75 10 push dword ptr ss:[ebp+10] ; |wParam
0040136E |. FF75 0C push dword ptr ss:[ebp+C] ; |Message
00401371 |. FF75 08 push dword ptr ss:[ebp+8] ; |hWnd
00401374 |. E8 3F000000 call <jmp.&USER32.DefWindowProcA> ; \DefWindowProcA
00401379 |. C9 leave
0040137A |. C2 1000 retn 10
0040137D |> 33C0 xor eax,eax
0040137F |. C9 leave
00401380 \. C2 1000 retn 10
00401383 /$ 55 push ebp
00401384 |. 8BEC mov ebp,esp
00401386 |. FF75 08 push dword ptr ss:[ebp+8] ; /String
00401389 |. E8 A2000000 call <jmp.&KERNEL32.lstrlenA> ; \lstrlenA ;取第二个“DlgItem”的字符串的长度
0040138E |. 53 push ebx
0040138F |. 33DB xor ebx,ebx ;寄存器清零,准备开始计算。
00401391 |. 8BC8 mov ecx,eax ;长度(为数)放于计数器ECX
00401393 |. 8B75 08 mov esi,dword ptr ss:[ebp+8] ;取BUFFER里的双字字符于ESI
00401396 |> 51 /push ecx ;保存长度(为数),两重计数
00401397 |. 33C0 |xor eax,eax ;清EAX
00401399 |. AC |lods byte ptr ds:[esi] ;取BUFFER里的一个字节字符于EAX
0040139A |. 83E8 30 |sub eax,30 ;EAX=EAX-30
0040139D |. 49 |dec ecx ;内层计数减1
0040139E |. 74 05 |je short Key-Crac.004013A5 ;内层计数值为0,则去计算总数
004013A0 |> 6BC0 0A |/imul eax,eax,0A ;内层计数值不为0,则计算:EAX*0A(10)
004013A3 |.^ E2 FB |\loopd short Key-Crac.004013A0 ;一直循环,即EAX*0A^(ECX-1)(10的(ECX-1)次方)
004013A5 |> 03D8 |add ebx,eax ;EBX+EAX*0A^(ECX-1)
004013A7 |. 59 |pop ecx ;外层计数值
004013A8 |.^ E2 EC \loopd short Key-Crac.00401396 ;外层计数不为0,则继续 EAX*0A^(ECX-1)+EAX*0A^(ECX-2)+EAX*0A^(ECX-3)+...+EAX*0A^(ECX-ECX)
004013AA |. 8BC3 mov eax,ebx ;外层计数为0,则保存计算值于EAX
004013AC |. 5B pop ebx
004013AD |. C9 leave
004013AE \. C2 0400 retn 4
【破解总结】
算法一与算法二的计算值相等,算法一用公式来表示是这样的:
(a7^2+a7/2-a7)+(a6^2+a6/2-a6)+(a5^2+a5/2-a5)+(a4^2+a4/2-a4)+(a3^2+a3/2-a3)+(a2^2+a2/2-a2)+(a1^2+a1/2-a1)+(a0^2+a0/2-a0)
只不过是一种数值的变换处理。问题是在第二个算法上,将算法二的公式用简易的表示方法来表示就是:
a7*10^7+a6*10^6+a5*10^5+a4*10^4+a3*10^3+a2*10^2+a1*10^1+a0
也就是:
(((((((a7*10)+a6)*10+a5)*10+a4)*10+a3)*10+a2)*10+a1)*10+a0
这也就是一个十六进制数的十进制表示法。意思就是将算法一的计算值的十六进制数用十进制数来表示。
于是将算法一的计算值除以10求余即得算法二的计算值。
"abcdefgh"的计算值是13A38,将其转换成十进制数就是80440。
算法二转换的结果也就是第二个“DlgItem”框所需的数据了。
附件:Key-Crackme2.rar
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法