破解

      关于创作者 2004-12-11 19:50
第五节 脱壳高级篇

 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 这个例子

':' 每一行都要以冒号结尾 , 相当于回车

'
标签集:TAGS:
回复Comments() 点击Count()
脚本结束标志


所有数字采用 16 进制


内存地址和原码都符合才会进行补丁 , 字节间请用逗号分开。脚本文件不能大于 40K, 被补的字节有限为 1f0h 字节,被处理的原文件不小于 30h 字节。



脚本例子


;script.rpp

T=1000: ; 对内存尝试 1000 次补丁 , 不行则放弃 , 如果不设默认为 8000

F=test.exe: ; 要补丁的程序

P=40101D/74,60/74,00: ; 将命令 jz xx 改为 jz next instruction


P=4024A6/46,52,45,45,20/52,21,53,43,00: ; 将字符 'FREE ' 替换成 'R!SC'


$ ; 结束


具体的脚本范例大家可参考其自带的 Scripts.zip 。




一些问题

下面是一有趣的试验,写一脚本文件,输入输出名一样,产生一执行文件,该文件将不断装载其自身

最后导致 windows 崩溃,你只好重新启动了。


'P=401000/68/B8:'

'F=fun.exe:'

'O=fun.exe:', 然后运行 fun.exe 不一会你只好重新启动微机了 :)

1、CrackCode2000使用介绍

以前我们写注册机时,一般都要了解程式的算法,之后用汇编语言或 C 语言来把算法还原,这样做一个注册机一般都有要花不少的时间,而且要对汇编语言和编程有比较高的要求,所以对于初学者来说,是一件很难的事情,对于不少的初学者 ,有时他们能在内存中找到注册码,但却没有能力写出注册机来,这大大削弱了他 们的破解积极性,但还有更可恶的事,就是目前有不少的程式,它的注册码都与硬 件有关,就是在每一台机上安装都有一个机身码,要把这个机身码 E-MAIL 给作者,作者把收到的机身码用注册程式算出注册码后再寄回给用户,这样做使得软件的防 复制方面加强了,但造成了不少用户的麻烦,因为只要用户一重装系统或升级主板 ,就要重新去注册了。对于这种程式,一般初学者只能在内存中找到自己机器的注 册码,但这种注册码到了其它的机器上又不能用了,而自己又没有办法写出注册机来,为了解决这方面的问题,我写了一个小软件,它可以从另一进程内存中取出注 册码来,显示出来,而不需要你去了解注册程式的算法,但它的应用面是很有限的, 只能对付符合以下条件的软件:

一、必须在内存中或在寄存器中可以找到正确的注册码;

二、被取注册码的软件不能反跟踪程式;

三、被取注册码的软件的比较部分程式是静态的存在的;

四、注册码比较程式只作比较注册码使用。


好了,讲了这么多,不如来个例子说明一下如何使用它吧!哦对了,大家还不知那 个东西是什么呢?它叫 CrackCode2000 啊!

以下是一个软件的注册码比较程式,大家不要问我怎么样得到了,大家只要听下去 就可以了。


015F:004149D2 8A06 MOV AL,[ESI] 这里放你的输入的注册码

015F:004149D4 84C0 TEST AL,AL

015F:004149D6 740D JZ 004149E5

015F:004149D8 8A11 MOV DL,[ECX] 这里放正确的注册码

015F:004149DA 41 INC ECX

015F:004149DB 46 INC ESI

015F:004149DC 3AC2 CMP AL,DL

015F:004149DE 751F JNZ 004149FF

015F:004149E0 803900 CMP BYTE PTR [ECX],00

015F:004149E3 75ED JNZ 004149D2

015F:004149E5 803900 CMP BYTE PTR [ECX],00

015F:004149E8 7515 JNZ 004149FF

015F:004149EA 803E00 CMP BYTE PTR [ESI],00

015F:004149ED 7510 JNZ 004149FF

015F:004149EF B801000000 MOV EAX,00000001 最后正确就把 EAX=1

015F:004149F4 5F POP EDI

015F:004149F5 5E POP ESI

015F:004149F6 5D POP EBP

015F:004149F7 5B POP EBX

015F:004149F8 81C460030000 ADD ESP,00000360

015F:004149FE C3 RET


好了,大家在 Winsoftice 下以下的命令可以看到:

:d esi

0167:0041F1F8 34 38 34 38 34 38 34 38-34 38 34 38 00 00 00 00 484848484848....

0167:0041F208 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

0167:0041F218 04 0D 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

0167:0041F228 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

0167:0041F238 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

0167:0041F248 00 00 00 00 00 00 00 00-00 C0 00 00 0A 04 00 00 ................

0167:0041F258 04 00 00 00 0A 00 00 00-01 00 00 00 90 03 CA 00 ................

0167:0041F268 00 00 00 00 D0 03 CA 00-00 00 00 00 00 00 00 00 ................

:d ecx

0167:0066F3E4 58 51 4D 50 5A 43 57 58-54 45 52 53 00 01 08 00 XQMPZCWXTERS....

0167:0066F3F4 9A EE 8B 17 E3 A4 00 00-10 00 E0 2C 00 00 00 01 ...........,....

0167:0066F404 00 03 00 00 00 00 00 00-80 01 AB 01 8D 01 9C 01 ................

0167:0066F414 00 00 AB 01 8D 01 00 00-80 01 9C 01 8C 01 A4 01 ................

0167:0066F424 8D 01 9C 01 8C 01 A4 01-8D 01 04 00 00 00 B6 0C ................

0167:0066F434 00 A9 52 FB 83 2A D1 78-21 88 73 DA A2 0B F0 59 ..R..*.x!.s....Y

0167:0066F444 65 CC 37 9E E6 4F B4 1D-44 ED 16 BF C7 6E 95 3C e.7..O..D....n.<

0167:0066F454 ED 44 BF 16 6E C7 3C 95-CC 65 9E 37 4F E6 1D B4 .D..n.<..e.7O...


见到了吧!那个 XQMPZCWXTERS 就是正确的注册码了,但如果我们用以前的方法来写注册机, 就要去分析前面的程式了,但我们今次不是用这种方法来制作,而是用 CRACKCODE 来做,这样大家可以见到用 CRACKCODE 来做注册机实在是太方便了,太简单了! 好,我们为 CRACKCODE 来写一个 INI 文件吧!

第一种写法(这是一种不提倡的写法!):

内存直接寻址的方法:

[Options]

CommandLine=Axplorer.exe 这是被取注册码的 EXE 文件名

Mode=0 采用模式 0 读取注册码

First_Break_Address=4149D2 程式的中断地址,它和 ICE 中见到的是一样的

First_Break_Address_Code=8A 中断程式的 1 Byte 代码,这个 8A 就是 015F:004149D2 的 8A

First_Break_Address_Code_Lenth=2 中断行代码的长度(单位: byte )

Save_Code_Address=66F3E4 存放注册码的内存地址


第二种写法(这种值得推荐!)

寄存器间接寻址的方法:

[Options]

CommandLine=test.exe 这是被取注册码的 EXE 文件名(化名)

Mode=0 取用模式 0 读取注册码

First_Break_Address=4149D2 程式的中断地址,它和 ICE 中见到的是一样的

First_Break_Address_Code=8A 中断程式的 1 Byte 代码,这个 8A 就是 015F:004149D2 的 8A

First_Break_Address_Code_Lenth=2 中断行代码的长度(单位: byte )

Save_Code_Address=ECX 存放注册码的内存地址,这个 ECX 是从 015F:004149D8 来

的,大家见到了吧!这和上前的方法相差就只是这句,

当你使用了这句,就不怕软件是否被压缩过了。

注意:

目前 CRACKCODE2000 对所中断地址的代码长度已经是无有要求的,只要把长度写进 INI

就可以了!

015F:004149D2 8A06 MOV AL,[ESI] 本行代码为 2 Bytes

015F:004149DA 41 INC ECX 本行代码为 1 Byte

015F:004149E0 803900 CMP BYTE PTR [ECX],00 本行代码为 3 Bytes


生成后保存为 CRACKCODE.INI 文件,把 CRACKCODE.EXE 和 CRACKCODE.INI 一起 copy 到被注册的 软件的安装目录下,运行 CRACKCODE.EXE 。哦!被取注册码的软件也运行了,到注册的窗口去,输入一个名字,随便输入注册码,按确定,哦!跳出一个显示窗来,里面出现了你想要的正确注册码了。是不是觉得很神奇呢!来试一试你就知道了!

好了,下面我再为大家显示 CrackCode2000 的另一种工作模式吧!

下面是 Decompile Winhelp 的注册机的写法,这个软件是加了壳的软件,我们来看一看加了壳 的软件对于 CrackCode2000 是否有影响 , 现在我把它注册码的部分那出来给大家看一看吧!而且它的注册码和硬件是有关系的,所以要想别人可以注册,就一定要写出注册机了!
下面就是它的比较程式了:

015f:0040e4a9 8d45c0 lea eax,[ebp-40]

015f:0040e4ac 8d55ac lea edx,[ebp-54]

015f:0040e4af 8a08 mov cl,[eax] ds:eax 放的是你输入的注册码

015f:0040e4b1 3a0a cmp cl,[edx] ds:edx 放的是正确的注册码

015f:0040e4b3 7516 jnz 0040e4cb

015f:0040e4b5 84c9 test cl,cl

015f:0040e4b7 746e jz 0040e527

015f:0040e4b9 8a4801 mov cl,[eax+01]

015f:0040e4bc 3a4a01 cmp cl,[edx+01]

015f:0040e4bf 750a jnz 0040e4cb

015f:0040e4c1 83c002 add eax,02

015f:0040e4c4 83c202 add edx,02

015f:0040e4c7 84c9 test cl,cl

015f:0040e4c9 75e4 jnz 0040e4af

015f:0040e4cb 745a jz 0040e527


在 winsoftice 里下以下命令可以见到:

:d ds:eax

0167:006DF33C 34 34 34 34 34 34 34 34-34 34 34 34 34 34 00 00 44444444444444..

0167:006DF34C 80 00 BC 58 C8 F3 6D 00-7E 51 46 00 8C 29 47 00 ...X..m.~QF..)G.

0167:006DF35C 1C F3 6D 00 14 00 00 00-00 00 78 83 F5 10 00 00 ..m.......x.....

0167:006DF36C 00 00 00 00 A0 0E 08 00-00 00 00 00 00 00 00 00 ................

:d ds:edx

0167:006DF328 32 39 34 46 41 41 38 36-33 30 44 30 35 39 00 58 294FAA8630D059.X

0167:006DF338 80 00 00 00 34 34 34 34-34 34 34 34 34 34 34 34 ....444444444444

0167:006DF348 34 34 00 00 80 00 BC 58-C8 F3 6D 00 7E 51 46 00 44.....X..m.~QF.

0167:006DF358 8C 29 47 00 1C F3 6D 00-14 00 00 00 00 00 78 83 .)G...m.......x.


好了,来段 INI 文件把帮它做一个注册机吧!

[Options]

CommandLine=Decompile Winhelp.exe 这是被取注册码的 EXE 文件名

Mode=0 采用模式 0 读取注册码

First_Break_Address=40E4AF 程式的中断地址,它和 ICE 中见到的是一样的

First_Break_Address_Code=8A 中断程式的 1 Byte 代码,这个 8A 就是 015f:0040e4af 的 8A

First_Break_Address_Code_Lenth=2 中断行代码的长度(单位: byte )

Save_Code_Address=EDX 存放注册码的内存地址


生成后保存为 CRACKCODE.INI 文件,把 CRACKCODE.EXE 和 CRACKCODE.INI 一起 copy 到被注册的 软件的安装目录下,运行 CRACKCODE.EXE 。哦!被取注册码的软件也运行了,到注册的窗口去,随便输入足够数量的注册码,按确定,哦!跳出一个显示窗来,里面出现了你想要的正 确注册码了。是不是觉得很神奇呢!来试一试你就知道了!大家现在可以见到,用寄存器寻 址是多么好的一件事啊!

下面我们再来看一看 CrackCode2000 的另一个工作模式吧!以下是关于美萍网管大师 3.1 的注册

机的写法:

大家看一看这个软件的比较程式吧!

015f:00460759 8bd8 mov ebx,eax

015f:0046075b b87c074600 mov eax,0046077c

015f:00460760 e81f000000 call 00460784

015f:00460765 3bd8 cmp ebx,eax 这里的 ebx 就是放你台机器

015f:00460767 7507 jnz 00460770 的正确的注册码了

015f:00460769 b801000000 mov eax,00000001

015f:0046076e 5b pop ebx

015f:0046076f c3 ret

好我们来写注册机了:


[Options]

CommandLine=scon.exe 这是被取注册码的 EXE 文件名

Mode=1 采用模式 1 读取注册码

First_Break_Address=460765 程式的中断地址,它和 ICE 中见到的是一样的

First_Break_Address_Code=3B 中断程式的 1 Byte 代码,这个 3B 就是 015f:00460765 的 3B

First_Break_Address_Code_Lenth=2 中断行代码的长度(单位: byte )

Save_Code_Address=EBX 存放注册码的内存地址


大家看到了吗?今次 CrackCode2000 使用了模式 1 来读取了,因为今次的注册码不是直接用 ASCII 的形式放在内存中的,而是用数值的形式放在寄存器处的,所以这时就要用模式 1 了。 生成后保存为 CRACKCODE.INI 文件,把 CRACKCODE.EXE 和 CRACKCODE.INI 一起 copy 到被注册的 软件的安装目录下,运行 CRACKCODE.EXE 。哦!被取注册码的软件也运行了,哦!软件一运行 注册码就出来了!哈哈。。。。。。

好了,我们再来进一步地研究 CrackCode 的加强模式吧!这是正式版本才具有的,二重断点读取注册码,这是 CrackCode 的增强模式,它可以使用二次重点的方法,来达到的目的,大 家可能还不了解为什么要这样做吧!好,让我们看一看下面这个软件,你就明白这是多么 的重要啊!
下面的实现例子是大家熟悉的 Winzip7.0 !好了开始吧!我们找到了它的比较程式了:

015f:00457920 8a06 mov al,[esi] 输入的注册码

015f:00457922 46 inc esi

015f:00457923 8a27 mov ah,[edi] 正确的注册码

015f:00457925 47 inc edi

015f:00457926 38c4 cmp ah,al

015f:00457928 74f2 jz 0045791c

015f:0045792a 2c41 sub al,41

015f:0045792c 3c1a cmp al,1a

015f:0045792e 1ac9 sbb cl,cl

015f:00457930 80e120 and cl,20

015f:00457933 02c1 add al,cl

015f:00457935 0441 add al,41

015f:00457937 86e0 xchg ah,al

015f:00457939 2c41 sub al,41

015f:0045793b 3c1a cmp al,1a

015f:0045793d 1ac9 sbb cl,cl

015f:0045793f 80e120 and cl,20

015f:00457942 02c1 add al,cl

015f:00457944 0441 add al,41

015f:00457946 38e0 cmp al,ah

015f:00457948 74d2 jz 0045791c

我们在 winsoftice 中下以下的命令:

:d ds:esi

0167:0047D958 34 38 34 38 34 38 34 38-34 38 00 00 00 00 00 00 4848484848......

0167:0047D968 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

0167:0047D978 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

:d ds:edi

0167:0072F41C 43 39 36 32 30 35 45 42-00 00 01 00 00 00 0A 00 C96205EB........

0167:0072F42C D0 00 36 18 DA F4 0C 00-2C 20 0C 00 CE 1F 1A 84 ..6....., ......

0167:0072F43C 3F 19 5C 84 97 0F 47 04-00 00 0A 00 00 00 0A 00 ?.\...G.........

看到了吗?那 ds:edi 放的就是你要的东西啊!

好了,我们先试一试用普通模式 0 来写注册机吧!

[Options]

CommandLine=winzip32.exe 这是被取注册码的 EXE 文件名

Mode=0 采用模式 1 读取注册码

First_Break_Address=457923 程式的中断地址,它和 ICE 中见到的是一样的

First_Break_Address_Code=8A 中断程式的 1 Byte 代码,这个 3B 就是 015f:00460765 的 3B

First_Break_Address_Code_Lenth=2 中断行代码的长度(单位: byte )

Save_Code_Address=EDI 存放注册码的内存地址


生成后保存为 CRACKCODE.INI 文件,把 CRACKCODE.EXE 和 CRACKCODE.INI 一起 copy 到被注册的 软件的安装目录下,运行 CRACKCODE.EXE 。哦! winzip 会说很多的 dll 找不到,不能正常运行。

哦!发生了什么事啊!好我们用 winsoftice 在那 cs:457923 下一个断点,重新运行 winzip , 哦!我们的 winsoftice 不断地中断,原来 winzip 的设计很特殊性,它会用比较注册码的程式来加载其它的 dll ,所以 CrackCode 的跟踪就不能正常地进行下去了。

