surge 发表于 2005-11-29 13:30:57

一个简单至级的keyfile-crackme分析

因为这人keyfile的保护比较简单,所以一直不打算写这个教程,我想有的兄弟可能早就把它破了.但看到一些新手不知如何下手,所以还是把这个教程贴出来了,不知道老大是不是允许我这样做.如果我做的不对,请老大批评,下次一定改正.

因为是针对初学者,所以我尽量写的详细些,希望其它兄弟有什么关于攻破keyfile保护的思路及方法,在后面跟下贴子,一起来帮助还在大门外徘徊的新手尽快入门.我写的有什么不对的地方,还望大家指正,以免误人.

od载入之后中断在如下代码处:
---------------------------------
00428001pushad
00428002jmp   ex1401.00428444
00428007jmp   01438531
---------------------------------
分析:一开始PUSHAD把EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI依次压入堆栈.
这是加壳程序通常的做法,壳代码执行完后会将这些寄存器出栈,并跳到
原始程序的入口代码执行.这里F8单步跟踪一次,看到ESP=0012FFA4,用著
名的ESP定律命令栏下断 hr 0012ffa4,回车,F9运行,断下来了:
--------------------------------
004283AApopad                                  ; 这里和上面的pushad对应
004283ABjnz   short ex1401.004283B5 ; 中断在这里,此时esp=0012ffc4,F8跳走
004283ADmov   eax, 1
004283B2retn    0C
004283B5push    ex1401.00401000       ; 跳到这里,把OEP压入堆栈,下面的ret就会返回到OEP.
004283BAretn
---------------------------------

===============================================================
脱壳后命令行下断bp CreateFileA,F9运行程序断下来了,堆栈提示如下:
---------------------------------------------------------------
0012FD40   004010B4/CALL 到 CreateFileA 来自 1.004010AF
0012FD44   004020E5|FileName = ".Key"
0012FD48   C0000000|Access = GENERIC_READ|GENERIC_WRITE
0012FD4C   00000003|ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
0012FD50   00000000|pSecurity = NULL
0012FD54   00000003|Mode = OPEN_EXISTING
0012FD58   004020EF|Attributes = READONLY|HIDDEN|SYSTEM|ARCHIVE|NORMAL|4>
0012FD5C   00000000\hTemplateFile = NULL
---------------------------------------------------------------
从这里看出是要读取.Key文件,调用来自004010AF,Alt+F9返回到程序领空
---------------------------------------------------------------------
00401098push    0                                 ; /hTemplateFile = NULL
0040109Apush    1.004020EF                  ; |Attributes = READONLY|HIDDEN|SYSTEM|ARCHIVE|NORMAL|402048
0040109Fpush    3                                 ; |Mode = OPEN_EXISTING
004010A1push    0                              ; |pSecurity = NULL
004010A3push    3                              ; |ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
004010A5push    C0000000                  ; |Access = GENERIC_READ|GENERIC_WRITE
004010AApush    1.004020E5                  ; |FileName = ".Key"
004010AFcall    <jmp.&kernel32.CreateFileA> ; \CreateFileA
004010B4mov   dword ptr ds:, eax;此时eax=ffffffff是-1,说明打开.Key文件失败了,
004010B9cmp   dword ptr ds:, -1
004010C0je      1.00401158                  ;所以就会跳走了,
----------------------------------------------------------------
跳走之后就到这里了,可以看出是显示尚未成功的消息框.
----------------------------------------------------------------
00401158push    1000                         ; /Style = MB_OK|MB_SYSTEMMODAL
0040115Dpush    1.00402026                ; |Title = "OfficialCrackme"
00401162push    1.00402083                ; |Text = "革命尚未成功,破解者仍需努力阿。^_^ GOOD LUCK!"
00401167push    0                               ; |hOwner = NULL
00401169call    <jmp.&user32.MessageBoxA> ; \MessageBoxA
================================================================
以上完成初步的粗跟踪,知道了程序要打开一个名为.Key的文件,
如果没有这个文件,就出现尚未成功的消息框,所以建一个文本文件,
命名为.Key,输入一些数据我输入的是123456.
Ctrl+F2重新运行,命令行下断点bp CreateFileA,F9运行程序,断下来后,
Alt+F9返回到程序领空
----------------------------------------------------------------
00401098push    0                           ; /hTemplateFile = NULL
0040109Apush    1.004020EF                  ; |Attributes = READONLY|HIDDEN|SYSTEM|ARCHIVE|NORMAL|402048
0040109Fpush    3                           ; |Mode = OPEN_EXISTING
004010A1push    0                           ; |pSecurity = NULL
004010A3push    3                           ; |ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
004010A5push    C0000000                  ; |Access = GENERIC_READ|GENERIC_WRITE
004010AApush    1.004020E5                  ; |FileName = ".Key"
004010AFcall    <jmp.&kernel32.CreateFileA> ; \CreateFileA
004010B4mov   dword ptr ds:, eax;此时eax返回打开文件的句柄.保存在402000
004010B9cmp   dword ptr ds:, -1
004010C0je      1.00401158                  ;这里不会跳走了,
----------------------------------------------
打开.key文件成功了,接着开始读文件里的内容
----------------------------------------------
004010C6push    0                                 ; /pOverlapped = NULL
004010C8push    1.00402107                  ; |pBytesRead = 1.00402107
004010CDpush    0A                               ; |BytesToRead = A (10.)
004010CFpush    1.004020F3                  ; |这里是读取的缓冲区指针,在命令行下d 4020f3观察一下
004010D4push    dword ptr ds:       ; |这里就是上面打开的那个文件的句柄
004010DAcall    <jmp.&kernel32.ReadFile>    ; \ReadFile
-----------------------------------------------
这时在命令行下d 4020f3命令,查看一下4020f3的内容,
如下会看到我输入的123456.
---------
004020F331 32 33 34 35 36 00 00123456..
-----------------------------------------------
004010DFtest    eax, eax
004010E1je      short 1.00401158             ;这里是判断是不是读取成功
004010E3push    0                                  ; /pOverlapped = NULL
004010E5push    1.00402107                   ; |pBytesRead = 1.00402107
004010EApush    0A                              ; |读取缓冲区大小为10个字节
004010ECpush    1.004020FD                   ; |这里是读取的缓冲区指针,在命令行下d 4020fd观察一下
004010F1push    dword ptr ds:      ; |这里就是上面打开的那个文件的句柄
004010F7call    <jmp.&kernel32.ReadFile>   ; \ReadFile
----------------------------------------------------
从上面看来对这个.key文件读了两次,每次读10个字节
分别放在了内存地址004020F3和004020FD
----------------------------------------------------
004010FCtest    eax, eax
004010FEje      short 1.00401158               ;这里是判断是不是读取成功
00401100push    dword ptr ds:      ; /这里就是上面打开的那个文件的句柄
00401106call    <jmp.&kernel32.CloseHandle>; \关闭前面打开的文件对象
0040110Bxor   eax, eax
0040110Djmp   short 1.00401113                ;跳到关键的地方去了!
0040110Fleave
00401110retn    10
-----------------------------------------------
下面就是关键了,在命令行下d 4020f3,一边跟踪
一边观察数据的变化
-----------------------------------------------
00401113xor   byte ptr ds:, 58 ;将缓冲区字符串依次与0x58异或
0040111Ainc   eax
0040111Bcmp   byte ptr ds:, 0;直到遇到00结尾
00401122jnz   short 1.00401113
-----------------------------------------------
处理完后来个比较
-------------------
00401124push    1.004020F3                   ; /字符串地址
00401129push    1.004020FD                   ; |字符串地址
0040112Ecall    <jmp.&kernel32.lstrcmp>   ; \比较是不是相等
00401133cmp   eax, 0
00401136je      short 1.0040113E             ;相等就成功了
-----------------------------------------------
00401138jmp   short 1.00401158
0040113Aleave
0040113Bretn    10
0040113Epush    1000                         ; /Style = MB_OK|MB_SYSTEMMODAL
00401143push    1.00402026                   ; |Title = "OfficialCrackme"
00401148push    1.004020BF                   ; |Text = "注册验证成功,恭喜您成功破解了这个程序"
0040114Dpush    0                            ; |hOwner = NULL
0040114Fcall    <jmp.&user32.MessageBoxA>    ; \MessageBoxA
00401154leave
00401155retn    10
00401158push    1000                         ; /Style = MB_OK|MB_SYSTEMMODAL
0040115Dpush    1.00402026               ; |Title = "OfficialCrackme"
00401162push    1.00402083                ; |Text = "革命尚未成功,破解者仍需努力阿。^_^ GOOD LUCK!"
00401167push    0                               ; |hOwner = NULL
00401169call    <jmp.&user32.MessageBoxA>    ; \MessageBoxA
0040116Eleave
0040116Fretn    10
00401172push    1000                        ; /Style = MB_OK|MB_SYSTEMMODAL
00401177push    1.00402026               ; |Title = "OfficialCrackme"
0040117Cpush    1.00402036               ; |Text = "中国破解组织BCG(BeNGiN's CrACKiNG GrOUp)Official CrackMe程序娃娃/制作"
00401181push    0                                 ; |hOwner = NULL
00401183call    <jmp.&user32.MessageBoxA>    ; \MessageBoxA
00401188leave
00401189retn    10
======================================================================
总结一下:
只要保证运算后的内存地址004020F3和004020FD指向的字符串相等就能成功,
大家都知道,字符串是以0结尾的.因为运算是简单的与58异或,而0 == 58 xor 58
58就是字符X,所以文件内容可以是如下形式:
*********X*********X
********X*********X*
......
只要X前后的*相等就可以,有很多种组合.
-------------------------------------------
另外如果文件小于10个字符,004020FD指向的总会是个空串,004020F3要构造一个空串
只要内容第一个是X其它任意,总计小于10个字符就行了,
所以还可以是如下形式:
X*********
======================================================================
surge
surgefree@163.com
2005-11-29
完.

风球 发表于 2005-11-29 15:39:09

兄弟好样的,写的好详细啊```分析得很好,学习了^_^

IceCrack 发表于 2005-12-27 14:01:52

看着相当的不错啊   我代新手们谢谢你了   看这个让我想了半天最后终于是看懂了不错

野猫III 发表于 2006-3-27 00:26:46

学习咯。。。

eopenfang 发表于 2006-7-24 13:11:43

懂了,

明白了,谢谢

rongaie 发表于 2006-7-25 09:04:47

joker27 发表于 2006-7-26 19:39:26

没弄名太keyfile怎么搞,米玩过

网游难民 发表于 2006-7-28 23:09:58

新手来学习的好文章哦~~~
楼主不要那么谦虚哦~~
严重支持~~

沙粒 发表于 2006-7-29 15:09:08

看着相当的不错啊   我代新手们谢谢你了
页: [1]
查看完整版本: 一个简单至级的keyfile-crackme分析