Double_Z 发表于 2015-5-28 20:17

160个CrackMe练手之024

本帖最后由 Double_Z 于 2015-5-28 21:28 编辑

   最近一直在练习160CrackMe,也积累了一些东西,一直没时间发,今天可能刚好有些时间就找一些可以发的东西发一下。

   这里有 44018723 发的相同的一篇帖子:可以参考一下 重复的内容我就不发了:http://www.52pojie.cn/thread-268511-1-1.html

   首先找到关键代码区,查找字符串,或者右键->查找->所有程序间的调用 找到编辑框相关断点下断 运行即可。
00401255   > \3B05 58314000 cmp eax, dword ptr
0040125B   .74 0C         je short 00401269
0040125D   .3B05 54314000 cmp eax, dword ptr
00401263   .0F85 AE000000 jnz 00401317
00401269   >C705 D9124000>mov dword ptr , 0x584554
00401273   .6A 00         push 0x0                                 ; /IsSigned = FALSE
00401275   .8D45 FC       lea eax, dword ptr              ; |
00401278   .50            push eax                                 ; |pSuccess
00401279   .6A 64         push 0x64                              ; |ControlID = 64 (100.)
0040127B   .FF35 50314000 push dword ptr                 ; |hWnd = NULL
00401281   .E8 BC010000   call <jmp.&USER32.GetDlgItemInt>         ; \GetDlgItemInt
00401286   .837D FC 00    cmp dword ptr , 0x0
0040128A      74 5F         je short 004012EB
0040128C   .50            push eax                                 ;在此处下F2断点
0040128D   .6A 14         push 0x14                              ; /Count = 14 (20.)
0040128F   .68 6C314000   push 0040316C                            ; |用户名
00401294   .FF35 54314000 push dword ptr                 ; |hWnd = NULL
0040129A   .E8 AF010000   call <jmp.&USER32.GetWindowTextA>      ; \GetWindowTextA
0040129F   .85C0          test eax, eax                            ;eax = length用户名长度
004012A1   .74 48         je short 004012EB
004012A3   .A1 0B304000   mov eax, dword ptr             ;1480938563 0x58455443
004012A8   .BB 6C314000   mov ebx, 0040316C                        ;用户名
004012AD   >0303          add eax, dword ptr                ;+*((int*)Name)
004012AF   .43            inc ebx
004012B0   .81FB 7C314000 cmp ebx, 0040317C                        ;循环 16次
004012B6   .^ 75 F5         jnz short 004012AD
004012B8   .5B            pop ebx
004012B9   .03C3          add eax, ebx                           ;eax = 用户名累加 ebx = serial 注册码
004012BB   .3105 D9124000 xor dword ptr , eax            ;00584554 ^ eax 对下面的代码进行改写
004012C1   .C1E8 10       shr eax, 0x10                            ;右移 16位
004012C4   .66:2905 D9124>sub word ptr , ax            ;0x4012d9 - ax
004012CB   .BE EC114000   mov esi, 004011EC
004012D0   .B9 3E000000   mov ecx, 0x3E
004012D5   .33DB          xor ebx, ebx
004012D7   .EB 04         jmp short 004012DD
004012D9      54            push esp                                 ;改写位置
004012DA      45            inc ebp
004012DB      58            pop eax                                  ;改写位置
004012DC      00AD 33D84975 add byte ptr , ch      ;改写位置
004012E2   ?FA            cli
004012E3   .81FB FBCFFCAF cmp ebx, 0xAFFCCFFB
004012E9   .^ 74 EE         je short 004012D9
004012EB   >68 59304000   push 00403059                            ; /Your serial is not valid.
004012F0   .FF35 5C314000 push dword ptr                 ; |hWnd = NULL
004012F6   .E8 7D010000   call <jmp.&USER32.SetWindowTextA>      ; \SetWindowTextA
004012FB   .33C0          xor eax, eax
004012FD   .C9            leave                                    ;(Initial CPU selection)
004012FE   .C2 1000       retn 0x10
00401301   .68 73 30 40 0>ascii "hs0@",0                           ;YES! You found your serial!!
00401306   .FF35 5C314000 push dword ptr                 ; |hWnd = NULL
0040130C   .E8 67010000   call <jmp.&USER32.SetWindowTextA>      ; \SetWindowTextA
00401311   .33C0          xor eax, eax
00401313   .C9            leave
00401314   .C2 1000       retn 0x10



这段代码就是将要分析的代码 ,很短,算法也很简单。
首先是 这段代码:

0040128C   .50            push eax                                 ;在此处下F2断点
0040128D   .6A 14         push 0x14                              ; /Count = 14 (20.)
0040128F   .68 6C314000   push 0040316C                            ; |用户名
00401294   .FF35 54314000 push dword ptr                 ; |hWnd = NULL
0040129A   .E8 AF010000   call <jmp.&USER32.GetWindowTextA>      ; \GetWindowTextA
0040129F   .85C0          test eax, eax                            ;eax = length用户名长度
004012A1   .74 48         je short 004012EB
004012A3   .A1 0B304000   mov eax, dword ptr             ;1480938563 0x58455443
004012A8   .BB 6C314000   mov ebx, 0040316C                        ;用户名
004012AD   >0303          add eax, dword ptr                ;+*((int*)Name)
004012AF   .43            inc ebx
004012B0   .81FB 7C314000 cmp ebx, 0040317C                        ;循环 16次
004012B6   .^ 75 F5         jnz short 004012AD
004012B8   .5B            pop ebx
004012B9   .03C3          add eax, ebx                           ;eax = 用户名累加 ebx = serial 注册码

分析一下,大体意思就是这样滴:
#include "stdio.h"
#include "string.h"
#include "stdlib.h"

main()
{
char strUsername="doubleZ"; // 用户名
int serial= 12345678;      // 注册码
int *pSerial=&serial;
char *pName = strUsername;
int EAX = 0x58455443; //dword ptr
int i=0;
int nLen=strlen(strUsername);

for( i=nLen;i<20;i++) //字符串后续地址清零
{
*(pName+i)=0;
}
for( i=0;i<16;i++)
{

EAX += *((int*)pName); // add eax, dword ptr
pName++;
}

EAX +=serial; //add eax, ebx
printf("EAX:%X\n",EAX);

system("pause");

}


不好意思,我用 DEV C++ 写的,代码比较粗糙。可以用OD调试下程序,看看结果是否正确:运行程序,然后输入用户名,注册码(这个要和C代码中的一致)
然后,找到刚才的代码区,下断点,点击注册框即可断下。
0040128A   /74 5F         je short 004012EB
0040128C   . |50            push eax                                 ;在此处下F2断点

F8 单步运行,也可直接F4 到此处:
004012B8   .5B            pop ebx
004012B9   .03C3          add eax, ebx                           ;eax = 用户名累加 ebx = serial 注册码


查看EAX的值是否与自己写的代码得出的结果是否相同。

然后分析一下下面的代码

004012BB   .3105 D9124000 xor dword ptr , eax            ;00584554 ^ eax 对下面的代码进行改写
004012C1   .C1E8 10       shr eax, 0x10                            ;右移 16位
004012C4   .66:2905 D9124>sub word ptr , ax            ;0x4012d9 - ax
004012CB   .BE EC114000   mov esi, 004011EC
004012D0   .B9 3E000000   mov ecx, 0x3E
004012D5   .33DB          xor ebx, ebx
004012D7   .EB 04         jmp short 004012DD


第一句 004012BB . xor dword ptr , eax ; 其中eax 为前面计算的那个数,0x4012d9 dword 是什么呢,多调试几次你就突然发现下面的代码会莫名的变红。对
其实就是下面的代码区(jmp 后的四个字节)。那为什么到对这几个字节更改呢?看下面
第二 三句 004012C1   .C1E8 10       shr eax, 0x10                            ;右移 16位
004012C4   .66:2905 D9124>sub word ptr , ax            ;0x4012d9 - ax


同样是对0x4012d9 位置的地址进行更改,且是根据用户名和注册码计算出的码进行更改,那猜一下,如果是你,你会改成什么?现在还不知道,待会再猜。

在后面的几句是为JMP后面的循环清零;

看看JMP后面是什么?
004012DD      AD            lods dword ptr                      ;JMP跳到此处
004012DE      33D8          xor ebx, eax
004012E0   .49            dec ecx
004012E1   .^ 75 FA         jnz short 004012DD
004012E3   .81FB FBCFFCAF cmp ebx, 0xAFFCCFFB
004012E9   .^ 74 EE         je short 004012D9


这段程序的意思就是从地址004011EC 到 004011EC+0x3E(注意:这个区间包括0x4012d9这个位置,这点很重要) 取值,然后依次异或,最后的计算结果和0xAFFCCFFB比较,相等则跳转。如果不跳转,下面就是显示注册失败的提示,那么这里就是所谓的关键跳了。那么如果相等的话,那会跳转到哪里呢?按照正常的思路,应该是是提示注册成功的那个位置。
也就是这里:
00401301   .68 73 30 40 0>ascii "hs0@",0                           ;YES! You found your serial!!
00401306   .FF35 5C314000 push dword ptr                 ; |hWnd = NULL
0040130C   .E8 67010000   call <jmp.&USER32.SetWindowTextA>      ; \SetWindowTextA
00401311   .33C0          xor eax, eax
00401313   .C9            leave
00401314   .C2 1000       retn 0x10

但是,他没有跳到这里(爆破的话可以改跳到这里),而是跳到 0x4012d9这个位置,这个位置的代码是根据咱输入的用户名和注册码计算出来的,所以这里的代码也和咱的
注册码和用户名一样是错的。如何强制改下跳转,你会发现程序会死掉滴。

那么,假若,我们输入的是正确的用户名和注册码,那么0x4012d9 位置的代码是什么? 废话,当然是跳到提示注册成功的哪里喽!
我们将 0x4012d9 出的代码改一下,改成这样。若是这样的话,那么若通过注册码检验,则跳到这里,然后在跳到提示成功!
004012D9   /EB 26         jmp short 00401301                     ;改写位置
004012DB   |90            nop                                    ;改写位置
004012DC   |90            nop                                    ;改写位置


这里有两个关键字节,即EB 26 (jmp short 00401301)。那如何验证我们的猜想呢?往下看。

我们先总结一下作者的思路:首先对用户名和注册码进行一系列的计算,得出Number1,
然后通Number1对0x4012d9 进行异或,加减一系列的操作,总之就是要改变dword
这个数。改变这个数的目的,是为了改变0x4012d9处的运行代码(我们猜测含有EB 26 这两个字节)。
最后,对地址004011EC 到 004011EC+0x3E的Dword读取的数进行异或运算,判断是否符合要求。
我们发现地址004011EC 到 004011EC+0x3E 只有两个数是会改变的,即0x4012d8 和 0x4012dc 中的 前者的后三个字节,后者的第一个字节,
这正是被改写的0x4012d9 的 四个字节。 所以最后的验证是验证0x4012d9 是否被改写正确。

如果我们得出0x4012d9的值,那么我们就所有的问题就解决了。那如何得出0x4012d9 处的代码后者说是值呢?

我们在来看一下最后的验证的代码:
004012DD      AD            lods dword ptr                      ;JMP跳到此处
004012DE      33D8          xor ebx, eax
004012E0   .49            dec ecx
004012E1   .^ 75 FA         jnz short 004012DD
004012E3   .81FB FBCFFCAF cmp ebx, 0xAFFCCFFB
004012E9   .^ 74 EE         je short 004012D9


lods dword ptr 可以这样理解:mov eax,dword ptr; add esi,4;
即不断取值,然后异或,最后和0xAFFCCFFB 比较相同即可;
即 可以转换为
A xor B xor C ocr D ...... xor E ?= 0xAFFCCFFB ,其中有有两个 F 和 G (F G的一部分)是未知的。那如何求解F,G;
这里有关异或的资料可以参考:http://www.cnblogs.com/suoloveyou/archive/2012/04/25/2470292.html
看完资料我们会发现 A xor B= C ; 则B = A xor C ;

好了,不废话了,说一下我的思路吧:
我们先计算 0x004012d8 处的值 因为这个值有三个字节是未知的,
把 0x004012d8 之前的 A xor D xor C xor D .... 计算出的值看成一个数 M 后面的看成 N

则 M xor dword xor N = 0xAFFCCFFB ;
   dword = 0xAFFCCFFB xor M xor N ;

那我们如何计算 M 和 N 呢?

嗯,又是一个问题,怎么办呢?我们用现成的工具 ——OD;
再次运行,断下,单步到此处(或F4);
004012DD      AD            lods dword ptr                      ;JMP跳到此处
004012DE      33D8          xor ebx, eax
004012E0   .49            dec ecx
004012E1   .^ 75 FA         jnz short 004012DD

然后调试->设置条件->选择条件为真 填写 esi == 004012d8(注意 ==) 然后跟踪步入,你会发现esi为004012d8,
然后F8一步,此时把ebx的值记下 M =0xA213FC72.
然后F8 单步走到达 xor ebx,ebx 处 此时 eax 为 0x004012d8的值,此时把eax和ebx中的值改为零,当然你也可以只改eax中的值。这里将0x4012dc 中最后一个字节改为00 即D833AD00,
然后在F8,注意jne是否向上跳,不跳的时候把 ebx 记下 N = 0x59C9D849;

则 dword 0x4012d8 =0xAFFCCFFB xor M xor N ;
计算看下面:
#include "stdio.h"
#include "stdlib.h"
main()
{
int b = 0xAFFCCFFB ^ 0x59C9D849 ^ 0xA213FC72;//b=0x5426EBC0
printf("%X",b);
system("pause");
}
0x5426EBC0,嗯,果然,有 eb 26 这两个字节,但是因为 0x4012d8 第一个字节是知道的为04
故0x4012d8 = 0x5426EB04;
然后用同样的方法计算出0x4012dc的值,跟踪 到 esi == 0x4012d8,然后F8 等到 0x004012d8 的数值载入到eax 时将eax 改为0x5426EB04这个值
然后 f8,我们用另一个方法,再次f8 到载入 0x4012dc 的值到eax 后,将eax 改为 0,然后f8直到循环结束,记下ebx 的值 S =0x77CF623F
0x4012dc=0xAFFCCFFB xor S=0xD833ADC4; 明显和原来的数只差一个字节;

0x4012d9 = C45426EB;;//得到这个数的方法很多,同学们可以总结下。

然后我们向上分析:
004012BB   .3105 D9124000 xor dword ptr , eax            ;00584554 ^ eax 对下面的代码进行改写
004012C1   .C1E8 10       shr eax, 0x10                            ;右移 16位
004012C4   .66:2905 D9124>sub word ptr , ax            ;0x4012d9 - ax


很简单:   0x00584554 xor C - C >> 0x10=0xC41926eb ; 问题又来了,我们如何计算C?
我们转换一下:
                0x00584554 xor C = C41926eb + C>>0x10;
方法很笨,但很有效:

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

main()
{
unsigned int i=0x0;
unsigned int j=0x0;
unsigned int k=0x0;
for( i=0x1;i<=0xFFFFFFFE;i++)
{

j = 0x00584554^i;
k = 0xC45426EB + (i>>0x10);
if(j==k) printf("%X\t%X\t%X\n",i,j,k);

}
//0xC40CAFA3 Number1
//0xC45426EB
system("pause");
}

最终得到 C = 0xC40CAFA3;就是前面我们所说的用用户名和注册码得出的Number1;

最后用户名到注册码的算法前面分析过了,很简单,我把代码放下:

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

main()
{
char strUsername="doubleZ";
intserial= 0;
int *pSerial=&serial;
char *pName = strUsername;
int i=0;
int nLen=strlen(strUsername);
for( i=nLen;i<20;i++)
{
       *(pName+i)=0;
}
serial =0x58455443;
for( i=0;i<16;i++)
{
       serial += *((int*)pName);
       pName++;
}

serial = 0xC40CAFA3-serial;
printf("Name:%s\n",strUsername);
printf("Serial:%u\n",serial);

//Name:doubleZ
//Serial:3703760779
system("pause");
   
}


最后得出一组用户名和注册码Name:doubleZ ,Serial:3703760779。但是这个注册码只能在调试时通过,正常情况下不能显示成功,这个好像程序设计时没处理好,
嗯,就这样吧,反正我们的最终的目的达到了——了解CrackMe作者的思路。

这是我第一次发帖,水平有限,莫怪。好吧,我把文件放下赚点外快。



























Pnmker 发表于 2015-6-19 11:34

Double_Z 发表于 2015-6-19 09:59
嗯,我知道了,这点我没想到。明天有空我把帖子在改一下,省的误导大家。我现在在上班,没有工具。用硬件 ...

不用调试,直接把11EC开始地址开始的 0x3E*4个字节的数据dump出来,分成四部分进行异或就可以了:
xxxxxxxx ^ xxxxxx04 ^ D833ADxx ^ 81FA7549 = AFFCCFFB
最前面的xxxxxxxx可以根据dump出来的数据异或出来, 中间的两个用你的方法就可以计算出来

Double_Z 发表于 2015-6-19 09:59

Pnmker 发表于 2015-6-19 00:40
程序没有问题,非调试状态下以下两组用户名验证通过
pnmker 3155544019
doubleZ 1891791755


嗯,我知道了,这点我没想到。明天有空我把帖子在改一下,省的误导大家。我现在在上班,没有工具。用硬件断点调试可以吗?

微笑最美 发表于 2015-5-28 21:12

好资源,已收藏了

Hmily 发表于 2015-6-3 12:01

Double_Z分析的很详细了,加精鼓励,期待更多分享,@44018723 带大家一起走入crackme系列,应该搞成一个教程合集,收录到板块推荐贴里。

boyving 发表于 2015-6-3 13:56

好东西,谢谢了哦。

24K灬纯帅 发表于 2015-6-3 14:11

这个很详细   我有空也去看看吧

qq734928657 发表于 2015-6-3 15:48

支持学习         

stdcall 发表于 2015-6-3 16:20

收下 有时间多学学

吾爱T阿杰 发表于 2015-6-3 20:57

我很纳闷,原创的精品评分这么少,什么音乐电影啥的评分反而那么多,,,郁闷

Ctrui 发表于 2015-6-4 03:08

收藏了,感谢分享!{:301_1003:}

wuaixuexi 发表于 2015-6-4 08:00

好文章 学习了 谢谢楼主 思路很好 继续关注你
页: [1] 2 3 4 5 6
查看完整版本: 160个CrackMe练手之024