好吧!我们再看一看程式吧!经过分析我们知道,上面的比较程式是由下面的程式调用去

做比较注册码的工作的。

015f:00407c14 50 push eax

015f:00407c15 57 push edi

015f:00407c16 e8ab000000 call 00407cc6 带过这个 Call 在上面的

015f:00407c1b 59 pop ecx 0167:0072F41C 址中注册

015f:00407c1c be58d94700 mov esi,0047d958 码就出来了。

015f:00407c21 59 pop ecx

015f:00407c22 8d85c0feffff lea eax,[ebp-0140]

015f:00407c28 56 push esi

015f:00407c29 50 push eax

015f:00407c2a e8d1fc0400 call 00457900 这个 Call 就是调用比较

015f:00407c2f f7d8 neg eax 注册码的 Call 了。

015f:00407c31 1bc0 sbb eax,eax

015f:00407c33 59 pop ecx

015f:00407c34 40 inc eax

015f:00407c35 59 pop ecx

015f:00407c36 a37cb04700 mov [0047b07c],eax


本来我们可以在上面出现了注册之后就找一个中断地址中断用模式 0 去取注册啊!但有一点你们切记,那是到了万不得意时才使用的,我们要尽可能地用寄存器寻址。所以我们使用增强模式来解决这个问题。好了,我们在出现了注册码和调用比较注册码程式的 Call 之间 找一个地址,但经过分析我选取 015f:00407c1c 这个地址,当然你也可以选择其它的。 下面大家看一看 INI 文件是如何写的:
[Options]

CommandLine=winzip32.exe 这是被取注册码的 EXE 文件名

Mode=2 采用增强模式 2 读取注册码

First_Break_Address=407C1C 程式的中断地址 1 ,它和 ICE 中见到的是一样的

First_Break_Address_Code=BE 中断程式的 1 Byte 代码,这个 3B 就是 015f:00407c1c 的 BE

First_Break_Address_Code_Lenth=5 中断行代码的长度(单位: byte )

Second_Break_Address=457923 程式的中断地址 2 ,它和 ICE 中见到的是一样的

Second_Break_Address_Code_Lenth=2 中断行代码的长度(单位: byte )

Save_Code_Address=EDI 存放注册码的内存地址


生成后保存为 CRACKCODE.INI 文件,把 CRACKCODE.EXE 和 CRACKCODE.INI 一起 copy 到被注册的 软件的安装目录下,运行 CRACKCODE.EXE 。哦!被取注册码的软件也运行了,哦!软件一运行 注册码就出来了!哈哈。。。。。。

作者: Ru Feng

2、Keymake使用(作者:刘健英 知软网)

  这个注册机编写器以前一直是我自己为写注册机而编写的,通过它只要略有汇编基础很快就能写出一个注册机。而不需要再过多的了解程序的指令算法。 整个程序体实际上只是我用汇编写的一个模板。所以大家也可以在其中自定义自己的界面和提示信息。可以用VC++或BC++等资源编辑工具自行修改key1.res资源文件,但请不要修改它们对应的ID号。

  点击此下载例子程序,主要用来举例说明这个程序的使用(我先假设自己并不太懂Win32汇编)。

   通过动态调试或反汇编例子程序可以得到以下注册码的计算过程:

xxxx:00401077 CALL GetCommandLineA
xxxx:0040107C CMP BYTE PTR [EAX],22
xxxx:0040107F JNZ 401082
xxxx:00401081 INC EAX
xxxx:00401082 MOV CX,WORD PTR [EAX]
xxxx:00401085 MOV WORD PTR [0040306C],CX
xxxx:0040108C MOV WORD PTR [0040306E],5C
xxxx:00401095 PUSH 0
xxxx:00401097 PUSH 0
xxxx:00401099 PUSH 0
xxxx:0040109B PUSH 0
xxxx:0040109D PUSH DWORD 00403058
xxxx:004010A2 PUSH 0
xxxx:004010A4 PUSH 0
xxxx:004010A6 PUSH DWORD 0040306C
xxxx:004010AB CALL GetVolumeInformationA
…………    …………
…………    …………
xxxx:0040111E MOV EAX,1
xxxx:00401123 CPUID
xxxx:00401125 MOV ECX,DWORD PTR [00403058]
xxxx:0040112B XOR EDX,EDX
xxxx:0040112D MUL ECX
xxxx:0040112F ADD EAX,EDX
xxxx:00401131 PUSH EAX
xxxx:00401132 PUSH DWORD 0040303E    ; 在这里下D 40303E可以看到数据窗口中显示为“%1X”
xxxx:00401137 PUSH DWORD 0040305C
xxxx:0040113C CALL wsprintfA

  对于以上的指令并不需要过多的了解它在干什么,只要将其中的每个地址改成一个变量地址的声明,然后再原封不动的抄到注册机编写器的代码窗口中即可。

  这是写好的声明:

