首页
社区
课程
招聘
加密算法练习(MD5)
发表于: 2006-8-31 17:48 9674

加密算法练习(MD5)

2006-8-31 17:48
9674

【文章标题】: crackme破解分析
【文章作者】: 逍遥风
【下载地址】: 本地下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
----------------------------------------------------------------------
【详细过程】
  
  
  一个典型的应用MD5算法的实例,在分析时要注意,有的信息是迷惑我们的。要多加注意
  
  用OD载入这个CRACKME,根据注册提示信息或者命令行下断点
  BP GetDlgItemTextA
  都可以使程序中断,很容易找到关键代码处
  
  来到这里:
  00401A94   .  68 2C010000   push    12C                          ; /Count = 12C (300.)
  00401A99   .  68 80334000   push    00403380                     ; |Buffer = kgme_#1.00403380
  00401A9E   .  6A 64         push    64                           ; |ControlID = 64 (100.)
  00401AA0   .  FF75 08       push    dword ptr [ebp+8]            ; |hWnd
  00401AA3   .  E8 68010000   call    <jmp.&USER32.GetDlgItemTextA>; \GetDlgItemTextA
  00401AA8   .  0BC0          or      eax, eax                     ;  取注册名的位数
  00401AAA   .  75 19         jnz     short 00401AC5               ;  输入了注册名就不出现错误提示
  00401AAC   .  6A 00         push    0                            ; /Style = MB_OK|MB_APPLMODAL
  00401AAE   .  68 E0324000   push    004032E0                     ; |oooh input error
  00401AB3   .  68 F1324000   push    004032F1                     ; |your name please !!!
  00401AB8   .  6A 00         push    0                            ; |hOwner = NULL
  00401ABA   .  E8 5D010000   call    <jmp.&USER32.MessageBoxA>    ; \MessageBoxA
  00401ABF   .  C9            leave
  00401AC0   .  C2 1000       retn    10
  00401AC3   .  EB 33         jmp     short 00401AF8
  00401AC5   >  50            push    eax                          ;  准备取注册码
  00401AC6   .  68 2C010000   push    12C                          ; /Count = 12C (300.)
  00401ACB   .  68 F89C4000   push    00409CF8                     ; |Buffer = kgme_#1.00409CF8
  00401AD0   .  68 C8000000   push    0C8                          ; |ControlID = C8 (200.)
  00401AD5   .  FF75 08       push    dword ptr [ebp+8]            ; |hWnd
  00401AD8   .  E8 33010000   call    <jmp.&USER32.GetDlgItemTextA>; \GetDlgItemTextA
  00401ADD   .  0BC0          or      eax, eax                     ;  取注册码的位数
  00401ADF   .  75 17         jnz     short 00401AF8               ;  输入了注册码就不出现错误提示
  00401AE1   .  6A 00         push    0                            ; /Style = MB_OK|MB_APPLMODAL
  00401AE3   .  68 E0324000   push    004032E0                     ; |oooh input error
  00401AE8   .  68 06334000   push    00403306                     ; |where is da serial dude ?
  00401AED   .  6A 00         push    0                            ; |hOwner = NULL
  00401AEF   .  E8 28010000   call    <jmp.&USER32.MessageBoxA>    ; \MessageBoxA
  00401AF4   .  C9            leave
  00401AF5   .  C2 1000       retn    10
  00401AF8   >  68 34334000   push    00403334                     ; /byteptr [e!]
  00401AFD   .  68 80334000   push    00403380                     ; |ConcatString = "lovetc",80,""
  00401B02   .  E8 EB000000   call    <jmp.&KERNEL32.lstrcatA>     ; \lstrcatA
  00401B07   .  58            pop     eax                          ;  将注册名与固定字符串byteptr [e!]合并,设为字符串A
  
  这个字符串是干什么用的呢?本以为后的算法与这个字符串有关,但是经过分析
  后面的算法依然只是对注册名进行计算。与这个字符串无关。所以
  这个字符串是没有什么意义的。
   
  00401B08   .  68 A8564000   push    004056A8                     ; /Arg3 = 004056A8
  00401B0D   .  50            push    eax                          ; |Arg2
  00401B0E   .  68 80334000   push    00403380                     ; |Arg1 = 00403380
  00401B13   .  E8 E8F4FFFF   call    00401000                     ; \将注册名进行MD5运算
  00401B18   .  E8 5C000000   call    00401B79                     ;  对MD5计算结果进行处理
  
  将注册名进行MD5计算(如何知道是MD5只需跟进这个CALL,就会发现4个MD5常数)。
  那后面如何对MD5的计算结果进行处理呢?
  跟进对MD5计算结果处理的那个CALL,看看。
  来到这里 :
  
  
  00401B79  /$  60            pushad
  00401B7A  |.  BF D0794000   mov     edi, 004079D0        ;  用于存放最后的结果
  00401B7F  |.  BE A8564000   mov     esi, 004056A8        ;  将MD5(注册名)放进ESI中
  00401B84  |.  8B06          mov     eax, [esi]           ;  取第一组数据放进EAX中
  00401B86  |.  8B5E 04       mov     ebx, [esi+4]         ;  取第二组数据放进EBX中
  00401B89  |.  33C3          xor     eax, ebx             ;  XOR(第一组数据,第二组数据),结果设为A
  00401B8B  |.  50            push    eax                  ; /将结果A作为注册码的第一部分
  00401B8C  |.  68 5C334000   push    0040335C             ; |Format = "%.8X"
  00401B91  |.  57            push    edi                  ; |s => kgme_#1.004079D0
  00401B92  |.  E8 67000000   call    <jmp.&USER32.wsprint>; \wsprintfA
  00401B97  |.  83C4 0C       add     esp, 0C
  00401B9A  |.  83C7 08       add     edi, 8
  00401B9D  |.  81F3 9900BD0F xor     ebx, 0FBD0099        ;  XOR(第二组数据,0xFBD0099),结果设为B
  00401BA3  |.  53            push    ebx                  ; /将结果B作为注册码的第二部分
  00401BA4  |.  68 5C334000   push    0040335C             ; |Format = "%.8X"
  00401BA9  |.  57            push    edi                  ; |s
  00401BAA  |.  E8 4F000000   call    <jmp.&USER32.wsprint>; \wsprintfA
  00401BAF  |.  83C4 0C       add     esp, 0C
  00401BB2  |.  8B4E 08       mov     ecx, [esi+8]         ;  取第三组数据放进ECX中
  00401BB5  |.  33CB          xor     ecx, ebx             ;  XOR(第三组数据,结果B),计算结果设为C
  00401BB7  |.  83C7 08       add     edi, 8
  00401BBA  |.  51            push    ecx                  ; /<%.8X>
  00401BBB  |.  68 5C334000   push    0040335C             ; |将结果C作为注册码的第三部分
  00401BC0  |.  57            push    edi                  ; |s
  00401BC1  |.  E8 38000000   call    <jmp.&USER32.wsprint>; \wsprintfA
  00401BC6  |.  83C4 0C       add     esp, 0C
  00401BC9  |.  81F3 090A0C0B xor     ebx, 0B0C0A09        ;  XOR(结果C,0xB0C0A09),结果设为D
  00401BCF  |.  8B56 0C       mov     edx, [esi+C]         ;  取第四组数据
  00401BD2  |.  83C7 08       add     edi, 8
  00401BD5  |.  52            push    edx                  ; /第四组数据作为注册码的最后一部分
  00401BD6  |.  68 5C334000   push    0040335C             ; |Format = "%.8X"
  00401BDB  |.  57            push    edi                  ; |s
  00401BDC  |.  E8 1D000000   call    <jmp.&USER32.wsprint>; \wsprintfA
  00401BE1  |.  83C4 0C       add     esp, 0C              ;  结果D没有作用
  00401BE4  |.  61            popad
  00401BE5  \.  C3            retn
  
  还是以实例说明吧。以注册名:lovetc为例
  MD5(lovetc) =  3A76C4E1F2907B1C35319657E278EA05
  需要注意的是,现在就要对这个计算结果进行分组:
  将MD5计算结果以8位为一组进行分组:
  
    3A76C4E1       F2907B1C      35319657       E278EA05
       |               |             |              |
    第一组数据     第二组数据    第三组数据     第四组数据
  
  现在开始计算:
  1)
     XOR(第一组数据,第二组数据),结果设为A
     即:
     XOR (3A76C4E1,F2907B1C) = C8E6BFFD ------- 结果A
  2)
     XOR(第二组数据,0xFBD0099),结果设为B
     即:
     XOR (F2907B1C,0xFBD0099) = FD2D7B85 ------- 结果B
  3)
     XOR(第三组数据,结果B),结果设为C
     即:
     XOR(35319657,FD2D7B85)= C81CEDD2 -------  结果C
  4)
     XOR(结果C,0xB0C0A09),结果设为D
     既:
     XOR(FD2D7B85,0xB0C0A09)= F621718C ------ 结果D
  
  现在得到4个计算结果 ,但是最后一个计算结果(结果D)是没有参与组成注册码的。所以这个结果D也是没有意义的。
  注册码的最后一部分,是由MD5(注册名)的最后一组数据(第4组数据)组成的。
  
  所以最后的注册码为:(将3个计算结果与第四组数据合并)
  
  
  合并:  C8E6BFFD   FD2D7B85  C81CEDD2  E278EA05
  
  00401B1D   .  68 D0794000   push    004079D0                     ; /String2 = "C8E6BFFDFD2D7B85C81CEDD2E278EA05"
  00401B22   .  68 F89C4000   push    00409CF8                     ; |String1 = "1234567"
  00401B27   .  E8 CC000000   call    <jmp.&KERNEL32.lstrcmpA>     ; \lstrcmpA
  最后真正的注册码与输入的注册码进行比较。
   
  所以:
  注册名:lovetc
  注册码:C8E6BFFDFD2D7B85C81CEDD2E278EA05
  
----------------------------------------------------------------------

【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2006年08月31日 17:45:33


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 7
支持
分享
最新回复 (13)
雪    币: 372
活跃值: (31)
能力值: ( LV12,RANK:410 )
在线值:
发帖
回帖
粉丝
2
学习~~
2006-8-31 19:37
0
雪    币: 338
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
算法高手!!
2006-8-31 21:27
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
MD5算法的特征是看那4个常数,算法可不必深究,但在哪里看到计算的结果?这是继续往下分析的线索.楼主没有说明呀.我进入"call 00401000 "; (\将注册名进行MD5运算")找不到计算结果.楼主的另一破文(SHA-160加密算法练习)也有同样
问题,期望楼主把怎样找到算法结果说明白......................同时楼主也应当就此例做些MD5变形算法的解析.
2006-9-2 19:59
0
雪    币: 2256
活跃值: (941)
能力值: (RANK:2210 )
在线值:
发帖
回帖
粉丝
5
在命令行输入
D命令,就可以看到计算的结果了.

例如 :这里就是D 004079D0
2006-9-2 21:44
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
谁能解mz.exer的强壳。。
2006-9-26 22:06
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
版主能帮我破精灵外挂的壳吗。。它是用themida加密的吗。。

2006-9-27 10:34
0
雪    币: 309
活跃值: (15)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
8
兄弟好强,偶慢慢研究下啊~~
2006-10-6 12:10
0
雪    币: 177
活跃值: (40)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
9
MD5,学习一下~
2006-10-7 12:35
0
雪    币: 177
活跃值: (40)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
perl写了个注册机
#!/usr/local/bin/perl

use Digest::MD5;

$data=<>;
chomp($data);

$ctx = Digest::MD5->new;
$ctx->add($data);
$digest = $ctx->hexdigest;

#print $digest, "\n";

$i=0;
$eax = hex(substr($digest, $i, 8));
$i+=8;
$ebx = hex(substr($digest, $i, 8));
$i+=8;
$eax ^= $ebx;
printf "%X", $eax;

$ebx ^= 0xfbd0099;
printf "%X", $ebx;

$ecx = hex(substr($digest, $i, 8));
$i += 8;
$ecx ^= $ebx;
printf "%X", $ecx;

$ebx = hex(substr($digest, $i, 8));
printf "%X\n", $ebx;

2006-10-16 17:18
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
汗,跟着追,追到这里
00401B27   .  E8 CC000000   call    <jmp.&KERNEL32.lstrcmpA>     ;
追进这个call,看了老半天才明白是真假注册码比较,再去google了一下,发现这是一个经常用来下断的API函数,又学到了一点东西.
  不至于看到算法的东西就躲着走了:)
2006-11-5 11:13
0
雪    币: 405
活跃值: (10)
能力值: ( LV9,RANK:1130 )
在线值:
发帖
回帖
粉丝
12
最初由 茶半 发布
汗,跟着追,追到这里
00401B27 . E8 CC000000 call <jmp.&KERNEL32.lstrcmpA> ;
追进这个call,看了老半天才明白是真假注册码比较,再去google了一下,发现这是一个经常用来下断的API函数,又学到了一点东西.
不至于看到算法的东西就躲着走了:)


<jmp.&KERNEL32.lstrcmpA>     你的OD不错哦,可以显示出函数,要怎么设置的啊?
2006-11-5 11:25
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
最初由 binbinbin 发布
<jmp.&KERNEL32.lstrcmpA> 你的OD不错哦,可以显示出函数,要怎么设置的啊?

  选项,调试选项,分析2,显示已知函数的参数,应该是这里吧,我也是前几天从这里下载的OD,默认设置.刚刚学了才一周,什么设置都不敢改
2006-11-5 11:58
0
雪    币: 33
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
真的不是一般的牛人哈。支持了。学习了
2006-11-7 12:00
0
游客
登录 | 注册 方可回帖
返回
//