📄 chap8-5-1.htm.primary
字号:
<html>
<head>
<title>Crack Tutorial</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<link rel="stylesheet" href="style/css.css" type="text/css">
<link rel="stylesheet" href="../STYLE/Css.css" type="text/css">
</head>
<body bgcolor="white" text="#000000" link="#004080" vlink="#004080" background="../image/Back.gif">
<p><a href="../catalog.htm">目录</a>>>第8章</p>
<p align="center" class="shadow1Copy"><b class="p3">第8章 压缩与脱壳</b></p>
<table width="80%" border="0" cellspacing="0" cellpadding="3" align="center" bgcolor="#bcbcbc" bordercolor="#111111" class="shadow1">
<tr>
<td class="shadow1" width="20%">
<div align="center"><a href="Chap8-1.htm"><font color="#FFFFFF">第一节 PE文件格式</font></a></div>
</td>
<td class="shadow1" width="20%">
<div align="center"><a href="Chap8-2.htm"><font color="#FFFFFF">第二节 认识脱壳</font></a></div>
</td>
<td class="shadow1" width="20%">
<div align="center"><a href="Chap8-3-1.htm"><font color="#FFFFFF">第三节 自动脱壳</font></a></div>
</td>
<td class="shadow1" width="20%">
<div align="center"><a href="Chap8-4.htm"><font color="#FFFFFF">第四节 手动脱壳</font></a></div>
</td>
<td class="shadow1" width="20%">
<div align="center"><a href="Chap8-5.htm"><font color="#FFFFFF">第五节 脱壳高级篇</font></a></div>
</td>
</tr>
</table>
<p align="center"><span class="p9"><b>第五节 脱壳高级篇</b></span></p>
<table border="1" width="80%" cellpadding="5" bordercolor="#111111" bgcolor="#efefef" align="center" cellspacing="0">
<tr>
<td width="33%" valign="middle" align="center" class="p9" height="23">
<div align="left"><span class="p9"><span class="p9"> <span class="p9">1、<a href="Chap8-5-1.htm">认识Import表</a></span></span></span></div>
</td>
<td valign="middle" align="center" class="p9" height="23" width="34%">
<div align="left"><span class="p9"><span class="p9"><span class="p9"> </span>2、<a href="Chap8-5-2.htm">Import表的重建</a></span></span></div>
</td>
<td valign="middle" align="center" class="p9" height="23" width="33%">
<div align="left"><span class="p9"><span class="p9"> 3、<a href="Chap8-5-3.htm">IceDump和NticeDump使用</a></span></span></div>
</td>
</tr>
<tr>
<td width="33%" valign="middle" align="center" class="p9" height="23">
<div align="left"><span class="p9"><span class="p9"> <span class="p9"></span></span></span>4、<a href="Chap8-5-4.htm">Import
REConstructor使用</a></div>
</td>
<td valign="middle" align="center" class="p9" height="23" width="34%">
<div align="left"><span class="p9"><span class="p9"><span class="p9"> </span>5、<a href="Chap8-5-5.htm">ASProtect保护</a></span></span></div>
</td>
<td valign="middle" align="center" class="p9" height="23" width="33%">
<div align="left"><span class="p9"> </span></div>
</td>
</tr>
</table>
<p align="center"><b>1、<span class="p9"><span class="p9"><span class="p9">认识Import表</span></span></span></b></p>
<p>著者: [yAtEs] [Jamesluton@hotmail.com] <br>
译者:hying[CCG] <br>
标题:PE输入表说明 <br>
例子:<a href="technology/blah.EXE">下载 </a><br>
有很多介绍PE文件的文章,但是我打算写一篇关于输入表的文章,因为它对于破解很有用。 <br>
我想解释它的最好的方法是举一个例子,你可以跟着我逐步深入,一步一步的思考,最后你将完全明白,我选择了一个我刚下载下来的小程序,它是用TASM编译的,有一个比较小的输入表,所以我想它应该是个不错的范例。
<br>
好了,让我们开始吧。首先我们得找到输入表,它的地址放在PE文件头偏移80处,所以我们用16进制编辑器打开我们的EXE文件,我们先得找到PE文件头的起始点,这很简单,因为它总是以PE,0,0开始,我们可以在偏移100处找到它。在一般的WIN32程序中文件头偏移被放在文件0X3C处,在那我们通常可看到00
01 00 00,由于数据存储时是低位在前,高位在后的,所以翻转过来实际就是00000100,就象前面我们说的。接下来我们就可以在PE文件中找到我们的输入表,100+80=180在偏移180处我们看到0030
0000,翻转一下,它其实应该是00003000,这说明输入表在内存3000处,我们必须把它转换成文件偏移。 <br>
一般来说,输入表总是在某个段的起始处,我们可以用PE编辑器来查看虚拟偏移,寻找3000并由此发现原始偏移。很简单的。打开我们看到:
<br>
-CODE 00001000 00001000 00000200 00000600 <br>
-DATA 00001000 00002000 00000200 00000800 <br>
.idata 00001000 00003000 00000200 00000A00 <br>
.reloc 00001000 00004000 00000200 00000C00 <br>
找一下,我们就发现.idata段的虚拟偏移是3000,原始偏移是A00,3000-A00=2600,我们要记住2600,以便以后转换其它的偏移。如果你没找到输入表的虚拟偏移,那么就找一下最接近的段。
<br>
来到偏移A00处,我们就看到被称为IMAGE_IMPORT_DESCRIPTORs(IID)的东东,它用5个字段表示每一个被调用DLL的信息,最后以Null结束。
<br>
************************************************************************** <br>
(IID) IMAGE_IMPORT_DESCRIPTOR的结构包含如下5个字段: <br>
OriginalFirstThunk, TimeDateStamp, ForwarderChain, Name, FirstThunk <br>
<br>
OriginalFirstThunk <br>
该字段是指向一32位以00结束的RVA偏移地址串,此地址串中每个地址描述一个输入函数,它在输入表中的顺序是不变的。 <br>
<br>
TimeDateStamp <br>
一个32位的时间标志,有特殊的用处。 <br>
<br>
ForwarderChain <br>
输入函数列表的32位索引。 <br>
<br>
Name <br>
DLL文件名(一个以00结束的ASCII字符串)的32位RVA地址。 <br>
<br>
FirstThunk <br>
该字段是指向一32位以00结束的RVA偏移地址串,此地址串中每个地址描述一个输入函数,它在输入表中的顺序是可变的。 <br>
************************************************************************** <br>
<br>
好了,你有没有理解?让我们看看我们有多少IID,它们从偏移A00处开始 <br>
3C30 0000 / 0000 0000 / 0000 0000 / 8C30 0000 / 6430 0000 <br>
{OrignalFirstThunk} {TimeDateStamp} {ForwardChain} {Name} {First Thunk} <br>
5C30 0000 / 0000 0000 / 0000 0000 / 9930 0000 / 8430 0000 <br>
{OrignalFirstThunk} {TimeDateStamp} {ForwardChain} {Name} {First Thunk} <br>
0000 0000 / 0000 0000 / 0000 0000 / 0000 0000 / 0000 0000 <br>
<br>
每三分之一是个分界,我们知道每个IID包含了一个DLL的调用信息,现在我们有2个IID,所以我们估计这个程序调用了2个DLL。甚至我可以打赌,你能推测出我们将能找到什么。
<br>
每个IID的第四个字段表示的是名字,通过它我们可以知道被调用的函数名。第一个IID的名字字段是8C30 0000,翻转过来也就是地址0000308C,将它减去2600可以得到原始偏移,308C-2600=A8C,来到文件偏移A8C处,我们看到了什么?啊哈!原来调用的是KERNEL32.dll。
<br>
好了,接下来我们就要去找出KERNEL32.dll中被调用的函数。回到第一个IID。 <br>
FirstThunk字段包含了被调用的函数名的标志,OriginalFirstThunk仅仅是FirstThunk的备份,甚至有的程序根本没有,所以我们通常看FirstThunk,它在程序运行时被初始化。
<br>
KERNEL32.dll的FirstThunk字段值是6430 0000,翻转过来也就是地址00003064,减去2600得A64,在偏移A64处就是我们的IMAGE_THUNK_DATA,它存储的是一串地址,以一串00结束。如下:
<br>
A430 0000/B230 0000/C030 0000/CE30 0000/DE30 0000/EA30 0000/F630 0000/0000 0000
<br>
通常在一个完整的程序里都将有这些。我们现在有了7个函数调用,让我们来看其中的两个: <br>
DE30 0000翻转后是30DE,减去2600后等于ADE,看在偏移ADE处的字符串是ReadFile, <br>
EA30 0000翻转后是30EA,减去2600后等于AEA,看在偏移AEA处的字符串是WriteFile, <br>
你可能注意到了,在函数名前还有2个这字节的00,它是被作为一个提示。 <br>
很简单吧,你可以自己来试一下。回到A00,看第二个DLL的调用 <br>
5C30 0000 / 0000 0000 / 0000 0000 / 9930 0000 / 8430 0000 <br>
{OrignalFirstThunk} {TimeDateStamp} {ForwardChain} {Name} {First Thunk} <br>
先找它的DLL文件名。9930翻转为3099-2600 =A99,在偏移A99处找到USER32.dll。再看FirstThunk字段值:8430翻转为3084-2600=A84,偏移A84处保存的地址为08310000,翻转后3108-2600=B08,偏移B08处字符串为MessageBoxA。明白了吧,接下来你就可以把这些用在你自己的EXE文件上了。
<br>
摘要: <br>
在PE文件头+80偏移处存放着输入表的地址,输入表包含了DLL被调用的每个函数的函数名和FirstThunk,通常还有Forward
Chain和TimeStamp。 <br>
当运行程序时系统调用GetProcAddress,将函数名作为参数,换取真正的函数入口地址,并在内存中写入输入表。当你对一个程序脱壳时你可能注意到你有了一个已经初始化的FirstThunk。例如,在我的WIN98上,函数GetProcAddress的入口地址是AE6DF7BF,在98上,所有的KERNEL32.dll函数调用地址看上去地址都象:xxxxF7BF,如果你在输入表中看到这些,你可以利用orignal
thunk重建它,或者重建这个PE程序。 <br>
好了,我已经告诉你它们是如何工作的,我不是专家,如果你发现什么错误,请告诉我。 </p>
<p align="center"><a href="../Catalog.htm"><img src="../image/navtoc.gif" width="84" height="23" border="0"></a><a href="Chap8-5.htm"><img src="../image/Navprev.gif" width="80" height="23" border="0"></a><a href="Chap8-5-2.htm"><img src="../image/navnext.gif" width="83" height="23" border="0"></a></p>
<hr width=735>
<div align="center"><span class="p9"><font size="2"><span class="p9"><font size="2"><span class="p9">Copyright
© 2000-2001 <a href="http://www.pediy.com/">KanXue Studio</a> All Rights
Reserved.</span></font></span></font></span></div>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -