-
-
[原创]分析论坛中一个简单的crackme
-
发表于: 2012-5-2 01:04 2345
-
【文章标题】: 分析一个crackme
【文章作者】: zjw023
【软件名称】: ncrackme.exe
【下载地址】: http://bbs.pediy.com/upload/files/1084801702.zip
【作者声明】: 感谢riijj提供的crackme教学贴,自己分析了好久,做出来还是很兴奋的。
直接到算法部分进行分析
00401230 /$ 8B0D BC564000 mov ecx,dword ptr ds:[4056BC]
00401236 |. 83EC 30 sub esp,30
00401239 |. 8D4424 00 lea eax,dword ptr ss:[esp]
0040123D |. 53 push ebx
0040123E |. 56 push esi
0040123F |. 8B35 94404000 mov esi,dword ptr ds:[<&USER32.GetD>; USER32.GetDlgItemTextA
00401245 |. 6A 10 push 10 ; /Count = 10 (16.)
00401247 |. 50 push eax ; |Buffer
00401248 |. 68 E8030000 push 3E8 ; |ControlID = 3E8 (1000.)
0040124D |. 51 push ecx ; |hWnd => 001404AC (class='#32770',parent=00150494)
0040124E |. 33DB xor ebx,ebx ; |
00401250 |. FFD6 call esi ; \GetDlgItemTextA
00401252 |. 83F8 03 cmp eax,3
00401255 |. 73 0B jnb short ncrackme.00401262
00401257 |. 5E pop esi
00401258 |. B8 01000000 mov eax,1
0040125D |. 5B pop ebx
0040125E |. 83C4 30 add esp,30
00401261 |. C3 retn
00401262 |> A1 BC564000 mov eax,dword ptr ds:[4056BC]
00401267 |. 8D5424 28 lea edx,dword ptr ss:[esp+28]
0040126B |. 6A 10 push 10
0040126D |. 52 push edx
0040126E |. 68 E9030000 push 3E9
00401273 |. 50 push eax
00401274 |. FFD6 call esi
00401276 |. 0FBE4424 08 movsx eax,byte ptr ss:[esp+8] ; eax=name[0]
0040127B |. 0FBE4C24 09 movsx ecx,byte ptr ss:[esp+9] ; ecx=name[1]
00401280 |. 99 cdq ; edx:eax 此时dx置0了
00401281 |. F7F9 idiv ecx ; (edx:eax)/=ecx
00401283 |. 8BCA mov ecx,edx ; ecx存放余数
00401285 |. 83C8 FF or eax,FFFFFFFF ; eax全位置1
00401288 |. 0FBE5424 0A movsx edx,byte ptr ss:[esp+A] ; edx=name[2]
0040128D |. 0FAFCA imul ecx,edx ; ecx*=edx
00401290 |. 41 inc ecx ; ecx++
00401291 |. 33D2 xor edx,edx ; edx=0;
00401293 |. F7F1 div ecx ; (edx:eax)/=ecx
00401295 |. 50 push eax ; 商入栈
00401296 |. E8 A5000000 call ncrackme.00401340 ; 转存内容到【4050AC】
0040129B |. 83C4 04 add esp,4 ; esp=esp+4
0040129E |. 33F6 xor esi,esi ; esi=0;
004012A0 |> E8 A5000000 /call ncrackme.0040134A ; 循环开始处
004012A5 |. 99 |cdq
004012A6 |. B9 1A000000 |mov ecx,1A ; ecx=1a 中间常量
004012AB |. F7F9 |idiv ecx ; eax/=ecx,余数在dx里
004012AD |. 80C2 41 |add dl,41 ; dl+=41
004012B0 |. 885434 18 |mov byte ptr ss:[esp+esi+18],dl ; 每次循环dl的值存入key[esi]
004012B4 |. 46 |inc esi ; esi++
004012B5 |. 83FE 0F |cmp esi,0F ; esi<0f
004012B8 |.^ 72 E6 \jb short ncrackme.004012A0 ; 小于的话就循环
004012BA |. 57 push edi
004012BB |. 8D7C24 0C lea edi,dword ptr ss:[esp+C] ; edi=name[]
004012BF |. 83C9 FF or ecx,FFFFFFFF ; ecx全位置1
004012C2 |. 33C0 xor eax,eax ; eax=0
004012C4 |. 33F6 xor esi,esi ; esi=0
004012C6 |. F2:AE repne scas byte ptr es:[edi]
004012C8 |. F7D1 not ecx ; ecx取反
004012CA |. 49 dec ecx ; ecx--;此时得到len
004012CB |. 74 59 je short ncrackme.00401326 ; {-------大循环开始
004012CD |> 8A4434 0C /mov al,byte ptr ss:[esp+esi+C] ; al=【esp+c+变量esi】,即name[esi]
004012D1 |. C0F8 05 |sar al,5 ; al算数右移5
004012D4 |. 0FBEC0 |movsx eax,al ; eax高位置0
004012D7 |. 8D1480 |lea edx,dword ptr ds:[eax+eax*4] ; edx=eax*5;
004012DA |. 8D04D0 |lea eax,dword ptr ds:[eax+edx*8] ; eax=(eax+edx*8)*3
004012DD |. 8D0440 |lea eax,dword ptr ds:[eax+eax*2]
004012E0 |. 85C0 |test eax,eax ; eax是否为0
004012E2 |. 7E 0A |jle short ncrackme.004012EE ; 不为0不跳,此时没跳
004012E4 |. 8BF8 |mov edi,eax ; edi=eax
004012E6 |> E8 5F000000 |/call ncrackme.0040134A ; 小循环 { 对【4050AC】地址进行重存放,并改变eax
004012EB |. 4F ||dec edi ; edi--
004012EC |.^ 75 F8 |\jnz short ncrackme.004012E6 ; 小循环 } //edi为循环次数
004012EE |> E8 57000000 |call ncrackme.0040134A ; 循环结束后再进行一次重存放
004012F3 |. 99 |cdq ; edx置为0
004012F4 |. B9 1A000000 |mov ecx,1A ; ecx=1a
004012F9 |. 8D7C24 0C |lea edi,dword ptr ss:[esp+C] ; edi=name[]
004012FD |. F7F9 |idiv ecx ; (edx:eax)/=ecx
004012FF |. 0FBE4C34 2C |movsx ecx,byte ptr ss:[esp+esi+2C] ; ecx=psw[esi]
00401304 |. 80C2 41 |add dl,41 ; 余数dl+=41
00401307 |. 0FBEC2 |movsx eax,dl ; eax=dl
0040130A |. 2BC1 |sub eax,ecx ; eax-=ecx 为使后面eax为0,则此处eax要等于ecx
0040130C |. 885434 1C |mov byte ptr ss:[esp+esi+1C],dl ; key[esi]=dl
00401310 |. 99 |cdq ; 若eax最高位为1,则edx全位为1,否则全位为0
00401311 |. 33C2 |xor eax,edx ; eax异或edx 取绝对值
00401313 |. 83C9 FF |or ecx,FFFFFFFF ; ecx全位置1
00401316 |. 2BC2 |sub eax,edx ; eax-=edx
00401318 |. 03D8 |add ebx,eax ; ebx+=eax 要使后面sum为0,则eax==edx
0040131A |. 33C0 |xor eax,eax ; eax=0
0040131C |. 46 |inc esi ; esi++
0040131D |. F2:AE |repne scas byte ptr es:[edi]
0040131F |. F7D1 |not ecx ; ecx取反
00401321 |. 49 |dec ecx ; ecx--
00401322 |. 3BF1 |cmp esi,ecx ; while(esi<ecx) 继续大循环
00401324 |.^ 72 A7 \jb short ncrackme.004012CD
00401326 |> 5F pop edi ; }-------大循环结束
00401327 |. 8BC3 mov eax,ebx
00401329 |. 5E pop esi
0040132A |. 5B pop ebx
0040132B |. 83C4 30 add esp,30
0040132E \. C3 retn ; 此时这边eax要为0才行,即上面的sum要为0
分析了一下之后,发现算法并不容易。由下面的那段测试段可以看出,通过测试的函数后若eax为0则过,否则报错。但函数中的运算并没有直接得到,eax由一堆运算得出。
00401064 . E8 C7010000 call ncrackme.00401230 ; 进行比较测试的函数
00401069 . 85C0 test eax,eax ; 若eax为0则对
0040106B . 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
0040106D . 68 80504000 push ncrackme.00405080 ; |Title = "ncrackme"
00401072 . 75 1B jnz short ncrackme.0040108F ; |跳了就错
00401074 . A1 B8564000 mov eax,dword ptr ds:[4056B8] ; |
00401079 . 68 64504000 push ncrackme.00405064 ; |Text = "Registration successful."
0040107E . 50 push eax ; |hOwner => 000A0494 ('Newbie smallsize crackme - v1',class='myWindowClass')
0040107F . FF15 C0404000 call dword ptr ds:[<&USER32.Message>; \MessageBoxA
00401085 . E8 A6020000 call ncrackme.00401330
0040108A . 33C0 xor eax,eax
0040108C . C2 1000 retn 10
0040108F > 8B0D B8564000 mov ecx,dword ptr ds:[4056B8] ; |
00401095 . 68 50504000 push ncrackme.00405050 ; |Text = "Registration fail."
0040109A . 51 push ecx ; |hOwner => 000A0494 ('Newbie smallsize crackme - v1',class='myWindowClass')
0040109B . FF15 C0404000 call dword ptr ds:[<&USER32.Message>; \MessageBoxA
004010A1 . 33C0 xor eax,eax
004010A3 . C2 1000 retn 10
虽然是个比较简单的才crackme,若直接爆破直接在关键跳jnz short ncrackme.0040108F处改jnz为jz就行。
但算法部分不好研究,就像文章中每个字都认识,但连在一起就不知道讲什么一样。
还需要对算法继续进行分析。待会继续。
---------------------------------------------------------------------------------
弄了好久,把这汇编代码重新写成c语言代码,发现单纯的写没办法解决问题,前面还想说是不是要用蛮力法找结果。
后面经过认真分析,发现ebx这个被我当成sum的东西没什么用,虽然最后确实是要让sum为0才能解决问题,但是问题完全可以避免处理sum。
要使sum为0,则前面一点点额eax要等于edx。要让eax==edx,注意到00401310处cdq指令,eax全为1或者全为0,edx才会跟eax相等,即eax要为0。
要使eax为0,看前面0040130A处eax-=ecx,则eax==ecx,前面三行提示ecx此时存放的就是key,只要这每个key跟eax相等后面条件即成立。
下断点记录每个值。OK...
----------------------------------------------------------------------------------
大气那个喘啊,不是明文的算法分析了好久。
把分析出来的c语言代码稍微改下,权当注册机用了。
#include<stdio.h>
main()
{
int i,j,k,len;
char name[20],psw[20],key[20];
long ax,cx,sum,dx,loc;
printf("name:");
scanf("%s",name);
sum=0;
ax=name[0];
cx=name[1];
cx=ax%cx;
loc=0x002266f0;
ax|=0xffffffff;
cx=cx*name[2]+1;
for(i=0;i<0x0f;i++)
{
ax=loc;
ax=ax*0x343FD;
ax+=0x269EC3;
loc=ax;
ax>>=0x10;
ax&=0x7fff;
key[i]=ax%0x1a+0x41;
}
len=strlen(name);
for(i=0;i<len;i++)
{
ax=name[i];
ax>>=5;
ax&=0x0ff;
dx=ax*5;
ax=(ax+dx*8)*3;
if(ax==0)break;
k=ax;
for(j=0;j<=k;j++)
{
ax=loc;
ax=ax*0x343FD;
ax+=0x269EC3;
loc=ax;
ax>>=0x10;
ax&=0x7fff;
}
dx=ax%0x1a+0x41;
printf("%c",dx);//计算每位码值
ax=dx-psw[i];
key[i]=dx;
sum+=ax;
}
printf("\n");
getchar();
}
1084801702.zip
【文章作者】: zjw023
【软件名称】: ncrackme.exe
【下载地址】: http://bbs.pediy.com/upload/files/1084801702.zip
【作者声明】: 感谢riijj提供的crackme教学贴,自己分析了好久,做出来还是很兴奋的。
直接到算法部分进行分析
00401230 /$ 8B0D BC564000 mov ecx,dword ptr ds:[4056BC]
00401236 |. 83EC 30 sub esp,30
00401239 |. 8D4424 00 lea eax,dword ptr ss:[esp]
0040123D |. 53 push ebx
0040123E |. 56 push esi
0040123F |. 8B35 94404000 mov esi,dword ptr ds:[<&USER32.GetD>; USER32.GetDlgItemTextA
00401245 |. 6A 10 push 10 ; /Count = 10 (16.)
00401247 |. 50 push eax ; |Buffer
00401248 |. 68 E8030000 push 3E8 ; |ControlID = 3E8 (1000.)
0040124D |. 51 push ecx ; |hWnd => 001404AC (class='#32770',parent=00150494)
0040124E |. 33DB xor ebx,ebx ; |
00401250 |. FFD6 call esi ; \GetDlgItemTextA
00401252 |. 83F8 03 cmp eax,3
00401255 |. 73 0B jnb short ncrackme.00401262
00401257 |. 5E pop esi
00401258 |. B8 01000000 mov eax,1
0040125D |. 5B pop ebx
0040125E |. 83C4 30 add esp,30
00401261 |. C3 retn
00401262 |> A1 BC564000 mov eax,dword ptr ds:[4056BC]
00401267 |. 8D5424 28 lea edx,dword ptr ss:[esp+28]
0040126B |. 6A 10 push 10
0040126D |. 52 push edx
0040126E |. 68 E9030000 push 3E9
00401273 |. 50 push eax
00401274 |. FFD6 call esi
00401276 |. 0FBE4424 08 movsx eax,byte ptr ss:[esp+8] ; eax=name[0]
0040127B |. 0FBE4C24 09 movsx ecx,byte ptr ss:[esp+9] ; ecx=name[1]
00401280 |. 99 cdq ; edx:eax 此时dx置0了
00401281 |. F7F9 idiv ecx ; (edx:eax)/=ecx
00401283 |. 8BCA mov ecx,edx ; ecx存放余数
00401285 |. 83C8 FF or eax,FFFFFFFF ; eax全位置1
00401288 |. 0FBE5424 0A movsx edx,byte ptr ss:[esp+A] ; edx=name[2]
0040128D |. 0FAFCA imul ecx,edx ; ecx*=edx
00401290 |. 41 inc ecx ; ecx++
00401291 |. 33D2 xor edx,edx ; edx=0;
00401293 |. F7F1 div ecx ; (edx:eax)/=ecx
00401295 |. 50 push eax ; 商入栈
00401296 |. E8 A5000000 call ncrackme.00401340 ; 转存内容到【4050AC】
0040129B |. 83C4 04 add esp,4 ; esp=esp+4
0040129E |. 33F6 xor esi,esi ; esi=0;
004012A0 |> E8 A5000000 /call ncrackme.0040134A ; 循环开始处
004012A5 |. 99 |cdq
004012A6 |. B9 1A000000 |mov ecx,1A ; ecx=1a 中间常量
004012AB |. F7F9 |idiv ecx ; eax/=ecx,余数在dx里
004012AD |. 80C2 41 |add dl,41 ; dl+=41
004012B0 |. 885434 18 |mov byte ptr ss:[esp+esi+18],dl ; 每次循环dl的值存入key[esi]
004012B4 |. 46 |inc esi ; esi++
004012B5 |. 83FE 0F |cmp esi,0F ; esi<0f
004012B8 |.^ 72 E6 \jb short ncrackme.004012A0 ; 小于的话就循环
004012BA |. 57 push edi
004012BB |. 8D7C24 0C lea edi,dword ptr ss:[esp+C] ; edi=name[]
004012BF |. 83C9 FF or ecx,FFFFFFFF ; ecx全位置1
004012C2 |. 33C0 xor eax,eax ; eax=0
004012C4 |. 33F6 xor esi,esi ; esi=0
004012C6 |. F2:AE repne scas byte ptr es:[edi]
004012C8 |. F7D1 not ecx ; ecx取反
004012CA |. 49 dec ecx ; ecx--;此时得到len
004012CB |. 74 59 je short ncrackme.00401326 ; {-------大循环开始
004012CD |> 8A4434 0C /mov al,byte ptr ss:[esp+esi+C] ; al=【esp+c+变量esi】,即name[esi]
004012D1 |. C0F8 05 |sar al,5 ; al算数右移5
004012D4 |. 0FBEC0 |movsx eax,al ; eax高位置0
004012D7 |. 8D1480 |lea edx,dword ptr ds:[eax+eax*4] ; edx=eax*5;
004012DA |. 8D04D0 |lea eax,dword ptr ds:[eax+edx*8] ; eax=(eax+edx*8)*3
004012DD |. 8D0440 |lea eax,dword ptr ds:[eax+eax*2]
004012E0 |. 85C0 |test eax,eax ; eax是否为0
004012E2 |. 7E 0A |jle short ncrackme.004012EE ; 不为0不跳,此时没跳
004012E4 |. 8BF8 |mov edi,eax ; edi=eax
004012E6 |> E8 5F000000 |/call ncrackme.0040134A ; 小循环 { 对【4050AC】地址进行重存放,并改变eax
004012EB |. 4F ||dec edi ; edi--
004012EC |.^ 75 F8 |\jnz short ncrackme.004012E6 ; 小循环 } //edi为循环次数
004012EE |> E8 57000000 |call ncrackme.0040134A ; 循环结束后再进行一次重存放
004012F3 |. 99 |cdq ; edx置为0
004012F4 |. B9 1A000000 |mov ecx,1A ; ecx=1a
004012F9 |. 8D7C24 0C |lea edi,dword ptr ss:[esp+C] ; edi=name[]
004012FD |. F7F9 |idiv ecx ; (edx:eax)/=ecx
004012FF |. 0FBE4C34 2C |movsx ecx,byte ptr ss:[esp+esi+2C] ; ecx=psw[esi]
00401304 |. 80C2 41 |add dl,41 ; 余数dl+=41
00401307 |. 0FBEC2 |movsx eax,dl ; eax=dl
0040130A |. 2BC1 |sub eax,ecx ; eax-=ecx 为使后面eax为0,则此处eax要等于ecx
0040130C |. 885434 1C |mov byte ptr ss:[esp+esi+1C],dl ; key[esi]=dl
00401310 |. 99 |cdq ; 若eax最高位为1,则edx全位为1,否则全位为0
00401311 |. 33C2 |xor eax,edx ; eax异或edx 取绝对值
00401313 |. 83C9 FF |or ecx,FFFFFFFF ; ecx全位置1
00401316 |. 2BC2 |sub eax,edx ; eax-=edx
00401318 |. 03D8 |add ebx,eax ; ebx+=eax 要使后面sum为0,则eax==edx
0040131A |. 33C0 |xor eax,eax ; eax=0
0040131C |. 46 |inc esi ; esi++
0040131D |. F2:AE |repne scas byte ptr es:[edi]
0040131F |. F7D1 |not ecx ; ecx取反
00401321 |. 49 |dec ecx ; ecx--
00401322 |. 3BF1 |cmp esi,ecx ; while(esi<ecx) 继续大循环
00401324 |.^ 72 A7 \jb short ncrackme.004012CD
00401326 |> 5F pop edi ; }-------大循环结束
00401327 |. 8BC3 mov eax,ebx
00401329 |. 5E pop esi
0040132A |. 5B pop ebx
0040132B |. 83C4 30 add esp,30
0040132E \. C3 retn ; 此时这边eax要为0才行,即上面的sum要为0
分析了一下之后,发现算法并不容易。由下面的那段测试段可以看出,通过测试的函数后若eax为0则过,否则报错。但函数中的运算并没有直接得到,eax由一堆运算得出。
00401064 . E8 C7010000 call ncrackme.00401230 ; 进行比较测试的函数
00401069 . 85C0 test eax,eax ; 若eax为0则对
0040106B . 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
0040106D . 68 80504000 push ncrackme.00405080 ; |Title = "ncrackme"
00401072 . 75 1B jnz short ncrackme.0040108F ; |跳了就错
00401074 . A1 B8564000 mov eax,dword ptr ds:[4056B8] ; |
00401079 . 68 64504000 push ncrackme.00405064 ; |Text = "Registration successful."
0040107E . 50 push eax ; |hOwner => 000A0494 ('Newbie smallsize crackme - v1',class='myWindowClass')
0040107F . FF15 C0404000 call dword ptr ds:[<&USER32.Message>; \MessageBoxA
00401085 . E8 A6020000 call ncrackme.00401330
0040108A . 33C0 xor eax,eax
0040108C . C2 1000 retn 10
0040108F > 8B0D B8564000 mov ecx,dword ptr ds:[4056B8] ; |
00401095 . 68 50504000 push ncrackme.00405050 ; |Text = "Registration fail."
0040109A . 51 push ecx ; |hOwner => 000A0494 ('Newbie smallsize crackme - v1',class='myWindowClass')
0040109B . FF15 C0404000 call dword ptr ds:[<&USER32.Message>; \MessageBoxA
004010A1 . 33C0 xor eax,eax
004010A3 . C2 1000 retn 10
虽然是个比较简单的才crackme,若直接爆破直接在关键跳jnz short ncrackme.0040108F处改jnz为jz就行。
但算法部分不好研究,就像文章中每个字都认识,但连在一起就不知道讲什么一样。
还需要对算法继续进行分析。待会继续。
---------------------------------------------------------------------------------
弄了好久,把这汇编代码重新写成c语言代码,发现单纯的写没办法解决问题,前面还想说是不是要用蛮力法找结果。
后面经过认真分析,发现ebx这个被我当成sum的东西没什么用,虽然最后确实是要让sum为0才能解决问题,但是问题完全可以避免处理sum。
要使sum为0,则前面一点点额eax要等于edx。要让eax==edx,注意到00401310处cdq指令,eax全为1或者全为0,edx才会跟eax相等,即eax要为0。
要使eax为0,看前面0040130A处eax-=ecx,则eax==ecx,前面三行提示ecx此时存放的就是key,只要这每个key跟eax相等后面条件即成立。
下断点记录每个值。OK...
----------------------------------------------------------------------------------
大气那个喘啊,不是明文的算法分析了好久。
把分析出来的c语言代码稍微改下,权当注册机用了。
#include<stdio.h>
main()
{
int i,j,k,len;
char name[20],psw[20],key[20];
long ax,cx,sum,dx,loc;
printf("name:");
scanf("%s",name);
sum=0;
ax=name[0];
cx=name[1];
cx=ax%cx;
loc=0x002266f0;
ax|=0xffffffff;
cx=cx*name[2]+1;
for(i=0;i<0x0f;i++)
{
ax=loc;
ax=ax*0x343FD;
ax+=0x269EC3;
loc=ax;
ax>>=0x10;
ax&=0x7fff;
key[i]=ax%0x1a+0x41;
}
len=strlen(name);
for(i=0;i<len;i++)
{
ax=name[i];
ax>>=5;
ax&=0x0ff;
dx=ax*5;
ax=(ax+dx*8)*3;
if(ax==0)break;
k=ax;
for(j=0;j<=k;j++)
{
ax=loc;
ax=ax*0x343FD;
ax+=0x269EC3;
loc=ax;
ax>>=0x10;
ax&=0x7fff;
}
dx=ax%0x1a+0x41;
printf("%c",dx);//计算每位码值
ax=dx-psw[i];
key[i]=dx;
sum+=ax;
}
printf("\n");
getchar();
}
1084801702.zip
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
谁下载
看原图
赞赏
雪币:
留言: