搜索文章:

首页  |  Java技术  |  Asp.net  |  Asp编程  |  VC/C++  |  Delphi  |  VB编程

ikki_CrackMe变形SHA和变形BlowFish逆向分析(…

ikki_CrackMe变形SHA和变形BlowFish逆向分析(一)----全局篇
首先祝大家新年快乐万事如意,很久没有写过一篇文章了,看到别人写出一篇篇精彩文章,手不禁有些庠庠的,实在没什么写的,近来在学习密码学算法,所以写下了这个学习笔记。


[目标程序]CrackMe N0 2 by ikki
[目  的]学习密码学算法。
[下载地址]
附件:crackme.No.2.rar
[作  者]小虾(战神[DFCG])
[官方论坛]http://www.chinadfcg.com

首先要说明的是,这篇文章是我学习密码学算法的笔记之一,写得不好,如果你是高手就不必看了,否则就一定要捂紧大嘴,免得笑掉了大牙。这个CrackMe N0 2是ikki早前放出来的,已经有二、三个月了,但至今还没有结果(也可能是我没有看见到)。其次这个CrackMe一开始放出来时我就接触过了,开始跟踪后才发现这个CrackMe用了密码学算法,但那时学识浅,不认识。于是在看雪主页下载了一个密码学分析软件后发现这个算法使用了SHA1和BlowFish算法,于是我又兴冲冲地在网上找来这两个加密解密算法的工具,但很可惜,ikki可能对这个算法进行过变形处理,我的工具算出的值和CrackMe算出的值不相同。最后我的第一次Crack流产。

现经过这二、三个月的时间,学习了一些密码学算法,对SHA1和BlowFish算法有了一个大概的理解,于是为了实践自己的理解,这次再拿他出来研究研究。呵呵!

最后说明,我学习Crack才一年半有余,学习编程也就四、五个月左右(ASM、C、VB、Delphi(Pascal)),目前也只对Delphi(Pascal)比较熟悉一点点(只是熟悉一点点,嘿嘿,贪多的下场),所以我下面的注释和写注册机时,用了Delph(Pascal)语言,不过我学习编程也就四、五个月,所以代码写得不怎么样,还请大家见谅。

说到这里,我们还是转入正题,来看看这个CrackMe吧。这个算法没有反跟跟和反爆破,所以关键点很好定位,一般只要有一些Crack经验的人都能很快定位到关键点并爆破之(但采用破爆就没什么意思了)。不过这个CrackMe采取两种加密算法(还是变形的),而且是非明码比较,所以要得正确的注册码很不容易(SHA1算法代码超长,看到就头晕),因为我们必须对这个CrackMe的整个算法进行分析,最后还得写出BlowFish的解密算法。

因为分析文章会比较长,所以,我将这个CrackMe分成三次来分析,第一次是开幕篇,主要分析整体框架结构,第二次是分析SHA1的算法,第三次则分析BlowFish算法并写出解密算法。

呵呵,废话说得太多了,现在我们开始吧。用OD加载目标程序,F9运行。接着在程序的输入框中填入用户名、注册码一和注册码二。然后下断bpx GetDlgItemTextA(如果你的系统是Win2K以上也可以下API断点:bp GetDlgItemTextA)。

用户名:zhanshen[dfcg]
试炼码:78787878-12121212

接着按确定按钮,程序将中断在这里,GetDlgItemTextA这个函数不用我说了吧,作用是取得Edit1.Text的Name_Str。
00411D49     CALL DWORD PTR DS:[<&USER32.GetDlgItemTextA>]   ; \GetDlgItemTextA
00411D4F     CMP ESI,ESP
00411D51     CALL CRACKME_.004113FC
00411D56     LEA EAX,DWORD PTR SS:[EBP-EC]
00411D5C     PUSH EAX
00411D5D     CALL CRACKME_.00411221                          ;  取得Name_Len
00411D62     ADD ESP,4
00411D65     MOV DWORD PTR SS:[EBP-F8],EAX                   ;  保存Name_Len

这里比较输入的用户名长度是否小于1和大于等于0x64,不等则OVER。
00411D6B     CMP DWORD PTR SS:[EBP-F8],1
00411D72     JL SHORT CRACKME_.00411D7D                      ;  if Name_Len < 1 then Exit;
00411D74     CMP DWORD PTR SS:[EBP-F8],64
00411D7B     JLE SHORT CRACKME_.00411DA4                     ;  if not(Name_Len <= $64) then Exit;
00411D7D     MOV ESI,ESP

Name_Len为空的出错提示。
00411D7F     PUSH 0                                          ; /Style = MB_OK|MB_APPLMODAL
00411D81     LEA EAX,DWORD PTR SS:[EBP-24]                   ; |
00411D84     PUSH EAX                                        ; |Title
00411D85     LEA ECX,DWORD PTR SS:[EBP-14]                   ; |
00411D88     PUSH ECX                                        ; |Text
00411D89     MOV EDX,DWORD PTR SS:[EBP+8]                    ; |
00411D8C     PUSH EDX                                        ; |hOwner
00411D8D     CALL DWORD PTR DS:[<&USER32.MessageBoxA>]       ; \MessageBoxA
00411D93     CMP ESI,ESP
00411D95     CALL CRACKME_.004113FC
00411D9A     MOV EAX,1
00411D9F     JMP CRACKME_.00411EEA                           ; OVER;

这里开始进行SHA1的常规始初化常数。这个函数参考原型如下:
procedure SHA1_Init(var SHA1_Init:array of DWORD);
00411DA4     MOV DWORD PTR SS:[EBP-124],0                    ;  var Sn1:DWORD = 0;
00411DAE     XOR EAX,EAX
00411DB0     MOV DWORD PTR SS:[EBP-120],EAX                  ;  var Sn2:DWORD = 0;
00411DB6     LEA EAX,DWORD PTR SS:[EBP-114]                  ;  var SHA1_Init[1..5] of DWORD;
00411DBC     PUSH EAX
00411DBD     CALL CRACKME_.0041117C                          ;  CALL SHA1_Init;
00411DC2     ADD ESP,4

开始用Name_Str填充待加密的64位消息。这个函数包含了SHA1_En加密算法在内,现先不管他,待后再分析。填充64位消息函数参考原型如下:
procedure Name_Init_64(var SHA1_Init:array of DWORDvar Name_Str:Stringvar Name_Len:DWORD; tmp:DWORD = 0);
00411DC5     PUSH 0                                          ;  var tmp:DWORD = 0;
00411DC7     MOV EAX,DWORD PTR SS:[EBP-F8]
00411DCD     PUSH EAX                                        ;  var Name_Len
00411DCE     LEA ECX,DWORD PTR SS:[EBP-EC]
00411DD4     PUSH ECX                                        ;  var Name_Str;
00411DD5     LEA EDX,DWORD PTR SS:[EBP-114]
00411DDB     PUSH EDX                                        ;  var SHA1_Init:array[1..5] of DWORD;
00411DDC     CALL CRACKME_.004110C8                          ;  CALL SHA1_Init;
00411DE1     ADD ESP,10

这里开始填充BlowFish的Key,密钥就是经过SHA1加密的Name_Str。这个函数参考原型如下:
procedure BlowFish_Init(var BlowFish_Init:array of DWORDvar SHA_Init_En:array of DWORD);
00411DE4     LEA EAX,DWORD PTR SS:[EBP-114]
00411DEA     PUSH EAX                                        ;  var SHA1_Init_En[1..5] of DWORD;
00411DEB     LEA ECX,DWORD PTR SS:[EBP-11AC]
00411DF1     PUSH ECX                                        ;  var BlowFish_Init:array[1..1024] of DWORD;
00411DF2     CALL CRACKME_.004112A8                          ;  CALL BlowFish_Init;
00411DF7     ADD ESP,8
00411DFA     MOV ESI,ESP

这个函数也不用说了吧,这个函数就是将Edit2.Text的Sn1取出并转为整数(Hex)。在Delphi中就有StrToInt函数。不过我还是喜欢我自己编写一个这样的函数(Delphi的这个函数若遇上ABCD等字母会出常异常)。
00411DFC     PUSH 0                                          ; /IsSigned = FALSE
00411DFE     PUSH 0                                          ; |pSuccess = NULL
00411E00     PUSH 3ED                                        ; |ControlID = 3ED (1005.)
00411E05     MOV EAX,DWORD PTR SS:[EBP+8]                    ; |
00411E08     PUSH EAX                                        ; |hWnd
00411E09     CALL DWORD PTR DS:[<&USER32.GetDlgItemInt>]     ; \GetDlgItemInt
00411E0F     CMP ESI,ESP
00411E11     CALL CRACKME_.004113FC

保存Sn1
00411E16     MOV DWORD PTR SS:[EBP-124],EAX                  ;  Sn1 := MyStrToHex(Edit2.Text);
00411E1C     MOV ESI,ESP

和上面一样,将Edit3.Text取出并转为整数(Hex)。
00411E1E     PUSH 0                                          ; /IsSigned = FALSE
00411E20     PUSH 0                                          ; |pSuccess = NULL
00411E22     PUSH 3F0                                        ; |ControlID = 3F0 (1008.)
00411E27     MOV EAX,DWORD PTR SS:[EBP+8]                    ; |
00411E2A     PUSH EAX                                        ; |hWnd
00411E2B     CALL DWORD PTR DS:[<&USER32.GetDlgItemInt>]     ; \GetDlgItemInt
00411E31     CMP ESI,ESP
00411E33     CALL CRACKME_.004113FC

保存Sn2
00411E38     MOV DWORD PTR SS:[EBP-120],EAX                  ;  Sn2 := MyStrToHex(Edit3.Text);

这里开始对Sn1和Sn2进行BlowFish_En加密。参考函数原型如下:
procedure BlowFish_En(var BlowFish_Init_En:array of DWORDvar Sn1, Sn2:DWORD);
00411E3E     LEA EAX,DWORD PTR SS:[EBP-120]
00411E44     PUSH EAX                                        ;  var Sn2:DWORD;
00411E45     LEA ECX,DWORD PTR SS:[EBP-124]
00411E4B     PUSH ECX                                        ;  var Sn1:DWORD;
00411E4C     LEA EDX,DWORD PTR SS:[EBP-11AC]
00411E52     PUSH EDX                                        ;  var BlowFish_Init_En:array[1..1024] of DWORD;
00411E53     CALL CRACKME_.004114D3                          ;  CALL BlowFish_En;
00411E58     ADD ESP,0C

这里开始进行用户名和注册码的比较,因为BlowFish算法是_64位的分组对称加密算法,所以要比较两次。
第一次:if (SHA1_Init_En[1] xor SHA1_Init_En[5]) <> Sn1_En then 就OVER了。
第二次:if (SHA1_Init_En[2] xor SHA1_Init_En[4]) <> Sn2_En then 就OVER了。
00411E5B     MOV EAX,DWORD PTR SS:[EBP-114]                  ;  SHA1_Init_En[1]
00411E61     XOR EAX,DWORD PTR SS:[EBP-104]
00411E67     CMP DWORD PTR SS:[EBP-124],EAX

第一次关键比较,如果要爆破的话将这里NOP掉。
00411E6D     JNZ SHORT CRACKME_.00411EA5                     ;  if (SHA1_Init_En[1] xor SHA1_Init_En[5]) <> Sn1_En then Exit;
00411E6F     MOV EAX,DWORD PTR SS:[EBP-110]                  ;  SHA1_Init_En[2]
00411E75     XOR EAX,DWORD PTR SS:[EBP-108]

第二次关键比较,爆破的话这里也要NOP掉。
00411E7B     CMP DWORD PTR SS:[EBP-120],EAX
00411E81     JNZ SHORT CRACKME_.00411EA5                     ;  if (SHA1_Init_En[2] xor SHA1_Init_En[4]) <> Sn2_En then Exit;
00411E83     MOV ESI,ESP

这个对话框是注册成功的对话框。
00411E85     PUSH 2040                                       ; /Style = MB_OK|MB_ICONASTERISK|MB_TASKMODAL
00411E8A     LEA EAX,DWORD PTR SS:[EBP-50]                   ; |
00411E8D     PUSH EAX                                        ; |Title
00411E8E     LEA ECX,DWORD PTR SS:[EBP-38]                   ; |
00411E91     PUSH ECX                                        ; |Text
00411E92     MOV EDX,DWORD PTR SS:[EBP+8]                    ; |
00411E95     PUSH EDX                                        ; |hOwner
00411E96     CALL DWORD PTR DS:[<&USER32.MessageBoxA>]       ; \MessageBoxA
00411E9C     CMP ESI,ESP
00411E9E     CALL CRACKME_.004113FC
00411EA3     JMP SHORT CRACKME_.00411EC5
00411EA5     MOV ESI,ESP

这个对话框是注册失败的对话框。至此,后面的没什么可说的了。
00411EA7     PUSH 2030                                       ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_TASKMODAL
00411EAC     LEA EAX,DWORD PTR SS:[EBP-7C]                   ; |
00411EAF     PUSH EAX                                        ; |Title
00411EB0     LEA ECX,DWORD PTR SS:[EBP-6C]                   ; |
00411EB3     PUSH ECX                                        ; |Text
00411EB4     MOV EDX,DWORD PTR SS:[EBP+8]                    ; |
00411EB7     PUSH EDX                                        ; |hOwner
00411EB8     CALL DWORD PTR DS:[<&USER32.MessageBoxA>]       ; \MessageBoxA
00411EBE     CMP ESI,ESP
00411EC0     CALL CRACKME_.004113FC
00411EC5     MOV EAX,1
00411ECA     JMP SHORT CRACKME_.00411EEA
00411ECC     MOV ESI,ESP
00411ECE     PUSH 0                                          ; /Result = 0
00411ED0     MOV EAX,DWORD PTR SS:[EBP+8]                    ; |
00411ED3     PUSH EAX                                        ; |hWnd
00411ED4     CALL DWORD PTR DS:[<&USER32.EndDialog>]         ; \EndDialog
00411EDA     CMP ESI,ESP
00411EDC     CALL CRACKME_.004113FC
00411EE1     MOV EAX,1
00411EE6     JMP SHORT CRACKME_.00411EEA
00411EE8     XOR EAX,EAX
00411EEA     PUSH EDX
00411EEB     MOV ECX,EBP
00411EED     PUSH EAX
00411EEE     LEA EDX,DWORD PTR DS:[411F11]
00411EF4     CALL CRACKME_.004111D1
00411EF9     POP EAX
00411EFA     POP EDX
00411EFB     POP EDI
00411EFC     POP ESI
00411EFD     POP EBX
00411EFE     ADD ESP,1274
00411F04     CMP EBP,ESP
00411F06     CALL CRACKME_.004113FC
00411F0B     MOV ESP,EBP
00411F0D     POP EBP
00411F0E     RETN 10

至此,第一篇文章分析完毕,接着进行第二篇SHA1算法的分析(不过我是边分析边写破文的,SHA1算法还没完全写完(呵呵,看到一大段的代码我的头都有点晕了),所以,第二篇可能要明天或后天了)。未完待续。。。

----本文只能作为内部研究之用,如需转载请保持文章的完整性,谢谢!----小虾(战神[DFCG]),2005/2/10

相关文章:
© 2006   www.java-asp.net