a1 dd 0 ; 这是一个双字的内存空间,对应于上面的403058。
;(因为40109D处的指令是DWORD 403058,所以用dd,如果是WORD就用dw,如果是BYTE就用db)
a2 dd 0 ; 对应于上面的40306C
a3 db "%1X",0 ; 对应于上面的40303E指向的字符串
a4 db 20 dup (0)
; 这是20个字节的内存空间,用来存放输出的注册码,对应于上面的40305C

  输入如图所示:



    这是写好的程序代码:

CALL GetCommandLineA CMP BYTE PTR [EAX],22h ; 后面加h表示是十六进制
JNZ n1
INC EAX
n1:
MOV CX,WORD PTR [EAX]
MOV WORD PTR a2,CX
MOV WORD PTR a2+2,5Ch
PUSH 0
PUSH 0
PUSH 0
PUSH 0
LEA EAX,a1 ; 令EAX指向a1
PUSH EAX
PUSH 0
PUSH 0
LEA EAX,a2
PUSH EAX ; 令EAX指向a2
CALL GetVolumeInformationA ; 当然这几条语句也可以直接写成
invoke GetVolumeInformationA,addr a2,0,0,addr a1,0,0,0,0
的形式
MOV EAX,1
CPUID
MOV ECX,a1
XOR EDX,EDX
MUL ECX
ADD EAX,EDX
PUSH EAX
LEA EAX,a3 ; 令EAX指向a3,也就是指向字符“%1X”。
PUSH EAX
LEA EAX,a4
PUSH EAX
CALL wsprintfA
LEA EAX,a4
; 令EAX指向a4。因为程序最后显示的就是EAX寄存器所指向的内存地址的数据。

  输入如下图所示:



  可以看到这与上面的反汇编代码基本相同。点击编译就可以很容易的得到一个注册机了。

  生成的注册机如下图所示(这只是我写的外观,你也可以自行修改):



  需要说明的是因为这只是我写的一个模板,所以我也在程序中使用了几个变量。
  请不要再重复声明:hCursorHandle、hInstance、hIcon、hTempEbp、hInput、hMode以免出错。
  还有就是你一定要在指令结束时令EAX指向正确的注册码地址。

  这种算注册码的方法不是直接从用户所输入的序列号来计算注册码的,所以并不适用于所有情况。有时我们可能需要根据用户所填入的序列号来计算注册码。考虑到这种情况所以我在程序初使时令EAX指向第一个编辑框(也就是输入序列号的窗口)收到用户输入的数据,令EBX指向第二个编辑框收到用户输入的数据,令ECX指向第三个编辑框收到用户输入的数据。你如果要对用户输入的序列号或用户名等信息进行操作,那么可以就对EAX、EBX、ECX进行操作。

  下面的代码是本例根据用户所填入的序列号来计算注册码的方法:

MOV ECX,EAX ; EAX指向用户输入的八位序列号,现在暂将它移动到ECX寄存器
XOR EBX,EBX ; 以下是一段典型的将内存中的ASCII码转换为十六进制代码。
n1:
MOVZX EAX,BYTE PTR [ECX]
OR AL,AL
JZ n3
CMP AL,3Ah
JC n2
SUB AL,7
n2:
SUB AL,30h
SHL EBX,4
ADD EBX,EAX
INC ECX
JMP n1
n3: ; 我想以上的一段代码应该懂汇编就能写的出(如果不是很明白,那么你对我编写好的注册机用TRW调试一次就知道了)。
PUSH EBX ; 最后的十六进制结果都保存在寄存器EBX中
; 将EBX入栈,这是为了将EBX寄存器的数据保存起来。因为经过CPUID这个指令后EBX的值将被修改。然后后面就和上面一样照抄程序中的指令。以下计算注册码的方法很简短。但在实际的破解过程中,程序的算法可能会相当复杂。这就需要你通过调试或反汇编将关键的运算指令都找出来,再写进来。
MOV EAX,1
CPUID
POP ECX ; 恢复EBX的值到ECX寄存器
XOR EDX,EDX
MUL ECX
ADD EAX,EDX
PUSH EAX
LEA EAX,a3 ; 令EAX指向a3,也就是指向字符“%1X”。
PUSH EAX
LEA EAX,a4
PUSH EAX
CALL wsprintfA
LEA EAX,a4
; 令EAX指向a4。因为程序最后显示的就是EAX寄存器所指向的内存地址的数据。

下图分别是采用方案二和方案三编译后的窗口界面:

  

  如果你不采用这种方法编写那么也可以使用程序中的另一个功能“另类注册机”。它和CrackCode2000一样,也是通过拦截程序指令并显示出注册码。 我之所以再写一个是因为以前的CrackCode2000提供的拦截选项非常有限,而且也不对Wide格式(出现在VB程序中用00将ASCII码分隔开)提供支持,还有一个毛病是在有些程序中会出现莫名的非法操作或无法获得注册码的情况(就好比这个例子程序)。 另外它的界面也太简陋了,只是一个消息框。所以我用汇编写了这个另类注册机非常小巧,它最多可以设置100个断点(其实可以更多,但好象没这个必要),以及在每个断点处中断多少次,如下图所示:



  对于以上界面的说明:程序名称和中断地址的设置,这个我想用不着多说,会破解的人都懂。 而获取注册码的方式上需要说明一下,我是这样考虑的:寄存器方式-因为注册码可能是会放在寄存器中比较,并且可能经过十进制或十六进制的转换, 所以就提供了一个寄存器方式及十进制或十六进制的选项。 内存方式-是指:如设置为EDX,即指注册码保存在EDX所指向的内存地址中(而不是寄存器里)这样就为获取注册码提供了更多的选择。

  可以自定义在弹出的对话框中将显示的主页、邮件和窗口标题,如下图所示:



  生成的注册机有二个可选界面如下图所示:

  

  需要说明的一点是这个对话框只在拦截成功的时候出现。

  除此之外还有一个制作破解补丁的附加工具,制作界面如图所示。



  这是完成界面。

附录A、常用字符的7位ASCII值

Dec Hex Char Dec Hex Char Dec Hex Char Dec Hex Char
   32  20  (空格) 56  38  8 80  50  P 104  68  h
33  21  ! 57  39  9 81  51  Q 105  69  i
34  22  " 58  3A  : 82  52  R 106  6A  j
35  23  # 59  3B  ; 83  53  S 107  6B  k
36  24  $ 60  3C  < 84  54  T 108  6C  l
37  25  % 61  3D  = 85  55  U 109  6D  m
38  26  & 62  3E  > 86  56  V 110  6E  n
39  27  ' 63  3F  ? 87  57  W 111  6F  o
40  28  ( 64  40  @ 88  58  X 112  70  p
41  29  ) 65  41  A 89  59  Y 113  72  q
42  2A  * 66  42  B 90  5A  Z 114  72  r
43  2B  + 67  43  C 91  5B  [ 115  73  s
44  2C  , 68  44  D 92  5C  \ 116  74  t
45  2D  - 69  45  E 93  5D  ] 117  75  u
46  2E  . 70  46  F 94  5E  ^ 118  76  v
47  2F  / 71  47  G 95  5F  _ 119  77  w
48  30  0 72  48  H 96  60  ` 120  78  x
49  31  1 73  49  I 97  61  a 121  79  y
50  32  2 74  4A  J 98  62  b 122  7A  z
51  33  3 75  4B  K 99  63  c 123  7B  {
52  34  4 76  4C  L 100  64  d 124  7C  |
53  35  5 77  4D  M 101  65  e 125  7D  }
54  36  6 78  4E  N 102  66  f 126  7E  ~
55  37  7 79  4F  O 103  67  g 127  7F   

注:Dec表示:十进制
  Hex表示:十六进制
  Char表示:字符




标签集:TAGS:
回复Comments() 点击Count()

回复Comments

{commentauthor}
{commentauthor}
{commenttime}
{commentnum}
{commentcontent}
作者:
{commentrecontent}