📄 jiurl pe 格式学习总结(二)-- pe文件中的输出函数.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0062)http://jiurl.cosoft.org.cn/jiurl/document/jiurlpe/jiurlpe2.htm -->
<HTML><HEAD><TITLE>JIURL's PE 2</TITLE>
<META content="text/html; charset=gb2312" http-equiv=Content-Type>
<META content=黑客,安全,网络,编程,黑客软件,安全软件,hacker,UNIX,Linux,FreeBSD name=keywords>
<META content=黑客,安全,网络,编程,黑客软件,安全软件,hacker,UNIX,Linux,FreeBSD name=description>
<STYLE type=text/css>.title {
FONT-FAMILY: "黑体", Arial, sans-serif; FONT-SIZE: 21px; FONT-WEIGHT: bold; LINE-HEIGHT: 48px; TEXT-DECORATION: none
}
.author {
FONT-FAMILY: "宋体"; FONT-SIZE: 12px; LINE-HEIGHT: 16px
}
.content {
FONT-SIZE: 14px; LINE-HEIGHT: 20px
}
</STYLE>
<META content="MSHTML 5.00.2614.3500" name=GENERATOR></HEAD>
<BODY bgColor=#f7f7f7 topMargin=5>
<DIV align=center>
<CENTER>
<TABLE border=0 cellPadding=0 cellSpacing=0 height=29 width="96%">
<TBODY>
<TR>
<TD class=title height=41 width="100%">
<P align=center><FONT face=宋体><B>JIURL PE 格式学习总结(二)--
PE文件中的输出函数</B></FONT></P></TD></TR></CENTER>
<TR>
<TD class=author height=9 width="100%">
<P align=center>作者: <A href="mailto:jiurl@mail.china.com">JIURL</A>
</P></TD></TR>
<TR>
<TD class=author height=6 width="100%">
<P
align=center>
主页: <A href="http://jiurl.yeah.net/">http://jiurl.yeah.net/</A> </P></TD></TR>
<TR>
<TD class=author height=2 width="100%">
<P align=center> 日期: 2003-4-24
</P></TD></TR></TBODY></TABLE></DIV>
<DIV align=center>
<CENTER>
<TABLE border=0 cellPadding=0 cellSpacing=0 height=1 width="96%">
<TBODY>
<TR>
<TD height=1 width="100%">
<HR color=#396da5 SIZE=3>
</TD></TR></TBODY></TABLE></CENTER></DIV>
<DIV align=center>
<TABLE border=0 cellPadding=0 cellSpacing=0 class=content height=3194
width="96%">
<TBODY>
<TR>
<TD height=4000 vAlign=top width="131%">
一般来说输出函数都是在dll中。我们将详细介绍关于输出函数的各种结构,通过一个例子来说明输出函数及其相关结构是怎么放在PE文件中的。以及如何在PE文件中找到这些东西。
<P><B>一 找到输出函数在文件中位置。</B></P>
<P>1.1 得到PE Header在文件中的位置。<BR> 通过DOS
Header结构的成员e_lfanew,可以确定PE Header的在文件中的位置。</P>
<P>1.2 得到文件中节的数目。<BR> 确定PE Header的在文件中的位置之后,就可以确定PE
Header中的成员FileHeader和成员OptionalHeader在文件中的位置。根据 FileHeader 中的
成员NumberOfSections 的值,就可以确定文件中节的数目,也就是节表数组中元素的个数。<BR><BR>1.3
得到节表在文件中的位置。<BR> PE Header在文件中的位置加上PE
Header结构的大小就可以得到节表在文件中的开始位置。PE
Header结构的大小可以由Signature的大小加上FileHeader的大小再加上FileHeader中的SizeOfOptionalHeade来确定。其实到目前为止SizeOfOptionalHeade也就是结构Optional
Header的大小也是固定的,所以整个PE
Header结构的大小也是固定。不过为了安全起见,还是用Signature的大小加上FileHeader的大小再加上FileHeader中的SizeOfOptionalHeade来确定比较保险。</P>
<P>1.4 得到输出函数在文件中的位置。<BR>
第1.2步中我们确定了文件中节的数目,第1.3步中我们确定了节表在文件中的位置。<BR>
现在来确定输出函数在文件中的位置。<BR> 取得PE Header中的Optional
Header中的DataDirectory数组中的第一项,<BR>也就是输出函数项。DataDirectory[]数组的每项都是IMAGE_DATA_DIRECTORY结构,该结构定义如下。<BR>typedef
struct _IMAGE_DATA_DIRECTORY {<BR>DWORD VirtualAddress;<BR>DWORD
Size;<BR>} IMAGE_DATA_DIRECTORY,
*PIMAGE_DATA_DIRECTORY;<BR>取得DataDirectory数组中的第一项中的成员VirtualAddress的值。这个值就是在内存中资源节的RVA。<BR>如果这个RVA的值为0表示这个PE文件中没有输出函数。<BR>然后根据节的数目,遍历节表数组。也就是从0到(节表数-1)的每一个节表项。<BR>每个节在内存中的RVA的范围是从该节表项的成员VirtualAddress字段的值开始(包括这个值),<BR>到VirtualAddress+Misc.VirtualSize的值结束(不包括这个值)。<BR>我们遍历整个节表,看我们取得的输出函数的RVA,在哪个节表项的RVA范围之内。<BR>如果在范围之内,就找到了输出函数所在节的节表项。<BR>这个节表项中的
PointerToRawData 中的值,就是输出函数所在节在文件中的位置。这个节表项中的VirtualAddress
中的值,就是输出函数所在节在内存中的RVA。用输出函数的RVA减去输出函数所在节的RVA,就可以得到输出函数在该节内偏移。用这个偏移加上该节的在文件中的位置,就可以得到输出函数在文件中的位置。即DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
- SectionTable[i].VirtualAddress + SectionTable[i].PointerToRawData
。<BR><BR>这样我们就得到了输出函数在文件中开始的位置。</P>
<P><B>二 PE文件中的输出函数。</B></P>
<P>
输出函数是用来给其他程序使用的。其他程序如果知道了某个输出函数的入口地址(就是实现这个函数功能的代码开始的地方),就可以转到那里去执行。一个PE文件中,如果有有输出函数,一般都不是一个。所以有一个数组来保存每个输出函数的入口地址。在PE文件中,提供两种方法,来找到某个输出函数的入口地址。第一种方法是通过入口地址数组序号,就是说知道是入口地址数组中的第几个元素,这样就可以得到里面的入口地址。第二种方法是通过函数名,通过比较函数名,然后得到对应该函数名的入口地址数组的序号,从而得到该函数名的对应函数的入口地址。为了能够通过函数名得到序号,就需要一些相关的结构。具体内容后面讲。总得来说PE文件的输出函数部分中就是这些东西。</P>
<P>
前面我们已经得到了输出函数部分在文件中开始的位置,在输出函数部分的最开始,是一个IMAGE_EXPORT_DIRECTORY
结构,这个结构提供很多重要的信息。这个结构的后面紧跟着的是 输出函数入口地址数组
。输出函数入口地址数组之后紧跟着的是输出函数名的指针数组。输出函数名的指针数组之后紧跟着的是输出函数名对应的序号的数组。输出函数名对应的序号的数组之后紧跟着dll的名字和输出函数的名字。注意,他们之间是紧挨着的。并且顺序为IMAGE_EXPORT_DIRECTORY,输出函数入口地址的数组,输出函数名的指针的数组,输出函数名对应的序号的数组。最后是dll的名字的字符串和那些输出函数名的字符串。</P>
<P> 先看IMAGE_EXPORT_DIRECTORY 结构,在WINNT.H中定义如下。</P>
<P>typedef struct _IMAGE_EXPORT_DIRECTORY {<BR>DWORD
Characteristics;<BR>DWORD TimeDateStamp;<BR>WORD MajorVersion;<BR>WORD
MinorVersion;<BR>DWORD Name;<BR>DWORD Base;<BR>DWORD
NumberOfFunctions;<BR>DWORD NumberOfNames;<BR>DWORD AddressOfFunctions; //
RVA from base of image<BR>DWORD AddressOfNames; // RVA from base of
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -