📄 lion-petut-c06.htm
字号:
</td>
</tr>
<tr>
<td align="center" bgcolor="#666600"><font
size="2" face="MS Sans Serif">...</font> </td>
</tr>
<tr>
<td align="center" bgcolor="#666600"><font
size="2" face="MS Sans Serif">IMAGE_THUNK_DATA</font>
</td>
</tr>
</table>
</td>
</tr>
</table>
<p><font size="2">现在您应该明白我的意思。不要被</font><font
color="#CCFFCC" size="2" face="MS Sans Serif"><b>IMAGE_THUNK_DATA</b></font><font
size="2">这个名字弄糊涂</font><font size="2"
face="MS Sans Serif">: </font><font size="2">它仅是指向 </font><font
color="#CCFFCC" size="2" face="MS Sans Serif"><b>IMAGE_IMPORT_BY_NAME
</b></font><font size="2">结构的</font><font size="2"
face="MS Sans Serif">RVA</font><font size="2">。 如果将 </font><font
color="#CCFFCC" size="2" face="MS Sans Serif"><b>IMAGE_THUNK_DATA</b></font><font
size="2" face="MS Sans Serif"> </font><font size="2">字眼想象成</font><font
size="2" face="MS Sans Serif">RVA</font><font size="2">,就更容易明白了。</font><font
color="#FFFFCC" size="2" face="MS Sans Serif"><b>OriginalFirstThunk</b></font><font
size="2" face="MS Sans Serif"> </font><font size="2">和 </font><font
color="#FFFFCC" size="2" face="MS Sans Serif"><b>FirstThunk</b></font><font
size="2" face="MS Sans Serif"> </font><font size="2">所指向的这两个数组大小取决于</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">文件从</font><font
size="2" face="MS Sans Serif">DLL</font><font size="2">中引入函数的数目。比如,如果</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">文件从</font><font
size="2" face="MS Sans Serif">kernel32.dll</font><font size="2">中引入</font><font
size="2" face="MS Sans Serif">10</font><font size="2">个函数,那么</font><font
color="#CCFFCC" size="2" face="MS Sans Serif"><b>IMAGE_IMPORT_DESCRIPTOR</b></font><font
size="2" face="MS Sans Serif"> </font><font size="2">结构的 </font><font
color="#FFFFCC" size="2" face="MS Sans Serif"><b>Name1</b></font><font
size="2">域包含指向字符串</font><font size="2"
face="MS Sans Serif">"kernel32.dll"</font><font
size="2">的</font><font size="2" face="MS Sans Serif">RVA</font><font
size="2">,同时每个</font><font color="#CCFFCC" size="2"
face="MS Sans Serif"><b>IMAGE_THUNK_DATA</b></font><font size="2"
face="MS Sans Serif"> </font><font size="2">数组有</font><font
size="2" face="MS Sans Serif">10</font><font size="2">个元素。</font></p>
<p><font size="2">下一个问题是</font><font size="2"
face="MS Sans Serif">: </font><font size="2">为什么我们需要两个完全相同的数组</font><font
size="2" face="MS Sans Serif">? </font><font size="2">为了回答该问题,我们需要了解当</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">文件被装载到内存时,</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">装载器将查找</font><font
color="#CCFFCC" size="2" face="MS Sans Serif"><b>IMAGE_THUNK_DATA</b></font><font
size="2" face="MS Sans Serif"> </font><font size="2">和 </font><font
color="#CCFFCC" size="2" face="MS Sans Serif"><b>IMAGE_IMPORT_BY_NAME</b></font><font
size="2" face="MS Sans Serif"> </font><font size="2">这些结构数组,以此决定引入函数的地址。然后用引入函数真实地址来替代由</font><font
color="#FFFFCC" size="2" face="MS Sans Serif"><b>FirstThunk</b></font><font
size="2">指向的</font><font color="#CCFFCC" size="2"><b> </b></font><font
color="#CCFFCC" size="2" face="MS Sans Serif"><b>IMAGE_THUNK_DATA</b></font><font
size="2" face="MS Sans Serif"> </font><font size="2">数组里的元素值。因此当</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">文件准备执行时,上图已转换成</font><font
size="2" face="MS Sans Serif">:</font></p>
<table border="0" cellspacing="1">
<tr>
<th bgcolor="#006666"><font size="2" face="MS Sans Serif">OriginalFirstThunk</font></th>
<th> </th>
<th bgcolor="#006666"><font size="2" face="MS Sans Serif">IMAGE_IMPORT_BY_NAME</font></th>
<th> </th>
<th bgcolor="#006666"><font size="2" face="MS Sans Serif">FirstThunk</font></th>
</tr>
<tr>
<td align="center"><p align="center">| </p>
</td>
<td align="center"> </td>
<td align="center"> </td>
<td align="center"> </td>
<td align="center"><font size="2" face="MS Sans Serif">|</font>
</td>
</tr>
<tr>
<td align="center"><table border="1" cellpadding="2">
<tr>
<td align="center" bgcolor="#666600"><font
size="2" face="MS Sans Serif">IMAGE_THUNK_DATA</font>
</td>
</tr>
<tr>
<td align="center" bgcolor="#666600"><font
size="2" face="MS Sans Serif">IMAGE_THUNK_DATA</font>
</td>
</tr>
<tr>
<td align="center" bgcolor="#666600"><font
size="2" face="MS Sans Serif">IMAGE_THUNK_DATA</font>
</td>
</tr>
<tr>
<td align="center" bgcolor="#666600"><font
size="2" face="MS Sans Serif">IMAGE_THUNK_DATA</font>
</td>
</tr>
<tr>
<td align="center" bgcolor="#666600"><font
size="2" face="MS Sans Serif">...</font> </td>
</tr>
<tr>
<td align="center" bgcolor="#666600"><font
size="2" face="MS Sans Serif">IMAGE_THUNK_DATA</font>
</td>
</tr>
</table>
</td>
<td align="center"><table border="0" cellpadding="2">
<tr>
<td align="center" nowrap><font size="2"
face="MS Sans Serif">---></font></td>
</tr>
<tr>
<td align="center" nowrap><font size="2"
face="MS Sans Serif">---></font></td>
</tr>
<tr>
<td align="center" nowrap><font size="2"
face="MS Sans Serif">---></font></td>
</tr>
<tr>
<td align="center" nowrap><font size="2"
face="MS Sans Serif">---></font></td>
</tr>
<tr>
<td align="center" nowrap><font size="2"
face="MS Sans Serif">---></font></td>
</tr>
<tr>
<td align="center" nowrap><font size="2"
face="MS Sans Serif">---></font></td>
</tr>
</table>
</td>
<td align="center"><table border="1" cellpadding="2">
<tr>
<td align="center" bgcolor="#660066"><font
size="2" face="MS Sans Serif">Function 1</font> </td>
</tr>
<tr>
<td align="center" bgcolor="#660066"><font
size="2" face="MS Sans Serif">Function 2</font> </td>
</tr>
<tr>
<td align="center" bgcolor="#660066"><font
size="2" face="MS Sans Serif">Function 3</font> </td>
</tr>
<tr>
<td align="center" bgcolor="#660066"><font
size="2" face="MS Sans Serif">Function 4 </font></td>
</tr>
<tr>
<td align="center" bgcolor="#660066"><font
size="2" face="MS Sans Serif">...</font> </td>
</tr>
<tr>
<td align="center" bgcolor="#660066"><font
size="2" face="MS Sans Serif">Function n</font> </td>
</tr>
</table>
</td>
<td align="center"><table border="0" cellpadding="2">
<tr>
<td align="center" nowrap> </td>
</tr>
<tr>
<td align="center" nowrap> </td>
</tr>
<tr>
<td align="center" nowrap> </td>
</tr>
<tr>
<td align="center" nowrap> </td>
</tr>
<tr>
<td align="center" nowrap> </td>
</tr>
<tr>
<td align="center" nowrap> </td>
</tr>
</table>
</td>
<td align="center"><table border="1" cellpadding="2">
<tr>
<td align="center" bgcolor="#666600"><font
size="2" face="MS Sans Serif">Address of Function
1</font> </td>
</tr>
<tr>
<td align="center" bgcolor="#666600"><font
size="2" face="MS Sans Serif">Address of Function
2</font> </td>
</tr>
<tr>
<td align="center" bgcolor="#666600"><font
size="2" face="MS Sans Serif">Address of Function
3</font> </td>
</tr>
<tr>
<td align="center" bgcolor="#666600"><font
size="2" face="MS Sans Serif">Address of Function
4</font> </td>
</tr>
<tr>
<td align="center" bgcolor="#666600"><font
size="2" face="MS Sans Serif">...</font> </td>
</tr>
<tr>
<td align="center" bgcolor="#666600"><font
size="2" face="MS Sans Serif">Address of Function
n </font></td>
</tr>
</table>
</td>
</tr>
</table>
<p><font size="2">由</font><font color="#FFFFCC" size="2"
face="MS Sans Serif"><b>OriginalFirstThunk</b></font><font
size="2" face="MS Sans Serif"> </font><font size="2">指向的</font><font
size="2" face="MS Sans Serif">RVA</font><font size="2">数组始终不会改变,所以若还反过头来查找引入函数名,</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">装载器还能找寻到。<br>
</font><font size="2" face="MS Sans Serif">当然再简单的事物都有其复杂的一面。</font><font size="2">有些情况下一些函数仅由序数引出,也就是说您不能用函数名来调用它们</font><font
size="2" face="MS Sans Serif">: </font><font size="2">您只能用它们的位置来调用。此时,调用者模块中就不存在该函数的</font><font
color="#CCFFCC" size="2"><b> </b></font><font color="#CCFFCC"
size="2" face="MS Sans Serif"><b>IMAGE_IMPORT_BY_NAME</b></font><font
size="2" face="MS Sans Serif"> </font><font size="2">结构。不同的,对应该函数的 </font><font color="#CCFFCC" size="2" face="MS Sans Serif"><b>IMAGE_THUNK_DATA</b></font><font
size="2" face="MS Sans Serif"> </font><font size="2">值的低位字指示函数序数,而最高二进位 </font><font size="2" face="MS Sans Serif">(MSB)</font><font
size="2">设为</font><font size="2" face="MS Sans Serif">1</font><font
size="2">。例如,如果一个函数只由序数引出且其序数是</font><font
size="2" face="MS Sans Serif">1234h</font><font size="2">,那么对应该函数的 </font><font color="#CCFFCC" size="2" face="MS Sans Serif"><b>IMAGE_THUNK_DATA</b></font><font
size="2" face="MS Sans Serif"> </font><font size="2">值是</font><font
size="2" face="MS Sans Serif">80001234h</font><font size="2">。</font><font
size="2" face="MS Sans Serif">Microsoft</font><font size="2">提供了一个方便的常量来测试</font><font
size="2" face="MS Sans Serif">dword</font><font size="2">值的</font><font
size="2" face="MS Sans Serif">MSB</font><font size="2">位,就是 </font><font color="#CCFFCC" size="2" face="MS Sans Serif"><b>IMAGE_ORDINAL_FLAG32</b></font><font
size="2">,其值为</font><font size="2" face="MS Sans Serif">80000000h</font><font
size="2">。<br>
假设我们要列出某个</font><font size="2"
face="MS Sans Serif">PE</font><font size="2">文件的所有引入函数,可以照着下面步骤走</font><font
size="2" face="MS Sans Serif">:</font></p>
<ol>
<li><font size="2">校验文件是否是有效的</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">。</font></li>
<li><font size="2">从 </font><font size="2"
face="MS Sans Serif">DOS header </font><font size="2">定位到
</font><font size="2" face="MS Sans Serif">PE header</font><font
size="2">。</font></li>
<li><font size="2">获取位于 </font><font color="#FFFFCC"
size="2" face="MS Sans Serif"><b>OptionalHeader </b></font><font
size="2">数据目录地址。</font></li>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -