首页
社区
课程
招聘
[分享]跟了下CRC32的CrackMe
发表于: 2013-8-12 18:08 8280

[分享]跟了下CRC32的CrackMe

2013-8-12 18:08
8280
粘贴过来才知道语法高亮没效果了,可以看附件(mht格式的笔记,CrackMe,udd)

CRC32的CrackMe
不是原创。。自己跟了一下,写出来的笔记觉得还挺清晰的,代码高亮也好看就分享下!
多谢WindRand编写了系列密码学CrackMe

第一篇密码学CrackMe的破解笔记,虽然我依稀记得CRC32只是一个校验数据完整性的算法,还是干一下吧。

要注意的几点:
1 在贴出来的反汇编代码里你可能会见到一些变量名或者函数名,这个是我理解了之后放上去的,方法是在函数或变量的开头地方shift+分号来输入标签

2 这系列的CrackMe找注册算法定位点很简单,所以就不关注了,直接看注册算法(位于地址401282)

分析过程如下:

00401282   .  68 00010000          push 0x100                                   ; /Count = 100 (256.)

00401287   .  51                   push ecx                                     ; |Buffer

00401288   .  68 E8030000          push 0x3E8                                   ; |ControlID = 3E8 (1000.)

0040128D   .  56                   push esi                                     ; |hWnd

0040128E   .  FFD3                 call ebx                                     ; \GetDlgItemTextA

00401290   .  8DBC24 0C010000      lea edi,dword ptr ss:[esp+0x10C]

00401297   .  83C9 FF              or ecx,0xFFFFFFFF

0040129A   .  33C0                 xor eax,eax

0040129C   .  F2:AE                repne scas byte ptr es:[edi]

0040129E   .  F7D1                 not ecx

004012A0   .  49                   dec ecx                                      ;  获取szUserName长度

004012A1   .  83F9 01              cmp ecx,0x1

004012A4   .  73 1F                jnb short <CRC32Cra.BadBoy>                  ;  长度必须大于等于1

004012A6   .  6A 40                push 0x40                                    ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL

004012A8   .  68 8C604000          push CRC32Cra.0040608C                       ; |Title = "注册提示"

004012AD   .  68 74604000          push CRC32Cra.00406074                       ; |Text = "用户名不能为空请输入!"

004012B2   .  56                   push esi                                     ; |hOwner

004012B3   .  FF15 A8504000        call dword ptr ds:[<&USER32.MessageBoxA>]    ; \MessageBoxA

004012B9   .  5F                   pop edi

004012BA   .  5E                   pop esi

004012BB   .  33C0                 xor eax,eax

004012BD   .  5B                   pop ebx

004012BE   .  81C4 00030000        add esp,0x300

004012C4   .  C3                   retn

004012C5 > >  8D5424 0C            lea edx,dword ptr ss:[esp+0xC]               ;  label:BadBoy

004012C9   .  68 00010000          push 0x100

004012CE   .  52                   push edx

004012CF   .  68 07040000          push 0x407

004012D4   .  56                   push esi

004012D5   .  FFD3                 call ebx

004012D7   .  8D7C24 0C            lea edi,dword ptr ss:[esp+0xC]

004012DB   .  83C9 FF              or ecx,0xFFFFFFFF

004012DE   .  33C0                 xor eax,eax

004012E0   .  F2:AE                repne scas byte ptr es:[edi]

004012E2   .  F7D1                 not ecx

004012E4   .  49                   dec ecx                                      ;  获取szPassword长度

004012E5   .  83F9 01              cmp ecx,0x1                                  ;  长度必须大于等于1

004012E8   .  73 1F                jnb short <CRC32Cra.BadBoy2>

004012EA   .  6A 40                push 0x40                                    ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL

004012EC   .  68 8C604000          push CRC32Cra.0040608C                       ; |Title = "注册提示"

004012F1   .  68 5C604000          push CRC32Cra.0040605C                       ; |Text = "注册码不能为空请输入!"

004012F6   .  56                   push esi                                     ; |hOwner

004012F7   .  FF15 A8504000        call dword ptr ds:[<&USER32.MessageBoxA>]    ; \MessageBoxA

004012FD   .  5F                   pop edi

004012FE   .  5E                   pop esi

004012FF   .  33C0                 xor eax,eax

00401301   .  5B                   pop ebx

00401302   .  81C4 00030000        add esp,0x300

00401308   .  C3                   retn

00401309 > >  8D8424 0C020000      lea eax,dword ptr ss:[esp+0x20C]             ;  label:BadBoy2

00401310   .  8D8C24 0C010000      lea ecx,dword ptr ss:[esp+0x10C]

00401317   .  50                   push eax                                     ;  empty buffer

00401318   .  51                   push ecx                                     ;  szUserName

00401319   .  E8 F2FDFFFF          call <CRC32Cra.CRC32>

0040131E   .  8D9424 14020000      lea edx,dword ptr ss:[esp+0x214]

00401325   .  8D4424 14            lea eax,dword ptr ss:[esp+0x14]

00401329   .  52                   push edx                                     ;  may be CRC32 value

0040132A   .  50                   push eax                                     ;  szPassword

0040132B   .  E8 D0FCFFFF          call <CRC32Cra.Compare>

00401330   .  83C4 10              add esp,0x10

00401333   .  83F8 01              cmp eax,0x1

00401336   .  6A 40                push 0x40                                    ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL

00401338   .  68 8C604000          push CRC32Cra.0040608C                       ; |Title = "注册提示"

0040133D   .  75 18                jnz short CRC32Cra.00401357                  ; |

0040133F   .  68 48604000          push CRC32Cra.00406048                       ; |Text = "恭喜你,注册码正确!"

00401344   .  56                   push esi                                     ; |hOwner

00401345   .  FF15 A8504000        call dword ptr ds:[<&USER32.MessageBoxA>]    ; \MessageBoxA

0040134B   .  5F                   pop edi

0040134C   .  5E                   pop esi

0040134D   .  33C0                 xor eax,eax

0040134F   .  5B                   pop ebx

00401350   .  81C4 00030000        add esp,0x300

00401356   .  C3                   retn

00401357   >  68 30604000          push CRC32Cra.00406030                       ; |Text = "注册码错误,继续加油!"

0040135C   .  56                   push esi                                     ; |hOwner

0040135D   .  FF15 A8504000        call dword ptr ds:[<&USER32.MessageBoxA>]    ; \MessageBoxA

00401363   .  5F                   pop edi

00401364   .  5E                   pop esi

00401365   .  33C0                 xor eax,eax

00401367   .  5B                   pop ebx

00401368   .  81C4 00030000        add esp,0x300

0040136E   .  C3                   retn

进入名为CRC32的函数看看:

00401110 >/$  83EC 0C              sub esp,0xC

00401113  |.  56                   push esi

00401114  |.  57                   push edi

00401115  |.  E8 B6FFFFFF          call <CRC32Cra.InitCRCTable>

0040111A  |.  8B7424 18            mov esi,dword ptr ss:[esp+0x18]

0040111E  |.  83C9 FF              or ecx,0xFFFFFFFF

00401121  |.  8BFE                 mov edi,esi

00401123  |.  33C0                 xor eax,eax

00401125  |.  83CA FF              or edx,0xFFFFFFFF

00401128  |.  F2:AE                repne scas byte ptr es:[edi]

0040112A  |.  F7D1                 not ecx

0040112C  |.  49                   dec ecx

0040112D  |.  85C9                 test ecx,ecx

第四句在初始化一个表,进去看看:

004010D0 >/$  56                   push esi

004010D1  |.  33D2                 xor edx,edx

004010D3  |.  B9 20854000          mov ecx,CRC32Cra.00408520

004010D8  |>  8BC2                 /mov eax,edx

004010DA  |.  BE 08000000          |mov esi,0x8

004010DF  |>  A8 01                |/test al,0x1

004010E1  |.  74 09                ||je short CRC32Cra.004010EC

004010E3  |.  D1E8                 ||shr eax,1

004010E5  |.  35 2083B8ED          ||xor eax,0xEDB88320

004010EA  |.  EB 02                ||jmp short CRC32Cra.004010EE

004010EC  |>  D1E8                 ||shr eax,1

004010EE  |>  4E                   ||dec esi

004010EF  |.^ 75 EE                |\jnz short CRC32Cra.004010DF

004010F1  |.  8901                 |mov dword ptr ds:[ecx],eax

004010F3  |.  83C1 04              |add ecx,0x4

004010F6  |.  42                   |inc edx

004010F7  |.  81F9 20894000        |cmp ecx,CRC32Cra.00408920

004010FD  |.^ 7C D9                \jl short CRC32Cra.004010D8

004010FF  |.  5E                   pop esi

00401100  \.  C3                   retn

代码很简单,用C语言写出来如下(初步描述,不保证无逻辑和编译错误):

void InitCRCTable()

{

     DWORD *CRCTable=malloc(256*sizeof(int));

     int i=0,j=0,k=0;

     While(i<=256-1)

     {

          k=i;

          j=8;

LabelJ_UnequalZero:

          if(k==1)

          {

                k=k>>1;

j=j-1;

          }

          Else

          {

                k=k>>1;

k=k^0xEDB88320;

          }

  if(j!=0)

  {

        goto LabelJ_UnequalZero;

  }

          CRCTable[i++]=k;

     }

}

继续Call InitCRCTable之后的:

0040111A  |.  8B7424 18     mov esi,dword ptr ss:[esp+0x18]

0040111E  |.  83C9 FF       or ecx,0xFFFFFFFF

00401121  |.  8BFE          mov edi,esi

00401123  |.  33C0          xor eax,eax

00401125  |.  83CA FF       or edx,0xFFFFFFFF

00401128  |.  F2:AE         repne scas byte ptr es:[edi]

0040112A  |.  F7D1          not ecx

0040112C  |.  49            dec ecx                                  ;  获取szUserName长度

0040112D  |.  85C9          test ecx,ecx

0040112F  |.  7E 1F         jle short CRC32Cra.00401150              ;  长度必须大于等于0

00401131  |.  53            push ebx

00401132  |>  8BC2          /mov eax,edx

00401134  |.  33DB          |xor ebx,ebx

00401136  |.  8A1E          |mov bl,byte ptr ds:[esi]

00401138  |.  25 FF000000   |and eax,0xFF

0040113D  |.  33C3          |xor eax,ebx

0040113F  |.  C1EA 08       |shr edx,0x8

00401142  |.  8B0485 208540>|mov eax,dword ptr ds:[eax*4+<CRCTable>]

00401149  |.  33D0          |xor edx,eax

0040114B  |.  46            |inc esi

0040114C  |.  49            |dec ecx

0040114D  |.^ 75 E3         \jnz short CRC32Cra.00401132

0040112F处开始的循环用C语言写出来如下(初步描述,不保证无逻辑和编译错误):

while(length==0)

{

int i,j,k,z;

i=0xFFFFFFFF;

j=i;

k=0;

z=0;

k=szUserName[z];

j=j^0xFF;

j=j^k;

i=i>>8;

j=CRCTable[j];

i=i^j;

length=length-1;

       //这个循环是要计算i的值,不知道这是什么,不妨命名为magic

}

继续后面:

00401152  |.  8D4424 08     lea eax,dword ptr ss:[esp+0x8]

00401156  |.  894C24 09     mov dword ptr ss:[esp+0x9],ecx

0040115A  |.  6A 10         push 0x10                                ;  这是函数参数

0040115C  |.  F7D2          not edx                                  ;  not magic(从后面得知这个就是CRC32校验值了)

0040115E  |.  894C24 11     mov dword ptr ss:[esp+0x11],ecx

00401162  |.  50            push eax                                 ;  这是函数参数,一个buffer

00401163  |.  52            push edx                                 ;  这是magic取反之后的,是个函数参数

00401164  |.  C64424 14 00  mov byte ptr ss:[esp+0x14],0x0

00401169  |.  884C24 1D     mov byte ptr ss:[esp+0x1D],cl            ;  上面对一块地址的某些地方赋值为0(不知道何用)取magic相反数

0040116D  |.  E8 24380000   call CRC32Cra.00404996

最后有个call,进去看:

00404996  /$  55            push ebp

00404997  |.  8BEC          mov ebp,esp

00404999  |.  837D 10 0A    cmp [arg.3],0xA                          ;  刚刚压入了0x10

0040499D  |.  75 0C         jnz short CRC32Cra.004049AB

0040499F  |.  837D 08 00    cmp [arg.1],0x0

004049A3  |.  7D 06         jge short CRC32Cra.004049AB

004049A5  |.  6A 01         push 0x1

004049A7  |.  6A 0A         push 0xA

004049A9  |.  EB 05         jmp short CRC32Cra.004049B0

004049AB  |>  6A 00         push 0x0

004049AD  |.  FF75 10       push [arg.3]

004049B0  |>  FF75 0C       push [arg.2]                             ; |Arg2

004049B3  |.  FF75 08       push [arg.1]                             ; |Arg1

004049B6  |.  E8 08000000   call CRC32Cra.004049C3                   ; \CRC32Cra.004049C3

004049BB  |.  8B45 0C       mov eax,[arg.2]                          ;  发现这里的arg2变成了arg1的字符串形式

004049BE  |.  83C4 10       add esp,0x10

004049C1  |.  5D            pop ebp

004049C2  \.  C3            retn

由于call CRC32Cra.004049C3之后Arg2变成了arg1的字符串形式,所以不用费力跟这个call了,应该是个delphi的库函数,如果OD有个识别delphi函数的插件就好了。。

继续:

00401172  |.  8D7C24 14     lea edi,dword ptr ss:[esp+0x14]          ;  这个是crc32的字符串形式

00401176  |.  83C9 FF       or ecx,0xFFFFFFFF

00401179  |.  33C0          xor eax,eax

0040117B  |.  83C4 0C       add esp,0xC

0040117E  |.  33F6          xor esi,esi

00401180  |.  F2:AE         repne scas byte ptr es:[edi]

00401182  |.  F7D1          not ecx

00401184  |.  49            dec ecx                                  ;  获取CRC32值长度

00401185  |.  74 25         je short CRC32Cra.004011AC

发现delphi获取字符串长度的代码都很有个性的。。

继续,有个循环:

00401187  |> /0FBE4C34 08   /movsx ecx,byte ptr ss:[esp+esi+0x8]

0040118C  |. |51            |push ecx

0040118D  |. |E8 4E020000   |call CRC32Cra.004013E0                  ;  循环多几次可以发现这个函数在把ecx转换为大写,放到eax

00401192  |. |884434 0C     |mov byte ptr ss:[esp+esi+0xC],al        ;  物归原主

00401196  |. |83C4 04       |add esp,0x4

00401199  |. |8D7C24 08     |lea edi,dword ptr ss:[esp+0x8]

0040119D  |. |83C9 FF       |or ecx,0xFFFFFFFF

004011A0  |. |33C0          |xor eax,eax

004011A2  |. |46            |inc esi                                 ;  esi++

004011A3  |. |F2:AE         |repne scas byte ptr es:[edi]

004011A5  |. |F7D1          |not ecx

004011A7  |. |49            |dec ecx                                 ;  计算大小

004011A8  |. |3BF1          |cmp esi,ecx

004011AA  |.^\72 DB         \jb short CRC32Cra.00401187

很明显可以看出是在把CRC字符串中的字母转换为大写了

继续:

004011AC  |> \8B4424 1C     mov eax,dword ptr ss:[esp+0x1C]

004011B0  |.  8D5424 08     lea edx,dword ptr ss:[esp+0x8]

004011B4  |.  52            push edx                                 ; /String2

004011B5  |.  50            push eax                                 ; |String1

004011B6  |.  FF15 00504000 call dword ptr ds:[<&KERNEL32.lstrcpyA>] ; \lstrcpyA

004011BC  |.  5F            pop edi                                  ;  0012F723

004011BD  |.  5E            pop esi

004011BE  |.  83C4 0C       add esp,0xC

004011C1  \.  C3            retn

Copy一下字符串到12F91C

继续:

0040131E   .  8D9424 140200>lea edx,dword ptr ss:[esp+0x214]

00401325   .  8D4424 14     lea eax,dword ptr ss:[esp+0x14]

00401329   .  52            push edx                                 ;  may be CRC32 value

0040132A   .  50            push eax                                 ;  szPassword

0040132B   .  E8 D0FCFFFF   call <CRC32Cra.Compare>

进入Compare函数:

00401000 >/$  81EC 00020000 sub esp,0x200

00401006  |.  56            push esi

00401007  |.  57            push edi

00401008  |.  B9 3F000000   mov ecx,0x3F

0040100D  |.  33C0          xor eax,eax

0040100F  |.  8D7C24 09     lea edi,dword ptr ss:[esp+0x9]

00401013  |.  C64424 08 00  mov byte ptr ss:[esp+0x8],0x0

00401018  |.  F3:AB         rep stos dword ptr es:[edi]                    ;  初始化一段地方为0

0040101A  |.  66:AB         stos word ptr es:[edi]

0040101C  |.  AA            stos byte ptr es:[edi]

0040101D  |.  B9 3F000000   mov ecx,0x3F

00401022  |.  33C0          xor eax,eax

00401024  |.  8DBC24 090100>lea edi,dword ptr ss:[esp+0x109]

0040102B  |.  C68424 080100>mov byte ptr ss:[esp+0x108],0x0

00401033  |.  F3:AB         rep stos dword ptr es:[edi]

00401035  |.  66:AB         stos word ptr es:[edi]

00401037  |.  8B35 00504000 mov esi,dword ptr ds:[<&KERNEL32.lstrcpyA>]    ;  kernel32.lstrcpyA

0040103D  |.  8D4C24 08     lea ecx,dword ptr ss:[esp+0x8]

00401041  |.  AA            stos byte ptr es:[edi]

00401042  |.  8B8424 0C0200>mov eax,dword ptr ss:[esp+0x20C]

00401049  |.  50            push eax                                       ; /szPassword

0040104A  |.  51            push ecx                                       ; |empty buffer

0040104B  |.  FFD6          call esi                                       ; \lstrcpyA

0040104D  |.  8B9424 100200>mov edx,dword ptr ss:[esp+0x210]

00401054  |.  8D8424 080100>lea eax,dword ptr ss:[esp+0x108]

0040105B  |.  52            push edx                                       ; /szCRC

0040105C  |.  50            push eax                                       ; |empty buffer

0040105D  |.  FFD6          call esi                                       ; \lstrcpyA

0040105F  |.  8DBC24 080100>lea edi,dword ptr ss:[esp+0x108]

00401066  |.  83C9 FF       or ecx,0xFFFFFFFF

00401069  |.  33C0          xor eax,eax

0040106B  |.  F2:AE         repne scas byte ptr es:[edi]

0040106D  |.  F7D1          not ecx

0040106F  |.  49            dec ecx                                        ;  获取szCRC长度

00401070  |.  8D7C24 08     lea edi,dword ptr ss:[esp+0x8]

00401074  |.  8BD1          mov edx,ecx

00401076  |.  83C9 FF       or ecx,0xFFFFFFFF

00401079  |.  F2:AE         repne scas byte ptr es:[edi]

0040107B  |.  F7D1          not ecx

0040107D  |.  49            dec ecx                                        ;  获取szPassword长度

0040107E  |.  3BCA          cmp ecx,edx

00401080  |.  75 40         jnz short CRC32Cra.004010C2                    ;  首先长度得相等

00401082  |.  8D7C24 08     lea edi,dword ptr ss:[esp+0x8]

00401086  |.  83C9 FF       or ecx,0xFFFFFFFF

00401089  |.  33D2          xor edx,edx

0040108B  |.  F2:AE         repne scas byte ptr es:[edi]

0040108D  |.  F7D1          not ecx

0040108F  |.  49            dec ecx                                        ;  又计算szCRC长度,delphi就不能找个地方存起来?

00401090  |.  74 22         je short CRC32Cra.004010B4

00401092  |>  8A4414 08     /mov al,byte ptr ss:[esp+edx+0x8]

00401096  |.  8A8C14 080100>|mov cl,byte ptr ss:[esp+edx+0x108]

0040109D  |.  3AC1          |cmp al,cl

0040109F  |.  75 21         |jnz short CRC32Cra.004010C2

004010A1  |.  8D7C24 08     |lea edi,dword ptr ss:[esp+0x8]

004010A5  |.  83C9 FF       |or ecx,0xFFFFFFFF

004010A8  |.  33C0          |xor eax,eax

004010AA  |.  42            |inc edx

004010AB  |.  F2:AE         |repne scas byte ptr es:[edi]

004010AD  |.  F7D1          |not ecx

004010AF  |.  49            |dec ecx

004010B0  |.  3BD1          |cmp edx,ecx

004010B2  |.^ 72 DE         \jb short CRC32Cra.00401092

004010B4  |>  5F            pop edi

004010B5  |.  B8 01000000   mov eax,0x1

004010BA  |.  5E            pop esi

004010BB  |.  81C4 00020000 add esp,0x200

004010C1  |.  C3            retn

最后那个循环很容易看出是比较两个字符串了;一个字符一个字符地比较

写注册机:

这个CM就是单纯地计算字符串的CRC,所以注册机也就是一个CRC算法了,拼凑刚才写好的代码,运行了一下,错误一大堆,编译的改好了也有逻辑错误导致运算结果不正确,调试了一阵,结果出来了,要注意的地方有:

1 shr跟C语言的>>运算不同,硬要在C语言实现shr的话需要给操作数加上unsigned int

2 有一个地方test al,0x1,写注册机的时候不可以直接eax==0,而是取eax的最低位判断是否为0

最终注册机完整代码如下:

#include <string.h>

#include <windows.h>

#include <stdio.h>

int *CRCTable=NULL;

void InitCRCTable()

{

     int i=0,j=0;

unsigned int k=0;

     while(i<=256-1)

     {  

  //i是edx k是eax j是esi

      k=i;

          j=8;

LabelJ_UnequalZero:

  //如果最后一位是0

          if((k&1)==0)

          {

                k=k>>1;

        j=j-1;

          }

          else

          {

                k=k>>1;

k=k^0xEDB88320;

j=j-1;

          }

  if(j!=0)

  {

        goto LabelJ_UnequalZero;

  }

          CRCTable[i++]=k;

     }

}

void main()

{

    CRCTable=(int*)malloc(256*sizeof(int));

InitCRCTable();

char szUserName[20];

char *szTmpPassword=(char*)malloc(20);

char *szFinalPassword=(char*)malloc(20);

memset(szTmpPassword,0,20);

memset(szFinalPassword,0,20);

int length=0;

unsigned int i;

unsigned int j;

unsigned int k;

unsigned int z;

scanf("%s",szUserName);

length=strlen(szUserName);

i=0xFFFFFFFF;

z=0;

    //这里i是edx j是eax z对应esi k=ebx

while(length!=0)

{

j=i;

k=0;

k=szUserName[z++];

j=j&0xFF;

j=j^k;

i=i>>8;

j=CRCTable[j];

i=i^j;

length=length-1;

//这个循环是要计算i的值,不知道这是什么,不妨命名为magic

}

//再取反一下

i=~i;

//转为字符串

sprintf(szTmpPassword,"%x",i);

//转为大写

szFinalPassword=strupr(szTmpPassword);

//输出

printf("%s\n",szFinalPassword);

}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 0
支持
分享
最新回复 (3)
雪    币: 119
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
支持顶!!!楼主申精啊。。
2013-8-12 22:26
0
雪    币: 45
活跃值: (55)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
我也想,太菜了 哈哈
2013-8-12 22:30
0
雪    币: 61
活跃值: (1006)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
膜拜会分析算法的
2013-8-12 23:15
0
游客
登录 | 注册 方可回帖
返回
// // 统计代码