一个简单至级的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
[email protected]
2005-11-29
完. 兄弟好样的,写的好详细啊```分析得很好,学习了^_^ 看着相当的不错啊 我代新手们谢谢你了 看这个让我想了半天最后终于是看懂了不错 学习咯。。。
懂了,
明白了,谢谢 没弄名太keyfile怎么搞,米玩过 新手来学习的好文章哦~~~楼主不要那么谦虚哦~~
严重支持~~ 看着相当的不错啊 我代新手们谢谢你了
页:
[1]