- UID
- 2927
注册时间2005-8-29
阅读权限20
最后登录1970-1-1
以武会友
该用户从未签到
|
因为这人keyfile的保护比较简单,所以一直不打算写这个教程,我想有的兄弟可能早就把它破了.但看到一些新手不知如何下手,所以还是把这个教程贴出来了,不知道老大是不是允许我这样做.如果我做的不对,请老大批评,下次一定改正.
因为是针对初学者,所以我尽量写的详细些,希望其它兄弟有什么关于攻破keyfile保护的思路及方法,在后面跟下贴子,一起来帮助还在大门外徘徊的新手尽快入门.我写的有什么不对的地方,还望大家指正,以免误人.
od载入之后中断在如下代码处:
---------------------------------
00428001 pushad
00428002 jmp ex1401.00428444
00428007 jmp 01438531
---------------------------------
分析:一开始PUSHAD把EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI依次压入堆栈.
这是加壳程序通常的做法,壳代码执行完后会将这些寄存器出栈,并跳到
原始程序的入口代码执行.这里F8单步跟踪一次,看到ESP=0012FFA4,用著
名的ESP定律命令栏下断 hr 0012ffa4,回车,F9运行,断下来了:
--------------------------------
004283AA popad ; 这里和上面的pushad对应
004283AB jnz short ex1401.004283B5 ; 中断在这里,此时esp=0012ffc4,F8跳走
004283AD mov eax, 1
004283B2 retn 0C
004283B5 push ex1401.00401000 ; 跳到这里,把OEP压入堆栈,下面的ret就会返回到OEP.
004283BA retn
---------------------------------
===============================================================
脱壳后命令行下断bp CreateFileA,F9运行程序断下来了,堆栈提示如下:
---------------------------------------------------------------
0012FD40 004010B4 /CALL 到 CreateFileA 来自 1.004010AF
0012FD44 004020E5 |FileName = "[BCG].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
---------------------------------------------------------------
从这里看出是要读取[BCG].Key文件,调用来自004010AF,Alt+F9返回到程序领空
---------------------------------------------------------------------
00401098 push 0 ; /hTemplateFile = NULL
0040109A push 1.004020EF ; |Attributes = READONLY|HIDDEN|SYSTEM|ARCHIVE|NORMAL|402048
0040109F push 3 ; |Mode = OPEN_EXISTING
004010A1 push 0 ; |pSecurity = NULL
004010A3 push 3 ; |ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
004010A5 push C0000000 ; |Access = GENERIC_READ|GENERIC_WRITE
004010AA push 1.004020E5 ; |FileName = "[BCG].Key"
004010AF call <jmp.&kernel32.CreateFileA> ; \CreateFileA
004010B4 mov dword ptr ds:[402000], eax ; 此时eax=ffffffff是-1,说明打开[BCG].Key文件失败了,
004010B9 cmp dword ptr ds:[402000], -1
004010C0 je 1.00401158 ; 所以就会跳走了,
----------------------------------------------------------------
跳走之后就到这里了,可以看出是显示尚未成功的消息框.
----------------------------------------------------------------
00401158 push 1000 ; /Style = MB_OK|MB_SYSTEMMODAL
0040115D push 1.00402026 ; |Title = "OfficialCrackme"
00401162 push 1.00402083 ; |Text = "革命尚未成功,破解者仍需努力阿。^_^ GOOD LUCK!"
00401167 push 0 ; |hOwner = NULL
00401169 call <jmp.&user32.MessageBoxA> ; \MessageBoxA
================================================================
以上完成初步的粗跟踪,知道了程序要打开一个名为[BCG].Key的文件,
如果没有这个文件,就出现尚未成功的消息框,所以建一个文本文件,
命名为[BCG].Key,输入一些数据我输入的是123456.
Ctrl+F2重新运行,命令行下断点bp CreateFileA,F9运行程序,断下来后,
Alt+F9返回到程序领空
----------------------------------------------------------------
00401098 push 0 ; /hTemplateFile = NULL
0040109A push 1.004020EF ; |Attributes = READONLY|HIDDEN|SYSTEM|ARCHIVE|NORMAL|402048
0040109F push 3 ; |Mode = OPEN_EXISTING
004010A1 push 0 ; |pSecurity = NULL
004010A3 push 3 ; |ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
004010A5 push C0000000 ; |Access = GENERIC_READ|GENERIC_WRITE
004010AA push 1.004020E5 ; |FileName = "[BCG].Key"
004010AF call <jmp.&kernel32.CreateFileA> ; \CreateFileA
004010B4 mov dword ptr ds:[402000], eax ; 此时eax返回打开文件的句柄.保存在402000
004010B9 cmp dword ptr ds:[402000], -1
004010C0 je 1.00401158 ; 这里不会跳走了,
----------------------------------------------
打开[bcg].key文件成功了,接着开始读文件里的内容
----------------------------------------------
004010C6 push 0 ; /pOverlapped = NULL
004010C8 push 1.00402107 ; |pBytesRead = 1.00402107
004010CD push 0A ; |BytesToRead = A (10.)
004010CF push 1.004020F3 ; |这里是读取的缓冲区指针,在命令行下d 4020f3观察一下
004010D4 push dword ptr ds:[402000] ; |这里就是上面打开的那个文件的句柄
004010DA call <jmp.&kernel32.ReadFile> ; \ReadFile
-----------------------------------------------
这时在命令行下d 4020f3命令,查看一下4020f3的内容,
如下会看到我输入的123456.
---------
004020F3 31 32 33 34 35 36 00 00 123456..
-----------------------------------------------
004010DF test eax, eax
004010E1 je short 1.00401158 ; 这里是判断是不是读取成功
004010E3 push 0 ; /pOverlapped = NULL
004010E5 push 1.00402107 ; |pBytesRead = 1.00402107
004010EA push 0A ; |读取缓冲区大小为10个字节
004010EC push 1.004020FD ; |这里是读取的缓冲区指针,在命令行下d 4020fd观察一下
004010F1 push dword ptr ds:[402000] ; |这里就是上面打开的那个文件的句柄
004010F7 call <jmp.&kernel32.ReadFile> ; \ReadFile
----------------------------------------------------
从上面看来对这个[bcg].key文件读了两次,每次读10个字节
分别放在了内存地址004020F3和004020FD
----------------------------------------------------
004010FC test eax, eax
004010FE je short 1.00401158 ; 这里是判断是不是读取成功
00401100 push dword ptr ds:[402000] ; /这里就是上面打开的那个文件的句柄
00401106 call <jmp.&kernel32.CloseHandle> ; \关闭前面打开的文件对象
0040110B xor eax, eax
0040110D jmp short 1.00401113 ; 跳到关键的地方去了!
0040110F leave
00401110 retn 10
-----------------------------------------------
下面就是关键了,在命令行下d 4020f3,一边跟踪
一边观察数据的变化
-----------------------------------------------
00401113 xor byte ptr ds:[eax+4020F3], 58 ; 将缓冲区字符串依次与0x58异或
0040111A inc eax
0040111B cmp byte ptr ds:[eax+4020F3], 0 ; 直到遇到00结尾
00401122 jnz short 1.00401113
-----------------------------------------------
处理完后来个比较
-------------------
00401124 push 1.004020F3 ; /字符串地址
00401129 push 1.004020FD ; |字符串地址
0040112E call <jmp.&kernel32.lstrcmp> ; \比较是不是相等
00401133 cmp eax, 0
00401136 je short 1.0040113E ; 相等就成功了
-----------------------------------------------
00401138 jmp short 1.00401158
0040113A leave
0040113B retn 10
0040113E push 1000 ; /Style = MB_OK|MB_SYSTEMMODAL
00401143 push 1.00402026 ; |Title = "OfficialCrackme"
00401148 push 1.004020BF ; |Text = "注册验证成功,恭喜您成功破解了这个程序"
0040114D push 0 ; |hOwner = NULL
0040114F call <jmp.&user32.MessageBoxA> ; \MessageBoxA
00401154 leave
00401155 retn 10
00401158 push 1000 ; /Style = MB_OK|MB_SYSTEMMODAL
0040115D push 1.00402026 ; |Title = "OfficialCrackme"
00401162 push 1.00402083 ; |Text = "革命尚未成功,破解者仍需努力阿。^_^ GOOD LUCK!"
00401167 push 0 ; |hOwner = NULL
00401169 call <jmp.&user32.MessageBoxA> ; \MessageBoxA
0040116E leave
0040116F retn 10
00401172 push 1000 ; /Style = MB_OK|MB_SYSTEMMODAL
00401177 push 1.00402026 ; |Title = "OfficialCrackme"
0040117C push 1.00402036 ; |Text = "中国破解组织BCG(BeNGiN's CrACKiNG GrOUp)Official CrackMe程序 娃娃/[BCG]制作"
00401181 push 0 ; |hOwner = NULL
00401183 call <jmp.&user32.MessageBoxA> ; \MessageBoxA
00401188 leave
00401189 retn 10
======================================================================
总结一下:
只要保证运算后的内存地址004020F3和004020FD指向的字符串相等就能成功,
大家都知道,字符串是以0结尾的.因为运算是简单的与58异或,而0 == 58 xor 58
58就是字符X,所以文件内容可以是如下形式:
*********X*********X
********X*********X*
......
只要X前后的*相等就可以,有很多种组合.
-------------------------------------------
另外如果文件小于10个字符,004020FD指向的总会是个空串,004020F3要构造一个空串
只要内容第一个是X其它任意,总计小于10个字符就行了,
所以还可以是如下形式:
X*********
======================================================================
surge[PYG]
[email protected]
2005-11-29
完. |
|