?? pe-tut7.html
字號:
<html>
<head>
<title>Iczelion's PE Tutorial 7: Export Table</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body bgcolor="#000066" text="#FFFFFF" link="#FFFFCC" vlink="#FFCCCC" alink="#CCFFCC">
<h1 align="center"><font face="Arial, Helvetica, sans-serif" color="#FFFFCC">Tutorial
7: Export Table</font></h1>
<p><font face="MS Sans Serif" size="-1">We have learned about one part of the
dynamic linking, namely the import table, in the previous tutorial. Now we will
learn about the other side of the coin, the export table.</font></p>
<p><font face="MS Sans Serif" size="-1">Download <b><a href="files/pe-tut07.zip" style="text-decoration:none">the
example</a></b>.</font></p>
<h3><font face="Arial, Helvetica, sans-serif">Theory:</font></h3>
<p><font face="MS Sans Serif" size="-1">When the PE loader runs a program, it
loads the associated DLLs into the process address space. It then extracts information
about the import functions from the main program. It uses the information to
search the DLLs for the addresses of the functions to be patched into the main
program. The place in the DLLs where the PE loader looks for the addresses of
the functions is the export table.</font></p>
<p><font face="MS Sans Serif" size="-1">When a DLL/EXE exports a function to be
used by other DLL/EXE, it can do so in two ways: it can export the function
by name or by ordinal only. Say if there is a function named "GetSysConfig"
in a DLL, it can choose to tell the other DLLs/EXEs that if they want to call
the function, they must specify it by its name, ie. GetSysConfig. The other
way is to export by ordinal. What's an ordinal? An ordinal is a 16-bit number
that uniquely identifies a function in a particular DLL. This number is unique
only within the DLL it refers to. For example, in the above example, the DLL
can choose to export the function by ordinal, say, 16. Then the other DLLs/EXEs
which want to call this function must specify this number in GetProcAddress.
This is called export by ordinal only.</font></p>
<p><font face="MS Sans Serif" size="-1">Export by ordinal only is strongly discouraged
because it can cause a maintenance problem for the DLL. If the DLL is upgraded/updated,
the programmer of that DLL cannot alter the ordinals of the functions else other
programs that depend on the DLL will break.</font></p>
<p><font face="MS Sans Serif" size="-1">Now we can examine the export structure.
As with import table, you can find where the export table is from looking at
the data directory. In this case, the export table is the first member of the
data directory. The export structure is called IMAGE_EXPORT_DIRECTORY. There
are 11 members in the structure but only some of them are really used.</font></p>
<table border="1" cellspacing="2" cellpadding="2" align="center">
<tr bgcolor="#006666">
<th><b><font face="MS Sans Serif" size="-1">Field Name</font></b></th>
<th><font face="MS Sans Serif" size="-1">Meaning</font></th>
</tr>
<tr>
<td><b><font face="MS Sans Serif" size="-1">nName</font></b></td>
<td><font face="MS Sans Serif" size="-1">The actual name of the module. This
field is necessary because the name of the file can be changed. If it's
the case, the PE loader will use this internal name.</font></td>
</tr>
<tr>
<td><b><font face="MS Sans Serif" size="-1">nBase</font></b></td>
<td><font face="MS Sans Serif" size="-1">A number that you must bias against
the ordinals to get the indexes into the address-of-function array.</font></td>
</tr>
<tr>
<td><b><font face="MS Sans Serif" size="-1">NumberOfFunctions</font></b></td>
<td><font face="MS Sans Serif" size="-1">Total number of functions/symbols
that are exported by this module.</font></td>
</tr>
<tr>
<td><b><font face="MS Sans Serif" size="-1">NumberOfNames</font></b></td>
<td><font face="MS Sans Serif" size="-1">Number of functions/symbols that
are exported by name. This value is<font color="#CC9900"><b> not</b></font>
the number of ALL functions/symbols in the module. For that number, you
need to check <font color="#FFFFCC"><b>NumberOfFunctions</b></font>. This
value can be 0. In that case, the module may export by ordinal only. If
there is no function/symbol to be exported in the first case, the RVA of
the export table in the data directory will be 0. </font></td>
</tr>
<tr>
<td><b><font face="MS Sans Serif" size="-1">AddressOfFunctions</font></b></td>
<td><font face="MS Sans Serif" size="-1">An RVA that points to an array of
RVAs of the functions/symbols in the module. In short, RVAs to all functions
in the module are kept in an array and this field points to the head of
that array.</font></td>
</tr>
<tr>
<td><b><font face="MS Sans Serif" size="-1">AddressOfNames</font></b></td>
<td><font face="MS Sans Serif" size="-1">An RVA that points to an array of
RVAs of the names of functions in the module.</font></td>
</tr>
<tr>
<td><b><font face="MS Sans Serif" size="-1">AddressOfNameOrdinals</font></b></td>
<td><font face="MS Sans Serif" size="-1">An RVA that points to a 16-bit array
that contains the ordinals associated with the function names in the AddressOfNames
array above.</font></td>
</tr>
</table>
<p><font face="MS Sans Serif" size="-1">Just reading the above table may not give
you the real picture of the export table. The simplified explanation below will
clarify the concept.</font></p>
<p><font face="MS Sans Serif" size="-1">The export table exists for use by the
PE loader. First of all, the module must keep the addresses of all exported
functions somewhere so the PE loader can look them up. It keeps them in an array
that is pointed to by the field <font color="#FFFFCC"><b>AddressOfFunctions</b></font>.
The number of elements in the array is kept in <font color="#FFFFCC"><b>NumberOfFunctions</b></font>.
Thus if the module exports 40 functions, it must have <font color="#CC6600"><b>
</b></font> 40 members in the array pointed to by <font color="#FFFFCC"><b>AddressOfFunctions
</b></font>and <font color="#FFFFCC"> <b>NumberOfFunctions</b></font> must contain
a value 40. Now if some functions are exported by names, the module must keep
the names in the file. It keeps the RVAs to the names in an array so the PE
loader can look them up. That array is pointed to by<font color="#FFFFCC"><b>
AddressOfNames </b></font>and the number of names in <font color="#FFFFCC"><b>NumberOfNames</b></font>.
Think about the job of the PE loader, it knows the names of the functions, it
must somehow obtain the addresses of those functions. Up to now, the module
has two arrays: the names and the addresses but there is no linkage between
them. Thus we need something that relates the names of the functions to their
addresses. The PE specification uses indexes into the address array as that
essential linkage. Thus if the PE loader finds the name it looks for in the
name array, it can obtain <font color="#999900"><b>the index into the address
table</b></font> for that name too. The indexes are kept in another array (the
last one) pointed to by the field <font color="#FFFFCC"><b>AddressOfNameOrdinals</b></font>.
Since this array exists as the linkage between the names and the addresses,
it must have exactly the same number of elements as the name array, ie. each
name can have one and only one associated address. The reverse is not true:
an address may have several names associated with it. Thus we can have "aliases"
that refer to the same address. To make the linkage works, both name and index
arrays must run in parallel, ie. the first element in the index array must hold
the index for the first name and so on.</font></p>
<table border="0" cellspacing="2" cellpadding="2" align="center">
<tr>
<th bgcolor="#006666"><font face="MS Sans Serif" size="-1">AddressOfNames</font></th>
<th><font face="MS Sans Serif" size="-1"></font></th>
<th bgcolor="#006666"><font face="MS Sans Serif" size="-1">AddressOfNameOrdinals</font></th>
</tr>
<tr>
<td>
<div align="center"><font face="MS Sans Serif" size="-1">|</font></div>
</td>
<td>
<div align="center"><font face="MS Sans Serif" size="-1"></font></div>
</td>
<td>
<div align="center"><font face="MS Sans Serif" size="-1">|</font></div>
</td>
</tr>
<tr>
<td>
<table border="1" cellspacing="2" cellpadding="2" align="center">
<tr bgcolor="#660066">
<td><font face="MS Sans Serif" size="-1">RVA of Name 1</font></td>
</tr>
<tr bgcolor="#660066">
<td><font face="MS Sans Serif" size="-1">RVA of Name 2</font></td>
</tr>
<tr bgcolor="#660066">
<td><font face="MS Sans Serif" size="-1">RVA of Name 3</font></td>
</tr>
<tr bgcolor="#660066">
<td><font face="MS Sans Serif" size="-1">RVA of Name 4</font></td>
</tr>
<tr bgcolor="#660066">
<td>
<div align="center"><font face="MS Sans Serif" size="-1">...</font></div>
</td>
</tr>
<tr bgcolor="#660066">
<td><font face="MS Sans Serif" size="-1">RVA of Name N</font></td>
</tr>
</table>
</td>
<td>
<table border="0" cellspacing="2" cellpadding="2" align="center">
<tr>
<td><font face="MS Sans Serif" size="-1"><--></font></td>
</tr>
<tr>
<td><font face="MS Sans Serif" size="-1"><--></font></td>
</tr>
<tr>
<td><font face="MS Sans Serif" size="-1"><--></font></td>
</tr>
<tr>
<td><font face="MS Sans Serif" size="-1"><--></font></td>
</tr>
<tr>
<td>
<div align="center"><font face="MS Sans Serif" size="-1">...</font></div>
</td>
</tr>
<tr>
<td><font face="MS Sans Serif" size="-1"><--></font></td>
</tr>
</table>
</td>
<td>
<table border="1" cellspacing="2" cellpadding="2" align="center">
<tr bgcolor="#003300">
<td><font face="MS Sans Serif" size="-1">Index of Name 1</font></td>
</tr>
<tr bgcolor="#003300">
<td><font face="MS Sans Serif" size="-1">Index of Name 2</font></td>
</tr>
<tr bgcolor="#003300">
<td><font face="MS Sans Serif" size="-1">Index of Name 3</font></td>
</tr>
<tr bgcolor="#003300">
<td><font face="MS Sans Serif" size="-1">Index of Name 4</font></td>
</tr>
<tr bgcolor="#003300">
<td>
<div align="center"><font face="MS Sans Serif" size="-1">...</font></div>
</td>
</tr>
<tr bgcolor="#003300">
<td><font face="MS Sans Serif" size="-1">Index of Name N</font></td>
</tr>
</table>
</td>
</tr>
</table>
<p><font face="MS Sans Serif" size="-1">An example or two is in order. If we have
the name of an export function and we need to get its address in the module,
we can do like this:</font></p>
<ol>
<li><font face="MS Sans Serif" size="-1">Go to the PE header</font></li>
<li><font face="MS Sans Serif" size="-1">Read the virtual address of the export
table in the data directory</font></li>
<li><font face="MS Sans Serif" size="-1">Go to the export table and obtain the
number of names (<font color="#FFFFCC"><b>NumberOfNames</b></font>)</font></li>
<li><font face="MS Sans Serif" size="-1">Walk the arrays pointed to by <font color="#FFFFCC"><b>AddressOfNames</b></font>
and<font color="#FFFFCC"><b> AddressOfNameOrdinals</b></font> in parallel,
searching for the matching name. If the name is found in the <font color="#FFFFCC"><b>AddressOfNames</b></font>
array, you must extract the value in the associated element in the <font color="#FFFFCC"><b>AddressOfNameOrdinals</b></font>
array. For example, if you find the RVA of the matching name in 77th element
of the <font color="#FFFFCC"><b>AddressOfNames </b></font>array, you must
extract the value stored in the 77th element of the <font color="#FFFFCC"><b>AddressOfNameOrdinals</b></font>
array. If you walk the array until <font color="#FFFFCC"><b>NumberOfNames</b></font>
elements are examined, you know that the name is not in this module.</font></li>
<li><font face="MS Sans Serif" size="-1">Use the value from the <font color="#FFFFCC"><b>AddressOfNameOrdinals</b></font>
array as the index into the <font color="#FFFFCC"><b>AddressOfFunctions</b></font>
array. Say, if the value is 5, you must extract the value in the 5th element
of the <font color="#FFFFCC"><b>AddressOfFunctions</b></font> array. That
value is the RVA of the function.</font></li>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -