第五节 脱壳高级篇
5、ASProtect保护
1、ASProtect v0.95保护 2、ASProtect v0.94b保护 3、ASProtect v0.9x
4、ASProtect 1.1x 5、ASProtect 1.2x 6、ASProtect 1.3x
1、ASProtect v0.95保护
教程写作: 看雪
技术指导:D.boy 和RuFeng
写作日期:2000年5月30日
目标程序:ShowDep 4.0 beta 1
程序大小:Showdep.exe 为177K
程序下载:ShowDep 4.0 (http://www.pediy.com/tutorial/chap8/Exercise/Chap8-5-5-1.zip)
使用工具:Softice 4.05; ProcDump 1.6.2 Final; FrogsICE v0.43;Icedump 6.016
首先忠心感谢D.boy 和RuFeng的热心帮助,是在他们的帮助下,我才对PE文件有一定程度的了解。我把从他们那里吸取的经验总结了一篇文章,希望对大家有所帮助。为了使初学者能更好理解这文章,本人尽量写的仔细点。
一、Import表的一些理论知识
在你看这篇文章之前,你应对PE文件的结构有一定了解,否则请先看看PE介绍.
1、现在不少软件脱壳后Import表被损坏或地址发生改变,需要我们手动找到正确的Import表来替换被破坏的Import表,并修正Import表的地址,程序才能正确执行。
程序装载时,需要装载很多函数和DLL文件,这时程序需要判定目标函数的地址并将该函数插补到该执行文件的映像中,所需要的信息都是放在PE文件的Import表,PE文件中的每一个输入函数都明确的列于该表中。
一般来说Import表是存放在程序的.idata块,它一般包含其他外来DLL的函数及数据信息。但也有不少程序的Import表不存在idata块中,给我们判断Import表的地址造成困难,但不要着急,只要了解Import表的结构你就能迅速定位Import表的地址。
2、Import表以一个IMAGE_IMPORT_DESCRIPTOR数组开始。每一个被PE文件隐式连结进来的DLL都有一个IMAGE_IMPORT_DESCRIPTOR。在这个数组中,没有字段指出该结构数组的项数,但它的最后一个单元是NULL,可以由此计数算出该数组的项数。IMAGE_IMPORT_DESCRIPTOR的格式如下:
image_import_descriptors结构:
IMAGE_IMPORT_DESCRIPTOR struct
riginalFirstThunk dd 0 该字段是一个指针数组的RVA偏移。其中每一个指针都指向一IMAGE_IMPORT_BY_NAME结构
TimeDateStamp dd 0 时间及日期标志,在这可以忽略
ForwarderChain dd 0 正向链结索引,在这可以忽略
Name dd 0 以NULL结尾的ASCII字符的RVA地址,该字符串包含输入的DLL名,比如"Kernel32.dll" 或"USER32.DLL" (关键!,我们定位Import表的依据)
FirstThunk dd 0 该字段是在Image_thunk_data联合结构中的RVA偏移。大多数情况下,Image_thunk_data是指IMAGE_IMPORT_BY_NAME结构的指针。如果不是一个指针的话,那它就是该功能在DLL中的序号。
IMAGE_IMPORT_DESCRIPTOR ends
3、为了使大家更好理解,我们以ShowDep 4.0 beta的Import表为例,ShowDep 4.0用 ASProtect 加壳,用prodump 分析,发现没有idata段。 脱壳大师D.boy很成功分析出该软件的Import表:import rav 0042D104,size 00001470 ;Image Base(基址)=00400000。
该软件的Import表的image_import_descriptors结构如下:
-----SHOWDEP!.rdata+1104--------------------------dword-------------PROT---(0)--
0030:0042D104 ①0002D23C ②00000000 ③00000000 ④0002DA8A <............... ^
0030:0042D114 ⑤0002C070 ⑥0002D43C ⑦00000000 ⑦00000000 p...<........... v
(图一)
为了解释方便,我在每个数据前加了序号。上图就是一个典型的Import表开始处的image_import_descriptors结构,Import表就是以这个数组开始的一段连续内存空间,在这里大小是1470的连续空间。各项数据含义如下:
IMAGE_IMPORT_DESCRIPTOR struct
riginalFirstThunk dd 0 ①0002D23C
TimeDateStamp dd 0 ②00000000
ForwarderChain dd 0 ③00000000
Name dd 0 ④0002DA8A(关键!,我们定位Import表的依据)
FirstThunk dd 0 ⑤0002C070
IMAGE_IMPORT_DESCRIPTOR ends
现在我们将image_import_descriptors结构中每项的地址均显示分析一下:
① Name选项(我们定位Import表地址就是以此为依据的)
在这例Name项值为:④0002DA8A
下命令DD 42DA8A (显示内存地址42DA8A的数据,其中42DA8A=④0002DA8A+Image Base(基址))
-----SHOWDEP!.rdata+1A8A--------------------------dword-------------PROT---(0)--
0030:0042DA8A 4E52454B 32334C45 4C4C442E 019A0000 KERNEL32.DLL.... ^
0030:0042DA9A 64616F4C 73727543 0041726F 6F4C01AB LoadCursorA...Lo v
(图二)
想必大家己睁大眼睛了,发现什么有价值的东西?对,就是KERNEL32.DLL!就是我们的突破口。
Import表装载的基本原理是:根据Import表的指示找到外部模块的文件名,再使用Win32 API函数GetModuleHandleA获得该模块在内存中的句柄。如果没在内存中就使用LoadLibraryA API调用装入该模块。随后使用获得的模块句柄调用Win32 API函数GetProcAddress 获得该模块中Import表指定功能的实际地址,加上装入基址,并且填入Import表的FirstThunk所指的IMAGE_IMPORT_BY_NAME结构指针数组中,完成该模块的一个功能的人工装入填写。循环调用函数GetProcAddress以获得其他功能调用的地址,加上装入基址,并填入之,以完成一个外部模块的装入。再循环上述过程对其他模块进行装入。
因此我们可以从函数LoadLibraryA入手,该函数会装入外部模块,我们监视这函数的入口参数是否为KERNEL32.DLL,以此来确定Import表的状况。即确定 image_import_descriptors结构中的name选项。
函数LoadLibrary:
HINSTANCE LoadLibrary(
LPCTSTR lpLibFileName // 执行模块的文件名和地址
);
只要函数LoadLibrary参数的模块名为KERNEL32.DLL,就会出现图二的情况,这时KERNEL32.DLL地址为0042DA8A。因此image_import_descriptors结构中name为0042DA8A—400000=2DA8A,这时利用S命令在内存中查找字条串002DA8A,就可确定import表的地址。
(到这里我们就能确定Import表的地址了,下面几项可帮助我们大家更好理解Import表)
②riginalFirstThunk项
在这里riginalFirstThunk项值为:①0002D23C
下命令DD 42D23C (显示内存地址42D23C的数据,其中42DA8A=①0002D23C+Image Base(基址))
-----SHOWDEP!.rdata+123C--------------------------dword-------------PROT---(0)--
0030:0042D23C 0002D798 0002D7A8 0002D7BE 0002D782 ................ ^
0030:0042D24C 0002D7CC 0002D7E0 0002D7F6 0002D80A ................ ^
0030:0042D25C 0002D81C 0002D830 0002D840 0002D854 ....0...@...T... v
0030:0042D26C 0002D868 0002D87C 0002D890 0002D8A0 h...|........... v
(图三)
图三是一个指针数组,其中每一个指针都指向一IMAGE_IMPORT_BY_NAME结构。
我们以第一个指针0002D798为例,显示它所指的IMAGE_IMPORT_BY_NAME结构.
下命令:dd 42d798(注意:0002D798+Image Base(基址))
-----SHOWDEP!.rdata+1798--------------------------dword-------------PROT---(0)--
0030:0042D798 6547011B 636F4C74 69546C61 0000656D ..GetLocalTime.. ^
0030:0042D7A8 6F430025 6E69746E 65446575 45677562 %.ContinueDebugE ^
0030:0042D7B8 746E6576 022B0000 65736552 65764574 vent..+.ResetEve v
0030:0042D7C8 0000746E 615702CB 6F467469 62654472 nt....WaitForDeb v
(图四)
③FirstThunk项
在这例,FirstThunk项的值为:⑤0002C070
下命令dd 42c070 (注意:0002c070+Image Base(基址)):
-----SHOWDEP!.rdata+0070--------------------------dword-------------PROT---(0)--
0030:0042C070 0002D798 0002D7A8 0002D7BE 0002D782 ................ ^
0030:0042C080 0002D7CC 0002D7E0 0002D7F6 0002D80A ................ ^
0030:0042C090 0002D81C 0002D830 0002D840 0002D854 ....0...@...T... v
0030:0042C0A0 0002D868 0002D87C 0002D890 0002D8A0 h...|........... v
(图五)
图五是一个指针数组(Image_thunk_data联合结构),大多数情况下,Image_thunk_data是指IMAGE_IMPORT_BY_NAME结构的指针。如果不是一个指针的话,那它就是该功能在DLL中的序号。不知你发现没有,图五的数据和图三完全相同,原因就是这个。
二、确定Import表的地址和大小并修正Import表
通过上面的讲解,想必大家对Import表己比较熟悉了吧,现在以脱ShowDep 4.0 beta 1的壳为例,讲解定位Import表的位置和大小的几种方法。
方法一:通过idata来确定Import表的位置
大部分加壳程序的块表中都有.idata这一项,.idata包含其他外来DLL的函数及数据信息,也就是说Import表的起始地址就是.idata的地址。如是这种情况,脱壳就简单多了。
先dump取正确的Import表(假设取名为idata.bin),然后在解压入口点full dump取整个程序(假设取名为dump.exe),用 Procdump打开dump.exe文件, 察看.idata Section. 记下Raw Size和 Raw Offset的值。用HexWorkshop打开dump.exe, 将idata.bin拷贝/粘贴到 dump.exe(粘贴位置为Raw Offset, 大小为Raw Size). 再修正Entry Point和Import表的地址(此值就是.idata的RVA)
具体操作参考后面几节的脱壳教学实例。
方法二:没.idata一项,利用bpx loadlibrarya来判断Import表的位置
由于ShowDep 4.0 beta 1没.idata一项,因此要确定Import表的位置和大小较困难,步骤如下:
①分析ShowDep 4.0 beta 1的文件PE头
运行 Procdump,点击pe-editor按钮,选中ShowDep.exe文件:
Size of image : 000A0000 ; 这个PE文件执行时分配的内存空间。
Image Base : 00400000 ; 基址
②确定Import表的地址
a.先装载Icedump
在这用Icedump 6.016版本,其命令操作形式完全和以前的版本不同。先在Icedump目录里运行相应SOFTICE版本的icedump.exe(我用的SOFTICE是4.05版,因此在win9x/405目录下运行icedump.exe),如Icedump装载成功,Icedump会返回如下信息:
icedump v6.0.1.6 for winice v4.05 loader
icedump unloaded
icedump loaded ←出现这句话表示Icedump装载成功
C:>
(图六)
b.再装载FrogsICE
由于ShowDep能检测到SOFTICE的存在,因此装载Frogsice就可躲过。在我机子里:FrogsICE 1.00 Final和Icedump不能很好兼容工作,因此我将FrogsICE换成版本v0.43,hehe..它们配合的很好。双击FPloader.exe文件即可装载成功。
OK,到此你的SOFTICE的功能己大大加强里。
这时试试运行ShowDep,这时屏幕将蓝屏给你一菜单选项,告知ShowDep发现了SOFTICE,是否欺骗它,这时你按ESC按钮,程序即可正常运行。(注:我的SOFTICE用icepath打过补丁)
c、拦截函数loadlibararya
下命令:bpx loadlibrarya do "dd esp->4"
(注:在TRW2000下实现同样功能的命令是: bpx loadlibrarya do "dd *(esp+4)"
这个命令就是当拦截loadlibararya函数时,显示其入口参数的在内存的值,如:
0137:00710242 PUSH EAX
0137:00710243 CALL [loadlibarary] ;当调用此函数将中断,并显示push参数的值,在这里即:d eax
ok,断点设置好后,运行ShowDep程序,将中断,此时按F5一直到数据窗口显示为:KERNEL32.DLL字符。在我win97系统下,只要按两下F5,即可看到如下情况:
-----SHOWDEP!.rdata+1A8A--------------------------dword-------------PROT---(0)--
0030:0042DA8A 4E52454B 32334C45 4C4C442E 019A0000 KERNEL32.DLL.... ^
0030:0042DA9A 64616F4C 73727543 0041726F 6F4C01AB LoadCursorA...Lo v
(图六)
hehe...看看图六和图三是不是一样啊!其中前面的地址0042DA8A就是关键。
0042DA8A就是image_import_descriptors结构中的name项的值,因为该结构如下:
0030:0042D104 0002D23C 00000000 00000000 0002DA8A <............... ^
0030:0042D114 0002C070 0002D43C 00000000 00000000 p...<........... v
因此这时我要在数据窗口向前查找字符串0002DA8A(0002DA8A=0042DA8A-基址):
下命令:S DS:400000 L FFFFFFFF 8A DA 02 00
(注:在TRW2000下实现同样功能的命令是: S 30:0 L FFFFFFFF 8A DA 02 00)(用上面的好象不行,但愿新版能改进)
结果如下:
-----SHOWDEP!.rdata+1100--------------------------dword-------------PROT---(0)--
013F:0042D100 0042B385 0002D23C 00000000 00000000 ..B.<........... ^
013F:0042D110 0002DA8A 0002C070 0002D43C 00000000 ....p...<....... v
(图七)
仔细比较图七和图一,发现这就是Import表的IMAGE_IMPORT_DESCRIPTOR数组。
如你看不习惯,可再下命令: D 42D110-C 这样就可显示和图一一样的画面了。
这样就可确定Import表的地址是2D104=0042D104—400000(基址)
③确定Import表的大小
现己将Import表的起始地址确定了:RVA=42D104。只要确定Import表的尾部就可计算出其大小,Import表在内存里是连续存放的一段数据,其一般结尾处一段内存空间都是0,在此例,你开始先定位来到Import表的起始处,按ALT+↓向下翻页(或ALT+PageDown),直到看到如下情况:
013F:0042E54A 65530262 766E4574 6E6F7269 746E656D b.SetEnvironment
013F:0042E55A 69726156 656C6261 011D0041 4C746547 VariableA...GetL
013F:0042E56A 6C61636F 666E4965 0000576F 00000000 ocaleInfoW......
013F:0042E57A 00000000 00000000 00000000 00000000 ................ v
013F:0042E58A 00000000 00000000 00000000 00000000 ................ v
(图八)
字符串0000576F就是Import表的最后一项,其后面一位000000的地址为:42e574(其边界就是上面红色的W,如你在SOFTICE不能确定可DUMP后在十六进制工具Hexworkshop很方便知边界地址)
因此Import表的大小=42E574-42D104=1470
④、找入口点
在SOFTICE你会来到如下:
0137:00710B35 MOV EDX,[EAX]
0137:00710B37 MOV EAX,[EBP+08]
0137:00710B3A ADD EDX,[EAX+18]
0137:00710B3D MOV EAX,[EBP+08]
0137:00710B40 MOV EAX,[EAX+1C]
0137:00710B43 CALL 007104C8 ←按F8进去
0137:00710B48 POP EDI
0137:00710B49 POP ESI
0137:00710B4A POP EBX
0137:00710B4B POP ECX
按F8进去来到:
0137:007104C6 8BC0 MOV EAX,EAX
0137:007104C8 89C4 MOV ESP,EAX
0137:007104CA 89D0 MOV EAX,EDX
0137:007104CC 8B1D34567100 MOV EBX,[00715634]
137:007104D2 89041C MOV [EBX+ESP],EAX
0137:007104D5 61 POPAD
0137:007104D6 50 PUSH EAX ←此处EAX=422c3a即入口点的值
0137:007104D7 C3 RET ←返回到入口点
(图九)
此时程序己完全解压准备运行了。记下程序入口点:00422c3a 在dump前,清除所有的断点:bc *. 因此你可在SOFTICE下用命令:
:/dump 400000 A0000 c:\temp\dump.exe
(如你是用Icedump 6.016以前版本用此命令:pagein d 400000 A0000 c:\temp\dump.exe)
⑤修正PE文件头
用 Procdump打开刚建好的 dump.exe文件,点击pe-editor按钮,然后再点击SECTIONS按钮,在每个section点击右键,选中Edit section,把所有的 section 的PSize == VSize offset == RVA (即让物理地址和大小等于虚拟地址和大小)。如你是用Procdump脱的壳,可省去这一步。
在改完所有的sections后,按OK,存盘后,你在资源管理器中刷新一下,就会发现dumped.exe的图标回来了,但还不能运行,你还要修正入口点和import表。
将入口点(Entry Point)改为:00422c3a(记着:00422c3a-imagebase=22c3a)
再点击Directory按钮,将Import Table改为 RVA (2D104 );而其选项Size只要比0大就可;(这程序DUMP后improt并没被破坏,只要把import rav/size 填上就OK了!) 在这例中,Import表的尺寸没用上,但方法要掌握,如碰到Import表损坏的程序,就要替换Import表程了,这时需要Import表的大小了。
然后点击OK,退出Procdump,再运行 dumped.exe ,程序成功运行!
方法三:利用S命令查找字串KERNEL32.DLL来确定Import表的位置
如果软件没.idata项,用方法二bpx loadlibrarya do "dd esp->4"也不能看到KERNEL32.DLL,这种情况就要用S命令来协助了。
先bpx loadlibrarya do "dd esp->4"
中断后,凭经验来判断Import表完全触压时机,一般中断在第一次或第二次(某些情况要几次)Import表就基本解压结束了。这时下命令:S DS:400000 l FFFFFFFF 'KERNEL32.DLL'
会在数据区找到KERNEL32.DLL ,但这不一定是image_import_descriptors结构中对应的KERNEL32.DLL项,这要跟据具体情况来分析了,一般我们要找到的KERNEL32.DLL是在xxx:4xxxxxx的地址形式处。
如不能确定何处是关键的KERNEL32.DLL,只好dump后,用十六进制工具来分析了,这样较直观,打开后查找image_import_descriptors类似结构。
当然Import表确定方法多种,这里将本人常用的几种方法列出供参考!也欢迎你将自己的经验告诉大家,互相提高。
2、ASProtect v0.94b保护
英文原作:r!sc 《Almost Manual Unpacking (using Softice and Icedump)》
原作日期:6th febuary 2000
教程翻译: 看雪
翻译日期:2000年5月26日
声 明: 本文以r!sc的教程为基础,以自己的观点补充调整。
目标程序:aspack.exe . 231,424 . v 2.001
程序下载:AsPack(http://www.pediy.com/tutorial/chap8/Exercise/chap8-5-5-2.zip)
使用工具:Softice 4.05; ProcDump 1.6.2 Final; FrogsICE v0.43;Icedump 6.016
part1 . 理论知识
part2 . 分析原文件的PE头
part3 . 抓取import table
part4 . Dump整个程序并修正文件头
=part1===part1===part1===part1===part1===part1===part1===part1===part1===part1=
理论知识
这种被压缩或加密的PE文件,执行时,在内存中将会完全解压。其中import表在装载中也会被完全解压或解密(—攻击点)。其中抓取import表就很关键了,其具体位置,可用 Procdump分析文件头得到。然后,要跟踪程序完全解压后的跳到程序处的入口点,然后在内存里dump取程序的整个部分。将刚dump取的正确import表用十六进制工具粘贴到完全dump的程序,再 修正文件头,这样程序就可正常运行。
=part2===part2===part2===part2===part2===part2===part2===part2===part2===part2=
分析原文件的PE头
运行 Procdump,点击pe-editor按钮,选中ASPack.exe文件,我们想要得到程序解压后的尺寸,import表的地址和大小...幸运的是这个文件的每个块(section )都存在。
Size of image : 00079000 ; 这个PE文件执行时分配的内存空间。
Image Base : 00400000 ; 基址
.idata ;.idata包含其他外来DLL的函数及数据信息
Virtual Size : 00002000 ; idata在内存的尺寸
Virtual Offset : 00046000 ; idata的地址(+imagebase == 00446000)
.rdata
Virtual Size : 00001000
Virtual Offset : 00049000
import表有可能在idata块或rdata块,到底在哪部分?看看它们的尺寸,我将马压在.idata ...
=part3===part3===part3===part3===part3===part3===part3===part3===part3===part3=
抓取import table
1、先装载Icedump
在这用Icedump 6.016版本,其命令操作形式完全和以前的版本不同。先在Icedump目录里运行相应SOFTICE版本的icedump.exe(我用的SOFTICE是4.05版,因此在win9x/405目录下运行icedump.exe),如Icedump装载成功,Icedump会返回如下信息:
icedump v6.0.1.6 for winice v4.05 loader
icedump unloaded
icedump loaded ←出现这句话表示Icedump装载成功
C:>
2、再装载FrogsICE
由于aspack能检测到SOFTICE的存在,因此装载Frogsice就可躲过。在我机子里:FrogsICE 1.00 Final和Icedump不能很好兼容工作,因此我将FrogsICE换成版本v0.43,hehe..它们配合的很好。双击FPloader.exe文件即可装载成功。
OK,到此你的SOFTICE的功能己大大加强里。
这时试试运行aspack,这时屏幕将蓝屏给你一菜单选项,告知aspack发现了SOFTICE,是否欺骗它,这时你按ESC按钮,程序即可正常运行。
3、 记住我们的第一步是抓取import table,它在内存的446000到449000处,因此程序运行时注意这段内存代码的解压情况。
由于SOFTICE不能LOAD aspack.exe,我们用:bpx loadlibrarya命令来拦断。
loadlibrarya命令解释:如果import表没在内存中就使用LoadLibraryA API调用装入该模块,因此我们可以拦截此函数来观察import表。
:bpx loadlibrarya 然后运行aspack将中断如下:
Break due to BPX KERNEL32!LoadLibraryA
:dd 446000 l 40 (下此命令观察内存446000到449000处的数据)
.
-------SPACK!.idata--------------------dword----------ROT--?(0)--
0030:00446000 ???????? ???????? ???????? ???????? ................
0030:00446010 ???????? ???????? ???????? ???????? ................
0030:00446020 ???????? ???????? ???????? ???????? ................
0030:00446030 ???????? ???????? ???????? ???????? ................
上图是SOFTICE的数据窗口,显示 ??...说明import表在内存中没解压。
再按F5一下,程序将中断如下:(记着:在这例中只能要按一下F5,否则将不能抓取正确的import表)
0030:00446000 00000000 00000000 00000000 0004669C .............f..
0030:00446010 0004612C 00000000 00000000 00000000 ,a..............
0030:00446020 000468B6 000461AC 00000000 00000000 .h...a..........
0030:00446030 00000000 000468D0 000461B4 00000000 .....h...a......
这时446000处不是?? ?? ?? ??,意味着import表己被解压了。
.import表以一个IMAGE_IMPORT_DESCRIPTOR数组开始。 image_import_descriptors数据有5组dwords组成。
image_import_descriptors结构:
①dd offset original_first_thunk
②dd timedatestamp 时间及日期标志
③dd forwardchain 正向链结索引
④dd offset library name以NULL结尾的ASCII字符的RVA地址,该字符串包含输入的DLL名,
比如"Kernel32.dll"或"USER32.DLL"。
⑤dd offset first_thunk 该字段是在Image_thunk_data联合结构中的RVA偏移
其中timedatestamp和forwardchain通常设置为00000000, original first thunk 选项不是必须的.
:dd 446000 l 40
0030:00446000 00000000 00000000 00000000 0004669C .............f..
0030:00446010 0004612C 00000000 00000000 00000000 ,a..............
地址4669c 指向 LibraryName (RVA, 你需要加上基址imagebase+400000)
:db 44669c l 10
0030:0044669C 4B 45 52 4E 45 4C 33 32-2E 44 4C 4C 00 00 00 00 KERNEL32.DLL....
地址612c指向 first_thunk 库。
:dd 44612c l 10
0030:0044612C 000466AA 000466C2 000466DA 000466F2 .f...f...f...f..
这些是以NULL结尾的ASCII字符的RVA地址, . . 466aa 是第一个API函数的地址,466c2是第二个API函数地址...它们以以NULL结尾。
:db 0004466aa l 20
0030:004466AA 00 00 44 65 6C 65 74 65-43 72 69 74 69 63 61 6C ..DeleteCritical
0030:004466BA 53 65 63 74 69 6F 6E 00-00 00 4C 65 61 76 65 43 Section...LeaveC
通过上面的分析可知,这就是原始的.import表,快dump it!!(看看上文的image_import_descriptors地址)
:/dump 446000 2000 c:\aspack.idata.bin
(如你是用Icedump 6.016以前版本用此命令:pagein d 446000 2000 c:\aspack.idata.bin)
为了方便大家对比,特将dump正确的import表放在此下载。
=part4===part4===part4===part4===part4===part4===part4===part4===part4===part4=
Dump整个程序并修正文件头
1、现在我们要找程序的入口点,下命令:bpx loadlibrarya ,然后按14下F5,然后按F10一步一步跟踪来到如下代码:
0137:00C1150E 8B4508 MOV EAX,[EBP+08]
0137:00C11511 8B10 MOV EDX,[EAX] DS:004664FC=00400000
0137:00C11513 8B4508 MOV EAX,[EBP+08]
0137:00C11516 035018 ADD EDX,[EAX+18]
0137:00C11519 8B4508 MOV EAX,[EBP+08]
0137:00C1151C 8B401C MOV EAX,[EAX+1C]
0137:00C1151F E874F9FFFF CALL 00C10E98 ←在此按F8进入
0137:00C11524 5F POP EDI
0137:00C11525 5E POP ESI
0137:00C11526 5B POP EBX
0137:00C11527 59 POP ECX
0137:00C11528 59 POP ECX
0137:00C11529 5D POP EBP
0137:00C1152A C20400 RET 0004
F8进入后来到如下:
0137:00C10E96 8BC0 MOV EAX,EAX
0137:00C10E98 89C4 MOV ESP,EAX
0137:00C10E9A 89D0 MOV EAX,EDX
0137:00C10E9C 8B1D6C66C100 MOV EBX,[00C1666C]
0137:00C10EA2 89041C MOV [EBX+ESP],EAX
0137:00C10EA5 61 POPAD
0137:00C10EA6 50 PUSH EAX ;push 442b98 即为入口点
0137:00C10EA7 C3 RET ;返回到己完全解压的代码处,即入口点处。
0137:00C10EA8 C3 RET
来到入口点:
0167:00442B98 55 PUSH EBP ←此处为入口点
0167:00442B99 8BEC MOV EBP,ESP
0167:00442B9B 83C4F4 ADD ESP,-0C
在0167:00442B98 处就可dump整个内存数据了,此时程序己完全解压准备运行了。记下程序入口点:00442B98
在dump前,清除所有的断点:bc *.
./dump 400000 79000 c:\aspack.dumped.exe
(如你是用Icedump 6.016以前版本用此命令:pagein d 400000 79000 c:\aspack.dumped.exe)
2、替换正确的import表
用Hexworkshop打开aspack.dumped.exe和aspack.idata.bin. Goto到exe文件的46000偏移处,Select Block大小为2000. 拷贝aspack.idata.bin文件的同样大小(2000)的Block,粘贴到exe文件中以替换掉不正确的.idata section,然后存盘。(注意:以上所有数据都是十六进制)
3、修正PE文件头
用 Procdump打开刚建好的 aspack.dumped.exe文件,点击pe-editor按钮,然后再点击SECTIONS按钮,在每个section点击右键,选中Edit section,把所有的 section 的PSize = VSize offset = RVA 。
如:CODE 的PSize=0001E000; VSize=00042000;offset =00000400;RVA=00001000;
改成:PSize = VSize= 00042000;offset = RVA =00001000;
在改完所有的sections后,按OK,存盘后,你在资源管理器中刷新一下,就会发现aspack.dumped.exe的图标回来了,但还不能运行,你还要修正入口点和import表。
将入口点(Entry Point)改为:00042B98(记着:00442B98-imagebase=42B98)
再点击Directory按钮,将Import Table改为 RVA (46000 );而其选项Size只要比0大就可;
然后点击OK,退出Procdump,再运行 aspack.dumped.exe ,程序运行的很甜美!
这时你用W32DASM不能反汇编,你可用 Procdump编辑第一个section characteristics:
将其 c0000060 (data, writable)改为: 60000040 (code, executable)或 e0000060 (code, data, etc etc)
注:大家抓取屏幕可在Icedump 6.016中,用:/Screendump抓取。
不加参数命令:/Screendump 选取模式,重复执行,会在0、1、2、3、4五种模式下转换。
模式1(默认)是以文本方式存盘,模式2是以HTML文件存盘。其它的请参考其readme.
模式选好后,就可用命令: /SCREENDUMP [路径]文件名 抓取整个SOFTICE的屏幕。
3、ASProtect v0.9x保护
Advanced Zip Password Recovery 3.0的脱壳
教程写作: 冰毒
作者信箱: break_ice@hotmail.com
写作日期: 2000年3月25日
版权声明: 本文没有版权,允许任意转贴和修改. 但如果只引用文中部分内容时,请最好注明原文出处,以表示对一位Cracker同行的劳动的尊重.
使用工具:
TRW2000 1.03
ProcDump 1.6.2
Hexworkshop 3.02
下载:Advanced Zip Password Recovery 3.0(http://www.pediy.com/tutorial/chap8/Exercise/chap8-5-5-3.zip)
比起其Beta版来,AZPR 3.0正式版的保护更为加强. 1. 对Softice的多处Check,用FrogsICE不能完全骗过; 2. CRC的校验; 3. 动态地址(好象是这个名吧?); 4.对Loader的防范,这回用Process Patch不行了.
用Softice跟踪它会是一种痛苦 (当然完全可以用Softice,只是你要了解程序的Anti-debugger技巧,在关键的Check后改变跳转方向). 这次祭出我们中国人的骄傲TRW2000来对付它.
先用Procdump的PE Editor查看一下程序的.idata section记下数值. Virtual size=2000, Virtual offset=21000. 另外,记下程序的Image Base: 400000.
1. 运行TRW, Load程序. 程序中断在入口处. 但接下来无论是否BPX设断只要G继续运行程序,便会出错. 下Faults off, G, OK程序退出.
2. 试BPM 421000 (.idata的offset), 再Load程序. G, 程序可以被正常中断, COOL!
3. G,当程序第三次(? 记不清了. 原则是d 421000显示的data区见到XXXX0200 000000字样)中断时,BD*,F10直到下面的语句
*********************************
注意: 程序每次Load时Offset都不一样,你的机器中的XXXX:YYYYYYYY肯定和下面的不同. 下Code on指令,这样才好参照下面的代码. 另外,下面所摘的几段代码是引用高手tiamath的.因为我不清楚在TRW下如何dump屏幕 (谁能指教一下:);而用ICEDump的pagein n命令来Dump Softice的屏幕,我的机器会死机. :(
*********************************
0167:004F34CD 50 PUSH EAX
0167:004F34CE B890274F00 MOV EAX,004F2790
0167:004F34D3 50 PUSH EAX
0167:004F34D4 B8A4274F00 MOV EAX,004F27A4
0167:004F34D9 50 PUSH EAX
0167:004F34DA B8A0284F00 MOV EAX,004F28A0
0167:004F34DF 50 PUSH EAX
0167:004F34E0 B8AC274F00 MOV EAX,004F27AC
0167:004F34E5 50 PUSH EAX
0167:004F34E6 B8646C4E00 MOV EAX,004E6C64
0167:004F34EB 50 PUSH EAX
0167:004F34EC 8B4508 MOV EAX,[EBP+08]
0167:004F34EF 8D4824 LEA ECX,[EAX+24]
0167:004F34F2 8B4508 MOV EAX,[EBP+08]
0167:004F34F5 8B500C MOV EDX,[EAX+0C]
0167:004F34F8 8B4508 MOV EAX,[EBP+08]
0167:004F34FB 8B4008 MOV EAX,[EAX+08]
0167:004F34FE E899F4FFFF CALL 004F299C
0167:004F3503 33C0 XOR EAX,EAX <--在这里Dump .idata
下指令 W 421000 L 2000 azprdata.bin
OK. 再往下,直到
0167:004F3637 8D4818 LEA ECX,[EAX+18]
0167:004F363A 8B4508 MOV EAX,[EBP+08]
0167:004F363D 8B10 MOV EDX,[EAX]
0167:004F363F 8B4508 MOV EAX,[EBP+08]
0167:004F3642 8B401C MOV EAX,[EAX+1C]
0167:004F3645 E8EAF6FFFF CALL 004F2D34 <--F8进入
0167:004F364A 5F POP EDI
0167:004F364B 5E POP ESI
到了
0167:004F2D72 E9148B1DA8 JMP A86CB88B
0167:004F2D77 8E4F00 MOV CS,[EDI+00]
0167:004F2D7A EB01 JMP 004F2D7D
0167:004F2D7C EB89 JMP 004F2D07
0167:004F2D7E 041C ADD AL,1C
0167:004F2D80 EB02 JMP 004F2D84
0167:004F2D82 EBE8 JMP 004F2D6C
0167:004F2D84 61 POPAD
0167:004F2D85 EB01 JMP 004F2D88
0167:004F2D87 E850EB02E9 CALL E95218DC
0167:004F2D8C 17 POP SS
0167:004F2D8D E802000000 CALL 004F2D94
0167:004F2D92 E91758C35E JMP 5F1285AE
0167:004F2D97 5B POP EBX
0167:004F2D98 59 POP ECX
此时小心地跟踪,碰到JMP时按F8而不要按F10
直到显示变成
0167:004F2D72 E9148B1DA8 JMP A86CB88B
0167:004F2D77 8E4F00 MOV CS,[EDI+00]
0167:004F2D7A EB01 JMP 004F2D7D
0167:004F2D7C EB89 JMP 004F2D07
0167:004F2D7E 041C ADD AL,1C
0167:004F2D80 EB02 JMP 004F2D84
0167:004F2D82 EBE8 JMP 004F2D6C
0167:004F2D84 61 POPAD
0167:004F2D85 EB01 JMP 004F2D88
0167:004F2D87 E850EB02E9 CALL E95218DC
0167:004F2D8C 17 POP SS
0167:004F2D8D E802000000 CALL 004F2D94
0167:004F2D92 E91758C35E JMP 5F1285AE
0167:004F2D94 58 POP EAX <-- 光标位于此行时, EAX=401000
0167:004F2D95 C3 RET <--这里
下Suspend指令. 回到Windows. 用ProcDump来Dump(full)脱壳的程序,得到azprdump.exe. 你也可以用TRW的PEDUMP命令来得到脱壳程序,但我个人的经验很容易死机,所以我宁愿用ProcDump来做.
4. 用PE Editor修改程序的Entry Point为1000. 并查看脱壳后程序的.idata section. 此时Raw size=1670, Raw offset=1FC00. 修改Directory中Import Table的RVA=21000,SIZE=1670.
5. 用Hexworkshop打开azprdump.exe和azprdata.bin. Goto到exe文件的1FC00偏移处,Select Block大小为1670. 拷贝.bin文件的同样大小(1670)的Block,粘贴到exe文件中以替换掉不正确的.idata section.
现在,再试着运行程序,应该可以正常运行了. 如果程序出错,再做一件事: 把 .bss section的raw size值改为00000000 (高手tiamath的建议).
有了脱壳的程序,大家应该会Patch它成为注册版了吧. 只需改一个字节.
结语: 用本文所描述的方法,可以对绝大多数Asprotect+Aspack保护的程序进行成功的脱壳. 大家读完这篇教程,不妨找几个程序开刀. 比方说,The Bat! 1.39现在不应该再难住大家了.
好了,这次就到这儿了,下回见.
致谢:
感谢SV, Hobgoblin, tiamath. 没有他们的帮助,我不可能做到这一步.
第一节 概念介绍
何为注册机?注册机就是针对某一软件,通过一定算法算出注册码的程序。我们写注册机时,一般都要了解注册码的算法(这当然是通过跟踪调试了解的),之后用汇编语言或其它高级语言来把算法还原。这样大家可根据自己的要求输入注册码,如根据自己的姓名,公司的名称注册。
目前共享软件有两种注册方式:
一 种是交费后,作者给寄有全部功能的 Register软件,原来的Shareware根本没有某些功能;
第二种交费后, 作者给你个注册码(Register Number),注册后功能就无限制了 。 共享软件注册前后基本相同 , 只是功能受限制 ,或者使用时间受限制 ,或者经常出现要求注册的画面 , 等等 。
我们平时所接触的共享软件是第二种,通过算出注册码或打补丁使该软件有注册后的功能。
软件的破解也分两种:
一是、补丁( patches ), 这些小程序的功能是用来改变某种软件内某些特定的部位, 因此它们的作用通常只限于某一个软件的版本。请勿使用针对不同版本所设计的 patch,必须注意所使用软件版本的版本号与 patch 是否相同 。倘若使用不当,将导至错误信息,会破坏程序,严重时也有可能死机!
二是、序列号 (serial number) 和注册码 (key generator) 就显的安全多了。有时候旧版的序号亦适用于新出的版本,就算不能用也毫无伤害。只有在极少数的情况下软件作者会设下某些陷阱,当使用者输入黑名单上的序号后 , 软件会自动销毁而无法使用。
通过补丁和注册机可以大大方便用户的注册,就是目前有不少的程序,它的注册码都与硬件有关,就是在每一台机上安装都有一个机器码,要把这个机器码E-MAIL给作者, 作者把收到的机器码用注册程序算出注册码后再寄回给用户,这样做使得软件的防复制方面加强了,但造成了不少用户的麻烦,因为只要用户一重装系统或升级主板 ,就要重新去注册了。对于这种程序,一般初学者只能在内存中找到自己机器的注册码,但这种注册码到了其它的机器上又不能用了。所以要求大家能自己写出注册机来。
而有的软件注册码计算很复杂,或只是试用版,到期就停止使用,根本无法输入注册码。对这类软件只能通过改动原程序代码指令,但如何让大家很方便地解除限制,当然你可把改动的字节告诉大家,用二进制编辑工具修改,但很不方便。所以大家有必要自己制作补丁程序,只要用户运行该补丁程序,让它帮你改动指定的代码,就可解除原软件限制,是不是很方便。
1、文件补丁制作
今天我们接触补丁制作工具是CodeFusion,界面制作也不错,它有以下功能:
1、可以自动比较补丁前后的差别
2、可以对字节逐个补丁,也可以使用普通和模板两种查找、替换;
3、补丁前后的文件尺寸可以不同;
4、可以对单个文件补丁,也可以处理多个不同盘、不同目录、甚至名字并不匹配的多个文件;
5、界面文字和链接等完全定制;
6、可以使用内置和外部的压缩器;也可以不压缩自行修改窗体;
为了使初学者能更快掌握这一工具使用,我就把一补丁最常用的制作过作写下来。
首先建立一个临时目录C:\TEMP(只是为了下面讲述的方便罢了).并在其下建立两个子目录,分别为C:\TEMP\1\以及 C:\TEMP\2\. 以网络吸血鬼NET VAMPIRE 3.2为例: 将没有CRACK的主程序VAMPIRE.EXE拷到C:\TEMP\1\目录下. 将已经CRACK的主程序VAMPIRE.EXE拷到C:\TEMP\2\目录下.
(图一)是用CodeFusion制成的补丁程序运行的界面。
(图一)
界面还是不错的,只要你用用CodeFusion,你就发现它很容易上手。
第一步、运行CodeFusion,界面如图二:
(图二)
图一和图二中的数字1、2、3、4、5是彼此对应的,要得到(图一)结果只需在(图二)中键入你自己的说明即可。你自己定制好界面可以存盘,存盘名是*.cfp,以后你只要打开该文件,就可出现所要的界面。很简单,自己摸索一下就能掌握。
第二步、定制好界面后,可以按预览按钮(就是上面的眼睛图标)看看界面自己是否满意,满意后按下一步。
(图三)
在图三中,按(1)处的绿色的十字,以添加原文件(在这里是吸血鬼的原主文件),按1后出现左边的一窗口,按2选择吸血鬼的原主文,选好按Ok即可。
第三步、这一步按图四的1处的绿色十字,出现如下结果:
(图四)
按上图中的2处是文件比较。第3处是Byte-path offset,在原文件中指定的地址处打字节补丁。第4处是Find &Replace,在原文件查找替换字节。第五处是Truncate offset,从指定地址处切断原文件。3,4,5的用处我在这里就不写了,大家可自己试试。
第四步、用鼠标按图四中的2处(File Compare)出现图五,选择己被crack的文件,进行比较,在这里是C:\TEMP\2\目录下, 已经CRACK的主程序VAMPIRE.EXE。
(图五)
在1 处选择C:\TEMP\2\目录下, 已经CRACK的主程序VAMPIRE.EXE。下一步按第2处的compare,进行两文件的比较,比较结束后按Ok,再按下一步。
第五步,这是最后一步,出现图六。
(图六)
在这界面上的各项选项就以默认值为主,它们都是些压缩选项,压缩补丁以保护你的版权。最后一步按1处(Make win32 Executable),选择路径、文件名,生成你的补丁。好了你可以把这补丁散发给大家,真可谓,辛苦你一人,方便千万人啊!
该软件的其它功能,大家自己再摸索一下,是不是很直观好用。
2、内存补丁制作
R!SC'sPatcher 使用
简介
RPP.EXE 是内存动态补丁制作软件。它通过脚本命令创建 win32 文件,以此文件装载程序,装载过程中等待软件解压或解除其自身保护后,然后按脚本要求修补内存中的指令,以使软件能够按我们要求运行。
如 ACDSEE3.0 是用 ASPACK 压缩软件,你 crack 时发现在内存地址 433FEA 处把 6A00 改成 EB17 就可成功,但你不可能直接修改压缩过的 ACDSEE.EXE 文件;这里就可用 RPP.EXE 按我们要求生成一 LOAD.EXE 文件,首先运行 LOAD.EXE ,它自动装载 ACDSEE.EXE, 等其自解压完成后,然后修改内存 433FEA 地址为 EB17, 这样 ACDSEE.EXE 就可按我们要求运行了,不过我不赞成用此法对付 ACDSEE.EXE ,因为 ACDSEE.EXE 运行有两种界面,其中 VIEW 界面用此法不太灵。
RPP.EXE 还可很方便对付 NAG (一些提示、警告窗口的软件),如用 NEOLITE 2.0 Y 压缩过的软件运行之前弹出来的那种窗口,当然也有专门除掉 NAG 的工具。
用法
在资源管理器中双击 rpp.exe 文件,它弹出一菜单,你选择事先编好的脚本文件,然后按 OK 。
或在 WINDOWS 下的 DOS 窗口下用命令方式“ rpp.exe <script.rpp> ”,其中 script.rpp 为脚本命令文件。
如你的输出文件己存在,它将覆盖。在命令方式下,脚本文件可是任何文件名和扩展名;但在对话窗口操作方式下,文件名必须为 *.rpp
脚 本 命 令
-------------------
';' 注释符号 , 跟着的只是些说明 , 不会执行的 , 直到下一行 .
'T=' 表示对内存的检测次数, T=1000: 意味着对内存检测 1000 次,在放弃之前,告诉你的应用程序是
不正确的版本。
注意:在脚本文件里,默认值 T=8000 。
'F=' 需要补丁的文件名
'O=' 生成的补丁文件名 , 如你没指定文件名,默认为 LOAD.EXE
'P=' 如何在内存补丁 , 格式:内存地址 / 原码 / 补码
具体看看脚本的例子
'R:' 把前面需要补的全部补好后 , 再继续 , 可以看看 azpr243.rpp 这个例子
':' 每一行都要以冒号结尾 , 相当于回车
'
5、ASProtect保护
1、ASProtect v0.95保护 2、ASProtect v0.94b保护 3、ASProtect v0.9x
4、ASProtect 1.1x 5、ASProtect 1.2x 6、ASProtect 1.3x
1、ASProtect v0.95保护
教程写作: 看雪
技术指导:D.boy 和RuFeng
写作日期:2000年5月30日
目标程序:ShowDep 4.0 beta 1
程序大小:Showdep.exe 为177K
程序下载:ShowDep 4.0 (http://www.pediy.com/tutorial/chap8/Exercise/Chap8-5-5-1.zip)
使用工具:Softice 4.05; ProcDump 1.6.2 Final; FrogsICE v0.43;Icedump 6.016
首先忠心感谢D.boy 和RuFeng的热心帮助,是在他们的帮助下,我才对PE文件有一定程度的了解。我把从他们那里吸取的经验总结了一篇文章,希望对大家有所帮助。为了使初学者能更好理解这文章,本人尽量写的仔细点。
一、Import表的一些理论知识
在你看这篇文章之前,你应对PE文件的结构有一定了解,否则请先看看PE介绍.
1、现在不少软件脱壳后Import表被损坏或地址发生改变,需要我们手动找到正确的Import表来替换被破坏的Import表,并修正Import表的地址,程序才能正确执行。
程序装载时,需要装载很多函数和DLL文件,这时程序需要判定目标函数的地址并将该函数插补到该执行文件的映像中,所需要的信息都是放在PE文件的Import表,PE文件中的每一个输入函数都明确的列于该表中。
一般来说Import表是存放在程序的.idata块,它一般包含其他外来DLL的函数及数据信息。但也有不少程序的Import表不存在idata块中,给我们判断Import表的地址造成困难,但不要着急,只要了解Import表的结构你就能迅速定位Import表的地址。
2、Import表以一个IMAGE_IMPORT_DESCRIPTOR数组开始。每一个被PE文件隐式连结进来的DLL都有一个IMAGE_IMPORT_DESCRIPTOR。在这个数组中,没有字段指出该结构数组的项数,但它的最后一个单元是NULL,可以由此计数算出该数组的项数。IMAGE_IMPORT_DESCRIPTOR的格式如下:
image_import_descriptors结构:
IMAGE_IMPORT_DESCRIPTOR struct
riginalFirstThunk dd 0 该字段是一个指针数组的RVA偏移。其中每一个指针都指向一IMAGE_IMPORT_BY_NAME结构
TimeDateStamp dd 0 时间及日期标志,在这可以忽略
ForwarderChain dd 0 正向链结索引,在这可以忽略
Name dd 0 以NULL结尾的ASCII字符的RVA地址,该字符串包含输入的DLL名,比如"Kernel32.dll" 或"USER32.DLL" (关键!,我们定位Import表的依据)
FirstThunk dd 0 该字段是在Image_thunk_data联合结构中的RVA偏移。大多数情况下,Image_thunk_data是指IMAGE_IMPORT_BY_NAME结构的指针。如果不是一个指针的话,那它就是该功能在DLL中的序号。
IMAGE_IMPORT_DESCRIPTOR ends
3、为了使大家更好理解,我们以ShowDep 4.0 beta的Import表为例,ShowDep 4.0用 ASProtect 加壳,用prodump 分析,发现没有idata段。 脱壳大师D.boy很成功分析出该软件的Import表:import rav 0042D104,size 00001470 ;Image Base(基址)=00400000。
该软件的Import表的image_import_descriptors结构如下:
-----SHOWDEP!.rdata+1104--------------------------dword-------------PROT---(0)--
0030:0042D104 ①0002D23C ②00000000 ③00000000 ④0002DA8A <............... ^
0030:0042D114 ⑤0002C070 ⑥0002D43C ⑦00000000 ⑦00000000 p...<........... v
(图一)
为了解释方便,我在每个数据前加了序号。上图就是一个典型的Import表开始处的image_import_descriptors结构,Import表就是以这个数组开始的一段连续内存空间,在这里大小是1470的连续空间。各项数据含义如下:
IMAGE_IMPORT_DESCRIPTOR struct
riginalFirstThunk dd 0 ①0002D23C
TimeDateStamp dd 0 ②00000000
ForwarderChain dd 0 ③00000000
Name dd 0 ④0002DA8A(关键!,我们定位Import表的依据)
FirstThunk dd 0 ⑤0002C070
IMAGE_IMPORT_DESCRIPTOR ends
现在我们将image_import_descriptors结构中每项的地址均显示分析一下:
① Name选项(我们定位Import表地址就是以此为依据的)
在这例Name项值为:④0002DA8A
下命令DD 42DA8A (显示内存地址42DA8A的数据,其中42DA8A=④0002DA8A+Image Base(基址))
-----SHOWDEP!.rdata+1A8A--------------------------dword-------------PROT---(0)--
0030:0042DA8A 4E52454B 32334C45 4C4C442E 019A0000 KERNEL32.DLL.... ^
0030:0042DA9A 64616F4C 73727543 0041726F 6F4C01AB LoadCursorA...Lo v
(图二)
想必大家己睁大眼睛了,发现什么有价值的东西?对,就是KERNEL32.DLL!就是我们的突破口。
Import表装载的基本原理是:根据Import表的指示找到外部模块的文件名,再使用Win32 API函数GetModuleHandleA获得该模块在内存中的句柄。如果没在内存中就使用LoadLibraryA API调用装入该模块。随后使用获得的模块句柄调用Win32 API函数GetProcAddress 获得该模块中Import表指定功能的实际地址,加上装入基址,并且填入Import表的FirstThunk所指的IMAGE_IMPORT_BY_NAME结构指针数组中,完成该模块的一个功能的人工装入填写。循环调用函数GetProcAddress以获得其他功能调用的地址,加上装入基址,并填入之,以完成一个外部模块的装入。再循环上述过程对其他模块进行装入。
因此我们可以从函数LoadLibraryA入手,该函数会装入外部模块,我们监视这函数的入口参数是否为KERNEL32.DLL,以此来确定Import表的状况。即确定 image_import_descriptors结构中的name选项。
函数LoadLibrary:
HINSTANCE LoadLibrary(
LPCTSTR lpLibFileName // 执行模块的文件名和地址
);
只要函数LoadLibrary参数的模块名为KERNEL32.DLL,就会出现图二的情况,这时KERNEL32.DLL地址为0042DA8A。因此image_import_descriptors结构中name为0042DA8A—400000=2DA8A,这时利用S命令在内存中查找字条串002DA8A,就可确定import表的地址。
(到这里我们就能确定Import表的地址了,下面几项可帮助我们大家更好理解Import表)
②riginalFirstThunk项
在这里riginalFirstThunk项值为:①0002D23C
下命令DD 42D23C (显示内存地址42D23C的数据,其中42DA8A=①0002D23C+Image Base(基址))
-----SHOWDEP!.rdata+123C--------------------------dword-------------PROT---(0)--
0030:0042D23C 0002D798 0002D7A8 0002D7BE 0002D782 ................ ^
0030:0042D24C 0002D7CC 0002D7E0 0002D7F6 0002D80A ................ ^
0030:0042D25C 0002D81C 0002D830 0002D840 0002D854 ....0...@...T... v
0030:0042D26C 0002D868 0002D87C 0002D890 0002D8A0 h...|........... v
(图三)
图三是一个指针数组,其中每一个指针都指向一IMAGE_IMPORT_BY_NAME结构。
我们以第一个指针0002D798为例,显示它所指的IMAGE_IMPORT_BY_NAME结构.
下命令:dd 42d798(注意:0002D798+Image Base(基址))
-----SHOWDEP!.rdata+1798--------------------------dword-------------PROT---(0)--
0030:0042D798 6547011B 636F4C74 69546C61 0000656D ..GetLocalTime.. ^
0030:0042D7A8 6F430025 6E69746E 65446575 45677562 %.ContinueDebugE ^
0030:0042D7B8 746E6576 022B0000 65736552 65764574 vent..+.ResetEve v
0030:0042D7C8 0000746E 615702CB 6F467469 62654472 nt....WaitForDeb v
(图四)
③FirstThunk项
在这例,FirstThunk项的值为:⑤0002C070
下命令dd 42c070 (注意:0002c070+Image Base(基址)):
-----SHOWDEP!.rdata+0070--------------------------dword-------------PROT---(0)--
0030:0042C070 0002D798 0002D7A8 0002D7BE 0002D782 ................ ^
0030:0042C080 0002D7CC 0002D7E0 0002D7F6 0002D80A ................ ^
0030:0042C090 0002D81C 0002D830 0002D840 0002D854 ....0...@...T... v
0030:0042C0A0 0002D868 0002D87C 0002D890 0002D8A0 h...|........... v
(图五)
图五是一个指针数组(Image_thunk_data联合结构),大多数情况下,Image_thunk_data是指IMAGE_IMPORT_BY_NAME结构的指针。如果不是一个指针的话,那它就是该功能在DLL中的序号。不知你发现没有,图五的数据和图三完全相同,原因就是这个。
二、确定Import表的地址和大小并修正Import表
通过上面的讲解,想必大家对Import表己比较熟悉了吧,现在以脱ShowDep 4.0 beta 1的壳为例,讲解定位Import表的位置和大小的几种方法。
方法一:通过idata来确定Import表的位置
大部分加壳程序的块表中都有.idata这一项,.idata包含其他外来DLL的函数及数据信息,也就是说Import表的起始地址就是.idata的地址。如是这种情况,脱壳就简单多了。
先dump取正确的Import表(假设取名为idata.bin),然后在解压入口点full dump取整个程序(假设取名为dump.exe),用 Procdump打开dump.exe文件, 察看.idata Section. 记下Raw Size和 Raw Offset的值。用HexWorkshop打开dump.exe, 将idata.bin拷贝/粘贴到 dump.exe(粘贴位置为Raw Offset, 大小为Raw Size). 再修正Entry Point和Import表的地址(此值就是.idata的RVA)
具体操作参考后面几节的脱壳教学实例。
方法二:没.idata一项,利用bpx loadlibrarya来判断Import表的位置
由于ShowDep 4.0 beta 1没.idata一项,因此要确定Import表的位置和大小较困难,步骤如下:
①分析ShowDep 4.0 beta 1的文件PE头
运行 Procdump,点击pe-editor按钮,选中ShowDep.exe文件:
Size of image : 000A0000 ; 这个PE文件执行时分配的内存空间。
Image Base : 00400000 ; 基址
②确定Import表的地址
a.先装载Icedump
在这用Icedump 6.016版本,其命令操作形式完全和以前的版本不同。先在Icedump目录里运行相应SOFTICE版本的icedump.exe(我用的SOFTICE是4.05版,因此在win9x/405目录下运行icedump.exe),如Icedump装载成功,Icedump会返回如下信息:
icedump v6.0.1.6 for winice v4.05 loader
icedump unloaded
icedump loaded ←出现这句话表示Icedump装载成功
C:>
(图六)
b.再装载FrogsICE
由于ShowDep能检测到SOFTICE的存在,因此装载Frogsice就可躲过。在我机子里:FrogsICE 1.00 Final和Icedump不能很好兼容工作,因此我将FrogsICE换成版本v0.43,hehe..它们配合的很好。双击FPloader.exe文件即可装载成功。
OK,到此你的SOFTICE的功能己大大加强里。
这时试试运行ShowDep,这时屏幕将蓝屏给你一菜单选项,告知ShowDep发现了SOFTICE,是否欺骗它,这时你按ESC按钮,程序即可正常运行。(注:我的SOFTICE用icepath打过补丁)
c、拦截函数loadlibararya
下命令:bpx loadlibrarya do "dd esp->4"
(注:在TRW2000下实现同样功能的命令是: bpx loadlibrarya do "dd *(esp+4)"
这个命令就是当拦截loadlibararya函数时,显示其入口参数的在内存的值,如:
0137:00710242 PUSH EAX
0137:00710243 CALL [loadlibarary] ;当调用此函数将中断,并显示push参数的值,在这里即:d eax
ok,断点设置好后,运行ShowDep程序,将中断,此时按F5一直到数据窗口显示为:KERNEL32.DLL字符。在我win97系统下,只要按两下F5,即可看到如下情况:
-----SHOWDEP!.rdata+1A8A--------------------------dword-------------PROT---(0)--
0030:0042DA8A 4E52454B 32334C45 4C4C442E 019A0000 KERNEL32.DLL.... ^
0030:0042DA9A 64616F4C 73727543 0041726F 6F4C01AB LoadCursorA...Lo v
(图六)
hehe...看看图六和图三是不是一样啊!其中前面的地址0042DA8A就是关键。
0042DA8A就是image_import_descriptors结构中的name项的值,因为该结构如下:
0030:0042D104 0002D23C 00000000 00000000 0002DA8A <............... ^
0030:0042D114 0002C070 0002D43C 00000000 00000000 p...<........... v
因此这时我要在数据窗口向前查找字符串0002DA8A(0002DA8A=0042DA8A-基址):
下命令:S DS:400000 L FFFFFFFF 8A DA 02 00
(注:在TRW2000下实现同样功能的命令是: S 30:0 L FFFFFFFF 8A DA 02 00)(用上面的好象不行,但愿新版能改进)
结果如下:
-----SHOWDEP!.rdata+1100--------------------------dword-------------PROT---(0)--
013F:0042D100 0042B385 0002D23C 00000000 00000000 ..B.<........... ^
013F:0042D110 0002DA8A 0002C070 0002D43C 00000000 ....p...<....... v
(图七)
仔细比较图七和图一,发现这就是Import表的IMAGE_IMPORT_DESCRIPTOR数组。
如你看不习惯,可再下命令: D 42D110-C 这样就可显示和图一一样的画面了。
这样就可确定Import表的地址是2D104=0042D104—400000(基址)
③确定Import表的大小
现己将Import表的起始地址确定了:RVA=42D104。只要确定Import表的尾部就可计算出其大小,Import表在内存里是连续存放的一段数据,其一般结尾处一段内存空间都是0,在此例,你开始先定位来到Import表的起始处,按ALT+↓向下翻页(或ALT+PageDown),直到看到如下情况:
013F:0042E54A 65530262 766E4574 6E6F7269 746E656D b.SetEnvironment
013F:0042E55A 69726156 656C6261 011D0041 4C746547 VariableA...GetL
013F:0042E56A 6C61636F 666E4965 0000576F 00000000 ocaleInfoW......
013F:0042E57A 00000000 00000000 00000000 00000000 ................ v
013F:0042E58A 00000000 00000000 00000000 00000000 ................ v
(图八)
字符串0000576F就是Import表的最后一项,其后面一位000000的地址为:42e574(其边界就是上面红色的W,如你在SOFTICE不能确定可DUMP后在十六进制工具Hexworkshop很方便知边界地址)
因此Import表的大小=42E574-42D104=1470
④、找入口点
在SOFTICE你会来到如下:
0137:00710B35 MOV EDX,[EAX]
0137:00710B37 MOV EAX,[EBP+08]
0137:00710B3A ADD EDX,[EAX+18]
0137:00710B3D MOV EAX,[EBP+08]
0137:00710B40 MOV EAX,[EAX+1C]
0137:00710B43 CALL 007104C8 ←按F8进去
0137:00710B48 POP EDI
0137:00710B49 POP ESI
0137:00710B4A POP EBX
0137:00710B4B POP ECX
按F8进去来到:
0137:007104C6 8BC0 MOV EAX,EAX
0137:007104C8 89C4 MOV ESP,EAX
0137:007104CA 89D0 MOV EAX,EDX
0137:007104CC 8B1D34567100 MOV EBX,[00715634]
137:007104D2 89041C MOV [EBX+ESP],EAX
0137:007104D5 61 POPAD
0137:007104D6 50 PUSH EAX ←此处EAX=422c3a即入口点的值
0137:007104D7 C3 RET ←返回到入口点
(图九)
此时程序己完全解压准备运行了。记下程序入口点:00422c3a 在dump前,清除所有的断点:bc *. 因此你可在SOFTICE下用命令:
:/dump 400000 A0000 c:\temp\dump.exe
(如你是用Icedump 6.016以前版本用此命令:pagein d 400000 A0000 c:\temp\dump.exe)
⑤修正PE文件头
用 Procdump打开刚建好的 dump.exe文件,点击pe-editor按钮,然后再点击SECTIONS按钮,在每个section点击右键,选中Edit section,把所有的 section 的PSize == VSize offset == RVA (即让物理地址和大小等于虚拟地址和大小)。如你是用Procdump脱的壳,可省去这一步。
在改完所有的sections后,按OK,存盘后,你在资源管理器中刷新一下,就会发现dumped.exe的图标回来了,但还不能运行,你还要修正入口点和import表。
将入口点(Entry Point)改为:00422c3a(记着:00422c3a-imagebase=22c3a)
再点击Directory按钮,将Import Table改为 RVA (2D104 );而其选项Size只要比0大就可;(这程序DUMP后improt并没被破坏,只要把import rav/size 填上就OK了!) 在这例中,Import表的尺寸没用上,但方法要掌握,如碰到Import表损坏的程序,就要替换Import表程了,这时需要Import表的大小了。
然后点击OK,退出Procdump,再运行 dumped.exe ,程序成功运行!
方法三:利用S命令查找字串KERNEL32.DLL来确定Import表的位置
如果软件没.idata项,用方法二bpx loadlibrarya do "dd esp->4"也不能看到KERNEL32.DLL,这种情况就要用S命令来协助了。
先bpx loadlibrarya do "dd esp->4"
中断后,凭经验来判断Import表完全触压时机,一般中断在第一次或第二次(某些情况要几次)Import表就基本解压结束了。这时下命令:S DS:400000 l FFFFFFFF 'KERNEL32.DLL'
会在数据区找到KERNEL32.DLL ,但这不一定是image_import_descriptors结构中对应的KERNEL32.DLL项,这要跟据具体情况来分析了,一般我们要找到的KERNEL32.DLL是在xxx:4xxxxxx的地址形式处。
如不能确定何处是关键的KERNEL32.DLL,只好dump后,用十六进制工具来分析了,这样较直观,打开后查找image_import_descriptors类似结构。
当然Import表确定方法多种,这里将本人常用的几种方法列出供参考!也欢迎你将自己的经验告诉大家,互相提高。
2、ASProtect v0.94b保护
英文原作:r!sc 《Almost Manual Unpacking (using Softice and Icedump)》
原作日期:6th febuary 2000
教程翻译: 看雪
翻译日期:2000年5月26日
声 明: 本文以r!sc的教程为基础,以自己的观点补充调整。
目标程序:aspack.exe . 231,424 . v 2.001
程序下载:AsPack(http://www.pediy.com/tutorial/chap8/Exercise/chap8-5-5-2.zip)
使用工具:Softice 4.05; ProcDump 1.6.2 Final; FrogsICE v0.43;Icedump 6.016
part1 . 理论知识
part2 . 分析原文件的PE头
part3 . 抓取import table
part4 . Dump整个程序并修正文件头
=part1===part1===part1===part1===part1===part1===part1===part1===part1===part1=
理论知识
这种被压缩或加密的PE文件,执行时,在内存中将会完全解压。其中import表在装载中也会被完全解压或解密(—攻击点)。其中抓取import表就很关键了,其具体位置,可用 Procdump分析文件头得到。然后,要跟踪程序完全解压后的跳到程序处的入口点,然后在内存里dump取程序的整个部分。将刚dump取的正确import表用十六进制工具粘贴到完全dump的程序,再 修正文件头,这样程序就可正常运行。
=part2===part2===part2===part2===part2===part2===part2===part2===part2===part2=
分析原文件的PE头
运行 Procdump,点击pe-editor按钮,选中ASPack.exe文件,我们想要得到程序解压后的尺寸,import表的地址和大小...幸运的是这个文件的每个块(section )都存在。
Size of image : 00079000 ; 这个PE文件执行时分配的内存空间。
Image Base : 00400000 ; 基址
.idata ;.idata包含其他外来DLL的函数及数据信息
Virtual Size : 00002000 ; idata在内存的尺寸
Virtual Offset : 00046000 ; idata的地址(+imagebase == 00446000)
.rdata
Virtual Size : 00001000
Virtual Offset : 00049000
import表有可能在idata块或rdata块,到底在哪部分?看看它们的尺寸,我将马压在.idata ...
=part3===part3===part3===part3===part3===part3===part3===part3===part3===part3=
抓取import table
1、先装载Icedump
在这用Icedump 6.016版本,其命令操作形式完全和以前的版本不同。先在Icedump目录里运行相应SOFTICE版本的icedump.exe(我用的SOFTICE是4.05版,因此在win9x/405目录下运行icedump.exe),如Icedump装载成功,Icedump会返回如下信息:
icedump v6.0.1.6 for winice v4.05 loader
icedump unloaded
icedump loaded ←出现这句话表示Icedump装载成功
C:>
2、再装载FrogsICE
由于aspack能检测到SOFTICE的存在,因此装载Frogsice就可躲过。在我机子里:FrogsICE 1.00 Final和Icedump不能很好兼容工作,因此我将FrogsICE换成版本v0.43,hehe..它们配合的很好。双击FPloader.exe文件即可装载成功。
OK,到此你的SOFTICE的功能己大大加强里。
这时试试运行aspack,这时屏幕将蓝屏给你一菜单选项,告知aspack发现了SOFTICE,是否欺骗它,这时你按ESC按钮,程序即可正常运行。
3、 记住我们的第一步是抓取import table,它在内存的446000到449000处,因此程序运行时注意这段内存代码的解压情况。
由于SOFTICE不能LOAD aspack.exe,我们用:bpx loadlibrarya命令来拦断。
loadlibrarya命令解释:如果import表没在内存中就使用LoadLibraryA API调用装入该模块,因此我们可以拦截此函数来观察import表。
:bpx loadlibrarya 然后运行aspack将中断如下:
Break due to BPX KERNEL32!LoadLibraryA
:dd 446000 l 40 (下此命令观察内存446000到449000处的数据)
.
-------SPACK!.idata--------------------dword----------ROT--?(0)--
0030:00446000 ???????? ???????? ???????? ???????? ................
0030:00446010 ???????? ???????? ???????? ???????? ................
0030:00446020 ???????? ???????? ???????? ???????? ................
0030:00446030 ???????? ???????? ???????? ???????? ................
上图是SOFTICE的数据窗口,显示 ??...说明import表在内存中没解压。
再按F5一下,程序将中断如下:(记着:在这例中只能要按一下F5,否则将不能抓取正确的import表)
0030:00446000 00000000 00000000 00000000 0004669C .............f..
0030:00446010 0004612C 00000000 00000000 00000000 ,a..............
0030:00446020 000468B6 000461AC 00000000 00000000 .h...a..........
0030:00446030 00000000 000468D0 000461B4 00000000 .....h...a......
这时446000处不是?? ?? ?? ??,意味着import表己被解压了。
.import表以一个IMAGE_IMPORT_DESCRIPTOR数组开始。 image_import_descriptors数据有5组dwords组成。
image_import_descriptors结构:
①dd offset original_first_thunk
②dd timedatestamp 时间及日期标志
③dd forwardchain 正向链结索引
④dd offset library name以NULL结尾的ASCII字符的RVA地址,该字符串包含输入的DLL名,
比如"Kernel32.dll"或"USER32.DLL"。
⑤dd offset first_thunk 该字段是在Image_thunk_data联合结构中的RVA偏移
其中timedatestamp和forwardchain通常设置为00000000, original first thunk 选项不是必须的.
:dd 446000 l 40
0030:00446000 00000000 00000000 00000000 0004669C .............f..
0030:00446010 0004612C 00000000 00000000 00000000 ,a..............
地址4669c 指向 LibraryName (RVA, 你需要加上基址imagebase+400000)
:db 44669c l 10
0030:0044669C 4B 45 52 4E 45 4C 33 32-2E 44 4C 4C 00 00 00 00 KERNEL32.DLL....
地址612c指向 first_thunk 库。
:dd 44612c l 10
0030:0044612C 000466AA 000466C2 000466DA 000466F2 .f...f...f...f..
这些是以NULL结尾的ASCII字符的RVA地址, . . 466aa 是第一个API函数的地址,466c2是第二个API函数地址...它们以以NULL结尾。
:db 0004466aa l 20
0030:004466AA 00 00 44 65 6C 65 74 65-43 72 69 74 69 63 61 6C ..DeleteCritical
0030:004466BA 53 65 63 74 69 6F 6E 00-00 00 4C 65 61 76 65 43 Section...LeaveC
通过上面的分析可知,这就是原始的.import表,快dump it!!(看看上文的image_import_descriptors地址)
:/dump 446000 2000 c:\aspack.idata.bin
(如你是用Icedump 6.016以前版本用此命令:pagein d 446000 2000 c:\aspack.idata.bin)
为了方便大家对比,特将dump正确的import表放在此下载。
=part4===part4===part4===part4===part4===part4===part4===part4===part4===part4=
Dump整个程序并修正文件头
1、现在我们要找程序的入口点,下命令:bpx loadlibrarya ,然后按14下F5,然后按F10一步一步跟踪来到如下代码:
0137:00C1150E 8B4508 MOV EAX,[EBP+08]
0137:00C11511 8B10 MOV EDX,[EAX] DS:004664FC=00400000
0137:00C11513 8B4508 MOV EAX,[EBP+08]
0137:00C11516 035018 ADD EDX,[EAX+18]
0137:00C11519 8B4508 MOV EAX,[EBP+08]
0137:00C1151C 8B401C MOV EAX,[EAX+1C]
0137:00C1151F E874F9FFFF CALL 00C10E98 ←在此按F8进入
0137:00C11524 5F POP EDI
0137:00C11525 5E POP ESI
0137:00C11526 5B POP EBX
0137:00C11527 59 POP ECX
0137:00C11528 59 POP ECX
0137:00C11529 5D POP EBP
0137:00C1152A C20400 RET 0004
F8进入后来到如下:
0137:00C10E96 8BC0 MOV EAX,EAX
0137:00C10E98 89C4 MOV ESP,EAX
0137:00C10E9A 89D0 MOV EAX,EDX
0137:00C10E9C 8B1D6C66C100 MOV EBX,[00C1666C]
0137:00C10EA2 89041C MOV [EBX+ESP],EAX
0137:00C10EA5 61 POPAD
0137:00C10EA6 50 PUSH EAX ;push 442b98 即为入口点
0137:00C10EA7 C3 RET ;返回到己完全解压的代码处,即入口点处。
0137:00C10EA8 C3 RET
来到入口点:
0167:00442B98 55 PUSH EBP ←此处为入口点
0167:00442B99 8BEC MOV EBP,ESP
0167:00442B9B 83C4F4 ADD ESP,-0C
在0167:00442B98 处就可dump整个内存数据了,此时程序己完全解压准备运行了。记下程序入口点:00442B98
在dump前,清除所有的断点:bc *.
./dump 400000 79000 c:\aspack.dumped.exe
(如你是用Icedump 6.016以前版本用此命令:pagein d 400000 79000 c:\aspack.dumped.exe)
2、替换正确的import表
用Hexworkshop打开aspack.dumped.exe和aspack.idata.bin. Goto到exe文件的46000偏移处,Select Block大小为2000. 拷贝aspack.idata.bin文件的同样大小(2000)的Block,粘贴到exe文件中以替换掉不正确的.idata section,然后存盘。(注意:以上所有数据都是十六进制)
3、修正PE文件头
用 Procdump打开刚建好的 aspack.dumped.exe文件,点击pe-editor按钮,然后再点击SECTIONS按钮,在每个section点击右键,选中Edit section,把所有的 section 的PSize = VSize offset = RVA 。
如:CODE 的PSize=0001E000; VSize=00042000;offset =00000400;RVA=00001000;
改成:PSize = VSize= 00042000;offset = RVA =00001000;
在改完所有的sections后,按OK,存盘后,你在资源管理器中刷新一下,就会发现aspack.dumped.exe的图标回来了,但还不能运行,你还要修正入口点和import表。
将入口点(Entry Point)改为:00042B98(记着:00442B98-imagebase=42B98)
再点击Directory按钮,将Import Table改为 RVA (46000 );而其选项Size只要比0大就可;
然后点击OK,退出Procdump,再运行 aspack.dumped.exe ,程序运行的很甜美!
这时你用W32DASM不能反汇编,你可用 Procdump编辑第一个section characteristics:
将其 c0000060 (data, writable)改为: 60000040 (code, executable)或 e0000060 (code, data, etc etc)
注:大家抓取屏幕可在Icedump 6.016中,用:/Screendump抓取。
不加参数命令:/Screendump 选取模式,重复执行,会在0、1、2、3、4五种模式下转换。
模式1(默认)是以文本方式存盘,模式2是以HTML文件存盘。其它的请参考其readme.
模式选好后,就可用命令: /SCREENDUMP [路径]文件名 抓取整个SOFTICE的屏幕。
3、ASProtect v0.9x保护
Advanced Zip Password Recovery 3.0的脱壳
教程写作: 冰毒
作者信箱: break_ice@hotmail.com
写作日期: 2000年3月25日
版权声明: 本文没有版权,允许任意转贴和修改. 但如果只引用文中部分内容时,请最好注明原文出处,以表示对一位Cracker同行的劳动的尊重.
使用工具:
TRW2000 1.03
ProcDump 1.6.2
Hexworkshop 3.02
下载:Advanced Zip Password Recovery 3.0(http://www.pediy.com/tutorial/chap8/Exercise/chap8-5-5-3.zip)
比起其Beta版来,AZPR 3.0正式版的保护更为加强. 1. 对Softice的多处Check,用FrogsICE不能完全骗过; 2. CRC的校验; 3. 动态地址(好象是这个名吧?); 4.对Loader的防范,这回用Process Patch不行了.
用Softice跟踪它会是一种痛苦 (当然完全可以用Softice,只是你要了解程序的Anti-debugger技巧,在关键的Check后改变跳转方向). 这次祭出我们中国人的骄傲TRW2000来对付它.
先用Procdump的PE Editor查看一下程序的.idata section记下数值. Virtual size=2000, Virtual offset=21000. 另外,记下程序的Image Base: 400000.
1. 运行TRW, Load程序. 程序中断在入口处. 但接下来无论是否BPX设断只要G继续运行程序,便会出错. 下Faults off, G, OK程序退出.
2. 试BPM 421000 (.idata的offset), 再Load程序. G, 程序可以被正常中断, COOL!
3. G,当程序第三次(? 记不清了. 原则是d 421000显示的data区见到XXXX0200 000000字样)中断时,BD*,F10直到下面的语句
*********************************
注意: 程序每次Load时Offset都不一样,你的机器中的XXXX:YYYYYYYY肯定和下面的不同. 下Code on指令,这样才好参照下面的代码. 另外,下面所摘的几段代码是引用高手tiamath的.因为我不清楚在TRW下如何dump屏幕 (谁能指教一下:);而用ICEDump的pagein n命令来Dump Softice的屏幕,我的机器会死机. :(
*********************************
0167:004F34CD 50 PUSH EAX
0167:004F34CE B890274F00 MOV EAX,004F2790
0167:004F34D3 50 PUSH EAX
0167:004F34D4 B8A4274F00 MOV EAX,004F27A4
0167:004F34D9 50 PUSH EAX
0167:004F34DA B8A0284F00 MOV EAX,004F28A0
0167:004F34DF 50 PUSH EAX
0167:004F34E0 B8AC274F00 MOV EAX,004F27AC
0167:004F34E5 50 PUSH EAX
0167:004F34E6 B8646C4E00 MOV EAX,004E6C64
0167:004F34EB 50 PUSH EAX
0167:004F34EC 8B4508 MOV EAX,[EBP+08]
0167:004F34EF 8D4824 LEA ECX,[EAX+24]
0167:004F34F2 8B4508 MOV EAX,[EBP+08]
0167:004F34F5 8B500C MOV EDX,[EAX+0C]
0167:004F34F8 8B4508 MOV EAX,[EBP+08]
0167:004F34FB 8B4008 MOV EAX,[EAX+08]
0167:004F34FE E899F4FFFF CALL 004F299C
0167:004F3503 33C0 XOR EAX,EAX <--在这里Dump .idata
下指令 W 421000 L 2000 azprdata.bin
OK. 再往下,直到
0167:004F3637 8D4818 LEA ECX,[EAX+18]
0167:004F363A 8B4508 MOV EAX,[EBP+08]
0167:004F363D 8B10 MOV EDX,[EAX]
0167:004F363F 8B4508 MOV EAX,[EBP+08]
0167:004F3642 8B401C MOV EAX,[EAX+1C]
0167:004F3645 E8EAF6FFFF CALL 004F2D34 <--F8进入
0167:004F364A 5F POP EDI
0167:004F364B 5E POP ESI
到了
0167:004F2D72 E9148B1DA8 JMP A86CB88B
0167:004F2D77 8E4F00 MOV CS,[EDI+00]
0167:004F2D7A EB01 JMP 004F2D7D
0167:004F2D7C EB89 JMP 004F2D07
0167:004F2D7E 041C ADD AL,1C
0167:004F2D80 EB02 JMP 004F2D84
0167:004F2D82 EBE8 JMP 004F2D6C
0167:004F2D84 61 POPAD
0167:004F2D85 EB01 JMP 004F2D88
0167:004F2D87 E850EB02E9 CALL E95218DC
0167:004F2D8C 17 POP SS
0167:004F2D8D E802000000 CALL 004F2D94
0167:004F2D92 E91758C35E JMP 5F1285AE
0167:004F2D97 5B POP EBX
0167:004F2D98 59 POP ECX
此时小心地跟踪,碰到JMP时按F8而不要按F10
直到显示变成
0167:004F2D72 E9148B1DA8 JMP A86CB88B
0167:004F2D77 8E4F00 MOV CS,[EDI+00]
0167:004F2D7A EB01 JMP 004F2D7D
0167:004F2D7C EB89 JMP 004F2D07
0167:004F2D7E 041C ADD AL,1C
0167:004F2D80 EB02 JMP 004F2D84
0167:004F2D82 EBE8 JMP 004F2D6C
0167:004F2D84 61 POPAD
0167:004F2D85 EB01 JMP 004F2D88
0167:004F2D87 E850EB02E9 CALL E95218DC
0167:004F2D8C 17 POP SS
0167:004F2D8D E802000000 CALL 004F2D94
0167:004F2D92 E91758C35E JMP 5F1285AE
0167:004F2D94 58 POP EAX <-- 光标位于此行时, EAX=401000
0167:004F2D95 C3 RET <--这里
下Suspend指令. 回到Windows. 用ProcDump来Dump(full)脱壳的程序,得到azprdump.exe. 你也可以用TRW的PEDUMP命令来得到脱壳程序,但我个人的经验很容易死机,所以我宁愿用ProcDump来做.
4. 用PE Editor修改程序的Entry Point为1000. 并查看脱壳后程序的.idata section. 此时Raw size=1670, Raw offset=1FC00. 修改Directory中Import Table的RVA=21000,SIZE=1670.
5. 用Hexworkshop打开azprdump.exe和azprdata.bin. Goto到exe文件的1FC00偏移处,Select Block大小为1670. 拷贝.bin文件的同样大小(1670)的Block,粘贴到exe文件中以替换掉不正确的.idata section.
现在,再试着运行程序,应该可以正常运行了. 如果程序出错,再做一件事: 把 .bss section的raw size值改为00000000 (高手tiamath的建议).
有了脱壳的程序,大家应该会Patch它成为注册版了吧. 只需改一个字节.
结语: 用本文所描述的方法,可以对绝大多数Asprotect+Aspack保护的程序进行成功的脱壳. 大家读完这篇教程,不妨找几个程序开刀. 比方说,The Bat! 1.39现在不应该再难住大家了.
好了,这次就到这儿了,下回见.
致谢:
感谢SV, Hobgoblin, tiamath. 没有他们的帮助,我不可能做到这一步.
第一节 概念介绍
何为注册机?注册机就是针对某一软件,通过一定算法算出注册码的程序。我们写注册机时,一般都要了解注册码的算法(这当然是通过跟踪调试了解的),之后用汇编语言或其它高级语言来把算法还原。这样大家可根据自己的要求输入注册码,如根据自己的姓名,公司的名称注册。
目前共享软件有两种注册方式:
一 种是交费后,作者给寄有全部功能的 Register软件,原来的Shareware根本没有某些功能;
第二种交费后, 作者给你个注册码(Register Number),注册后功能就无限制了 。 共享软件注册前后基本相同 , 只是功能受限制 ,或者使用时间受限制 ,或者经常出现要求注册的画面 , 等等 。
我们平时所接触的共享软件是第二种,通过算出注册码或打补丁使该软件有注册后的功能。
软件的破解也分两种:
一是、补丁( patches ), 这些小程序的功能是用来改变某种软件内某些特定的部位, 因此它们的作用通常只限于某一个软件的版本。请勿使用针对不同版本所设计的 patch,必须注意所使用软件版本的版本号与 patch 是否相同 。倘若使用不当,将导至错误信息,会破坏程序,严重时也有可能死机!
二是、序列号 (serial number) 和注册码 (key generator) 就显的安全多了。有时候旧版的序号亦适用于新出的版本,就算不能用也毫无伤害。只有在极少数的情况下软件作者会设下某些陷阱,当使用者输入黑名单上的序号后 , 软件会自动销毁而无法使用。
通过补丁和注册机可以大大方便用户的注册,就是目前有不少的程序,它的注册码都与硬件有关,就是在每一台机上安装都有一个机器码,要把这个机器码E-MAIL给作者, 作者把收到的机器码用注册程序算出注册码后再寄回给用户,这样做使得软件的防复制方面加强了,但造成了不少用户的麻烦,因为只要用户一重装系统或升级主板 ,就要重新去注册了。对于这种程序,一般初学者只能在内存中找到自己机器的注册码,但这种注册码到了其它的机器上又不能用了。所以要求大家能自己写出注册机来。
而有的软件注册码计算很复杂,或只是试用版,到期就停止使用,根本无法输入注册码。对这类软件只能通过改动原程序代码指令,但如何让大家很方便地解除限制,当然你可把改动的字节告诉大家,用二进制编辑工具修改,但很不方便。所以大家有必要自己制作补丁程序,只要用户运行该补丁程序,让它帮你改动指定的代码,就可解除原软件限制,是不是很方便。
1、文件补丁制作
今天我们接触补丁制作工具是CodeFusion,界面制作也不错,它有以下功能:
1、可以自动比较补丁前后的差别
2、可以对字节逐个补丁,也可以使用普通和模板两种查找、替换;
3、补丁前后的文件尺寸可以不同;
4、可以对单个文件补丁,也可以处理多个不同盘、不同目录、甚至名字并不匹配的多个文件;
5、界面文字和链接等完全定制;
6、可以使用内置和外部的压缩器;也可以不压缩自行修改窗体;
为了使初学者能更快掌握这一工具使用,我就把一补丁最常用的制作过作写下来。
首先建立一个临时目录C:\TEMP(只是为了下面讲述的方便罢了).并在其下建立两个子目录,分别为C:\TEMP\1\以及 C:\TEMP\2\. 以网络吸血鬼NET VAMPIRE 3.2为例: 将没有CRACK的主程序VAMPIRE.EXE拷到C:\TEMP\1\目录下. 将已经CRACK的主程序VAMPIRE.EXE拷到C:\TEMP\2\目录下.
(图一)是用CodeFusion制成的补丁程序运行的界面。
(图一)
界面还是不错的,只要你用用CodeFusion,你就发现它很容易上手。
第一步、运行CodeFusion,界面如图二:
(图二)
图一和图二中的数字1、2、3、4、5是彼此对应的,要得到(图一)结果只需在(图二)中键入你自己的说明即可。你自己定制好界面可以存盘,存盘名是*.cfp,以后你只要打开该文件,就可出现所要的界面。很简单,自己摸索一下就能掌握。
第二步、定制好界面后,可以按预览按钮(就是上面的眼睛图标)看看界面自己是否满意,满意后按下一步。
(图三)
在图三中,按(1)处的绿色的十字,以添加原文件(在这里是吸血鬼的原主文件),按1后出现左边的一窗口,按2选择吸血鬼的原主文,选好按Ok即可。
第三步、这一步按图四的1处的绿色十字,出现如下结果:
(图四)
按上图中的2处是文件比较。第3处是Byte-path offset,在原文件中指定的地址处打字节补丁。第4处是Find &Replace,在原文件查找替换字节。第五处是Truncate offset,从指定地址处切断原文件。3,4,5的用处我在这里就不写了,大家可自己试试。
第四步、用鼠标按图四中的2处(File Compare)出现图五,选择己被crack的文件,进行比较,在这里是C:\TEMP\2\目录下, 已经CRACK的主程序VAMPIRE.EXE。
(图五)
在1 处选择C:\TEMP\2\目录下, 已经CRACK的主程序VAMPIRE.EXE。下一步按第2处的compare,进行两文件的比较,比较结束后按Ok,再按下一步。
第五步,这是最后一步,出现图六。
(图六)
在这界面上的各项选项就以默认值为主,它们都是些压缩选项,压缩补丁以保护你的版权。最后一步按1处(Make win32 Executable),选择路径、文件名,生成你的补丁。好了你可以把这补丁散发给大家,真可谓,辛苦你一人,方便千万人啊!
该软件的其它功能,大家自己再摸索一下,是不是很直观好用。
2、内存补丁制作
R!SC'sPatcher 使用
简介
RPP.EXE 是内存动态补丁制作软件。它通过脚本命令创建 win32 文件,以此文件装载程序,装载过程中等待软件解压或解除其自身保护后,然后按脚本要求修补内存中的指令,以使软件能够按我们要求运行。
如 ACDSEE3.0 是用 ASPACK 压缩软件,你 crack 时发现在内存地址 433FEA 处把 6A00 改成 EB17 就可成功,但你不可能直接修改压缩过的 ACDSEE.EXE 文件;这里就可用 RPP.EXE 按我们要求生成一 LOAD.EXE 文件,首先运行 LOAD.EXE ,它自动装载 ACDSEE.EXE, 等其自解压完成后,然后修改内存 433FEA 地址为 EB17, 这样 ACDSEE.EXE 就可按我们要求运行了,不过我不赞成用此法对付 ACDSEE.EXE ,因为 ACDSEE.EXE 运行有两种界面,其中 VIEW 界面用此法不太灵。
RPP.EXE 还可很方便对付 NAG (一些提示、警告窗口的软件),如用 NEOLITE 2.0 Y 压缩过的软件运行之前弹出来的那种窗口,当然也有专门除掉 NAG 的工具。
用法
在资源管理器中双击 rpp.exe 文件,它弹出一菜单,你选择事先编好的脚本文件,然后按 OK 。
或在 WINDOWS 下的 DOS 窗口下用命令方式“ rpp.exe <script.rpp> ”,其中 script.rpp 为脚本命令文件。
如你的输出文件己存在,它将覆盖。在命令方式下,脚本文件可是任何文件名和扩展名;但在对话窗口操作方式下,文件名必须为 *.rpp
脚 本 命 令
-------------------
';' 注释符号 , 跟着的只是些说明 , 不会执行的 , 直到下一行 .
'T=' 表示对内存的检测次数, T=1000: 意味着对内存检测 1000 次,在放弃之前,告诉你的应用程序是
不正确的版本。
注意:在脚本文件里,默认值 T=8000 。
'F=' 需要补丁的文件名
'O=' 生成的补丁文件名 , 如你没指定文件名,默认为 LOAD.EXE
'P=' 如何在内存补丁 , 格式:内存地址 / 原码 / 补码
具体看看脚本的例子
'R:' 把前面需要补的全部补好后 , 再继续 , 可以看看 azpr243.rpp 这个例子
':' 每一行都要以冒号结尾 , 相当于回车
'
回复Comments
作者:
{commentrecontent}