列出某个PE文件的所有引入函数的步骤: 第一,校验文件是否是有效的PE 第二,从 DOS heade定位到 PE header ·第三,获取位于 OptionalHeader的数据目录( DataDirectory)的地址。 第四,转至数据目录的第二个成员提取其Ⅵ irtualAddress值。 第五,利用上值定位第一个 MAGE MPORT DESCRIPTOR结构 第六,检査 OriginalFirstThunk值。若不为0,则顺着 origⅰ afiRst Thunk里的RⅥA值转入那个RVA数组。若 OriginalFirst Thunk为0,就改用 FirstThunk值。有些连接器生成PE文 件时会置 OriginalFirstThunk值为0,这应该算是个bug。不过为了安 全起见,我们还是先检查 OriginalFirstThunk的值
列出某个PE文件的所有引入函数的步骤: • 第一,校验文件是否是有效的PE。 • 第二,从 DOS header 定位到 PE header。 • 第三,获取位于OptionalHeader的数据目录(DataDirectory)的地址。 • 第四,转至数据目录的第二个成员提取其VirtualAddress值。 • 第五,利用上值定位第一个IMAGE_IMPORT_DESCRIPTOR结构。 • 第六,检查OriginalFirstThunk值。若不为0,则顺着 OriginalFirstThunk里的RVA值转入那个RVA数组。若 OriginalFirstThunk为0,就改用FirstThunk值。有些连接器生成PE文 件时会置OriginalFirstThunk值为0,这应该算是个bug。不过为了安 全起见,我们还是先检查OriginalFirstThunk的值
·第七,对于每个数组元素,我们用 IMAGE ORDINAL FLAG32来检 该元素的最高位。如果该元素值的最高三进位为1,那么函数是由 序数引入的,可以从该值的低字节提取序数。如果元素值的最高一二进 位为0,就可将该值作为RVA转入 IMAGE IMPORT BY NAME数组, 跳过Hn就是函数名字了。 结尾)。现在我们已遍历完一个DL的引入函数,接下去处理下x 第八,再跳至下一个数组元素提取函数名,一直到数组底部(它以 DLL。 第九,即跳转到下一个 IMAGE IMPORT DESCR|PTOR并处理之 依次循环直到数组结尾( MAGE IMPORT DESCRIPTOR数组以 个全0域元素结尾)
• 第七,对于每个数组元素,我们用IMAGE_ORDINAL_FLAG32来检 查该元素的最高位。如果该元素值的最高二进位为1,那么函数是由 序数引入的,可以从该值的低字节提取序数。如果元素值的最高二进 位为0,就可将该值作为RVA转入IMAGE_IMPORT_BY_NAME数组, 跳过Hint就是函数名字了。 • 第八,再跳至下一个数组元素提取函数名,一直到数组底部(它以null 结尾)。现在我们已遍历完一个DLL的引入函数,接下去处理下一个 DLL。 • 第九,即跳转到下一个IMAGE_IMPORT_DESCRIPTOR并处理之。 依次循环直到数组结尾(IMAGE_IMPORT_DESCRIPTOR 数组以一 个全0域元素结尾)
(7)引出表( Export Table) 附加概念:引出函数,数据目录 引出表是数据目录的第一个成员,又可称 为 IMAGE EXPORT D| RECTORY。 MAGE EXPORT DIRECTORY共有11 个成员,部分介绍如下:
(7)引出表(Export Table) • 附加概念:引出函数,数据目录 • 引出表是数据目录的第一个成员,又可称 为IMAGE_EXPORT_DIRECTORY。 • IMAGE_EXPORT_DIRECTORY共有11 个成员,部分介绍如下:
域名 含义 nName 模块的真实名称。该域是必须的,因为文件名可能会改变。这 种情况下,PE装载器将使用这个内部名字。 nBase 基数,(引出序数- nBase)就是函数地址数组的索引值了 Numberoffunctions 模块引出的函数/符号总数。 Number ofNames 通过名字引出的函数/符号数目。该值不是模块引出的函数/符号 总数,这是由上面的 Numberoffunctions给出。本域可以为0, 表示模块可能仅仅通过序数引出。如果模块根本不引出任何函 数/符号,那么数据目录中引出表的RVA为0。 AddressOfFunctions 模块中有一个指向所有函数/符号的RⅤAs数组,本域就是指向该 RVAs数组的RVA。简言之,模块中所有函数的RⅤAs都保存在 个数组里,本域就指向这个数组的首地址。 AddressofNames 类似上个域,模块中有一个指向所有函数名的RVAs数组,本域 就是指向该RVAs数组的RⅤA。 AddressOfName Ordinals RVA,指向包含上述 AddressofNames'数组中相关函数之序数的 16位数组
域名 含义 nName 模块的真实名称。该域是必须的,因为文件名可能会改变。这 种情况下,PE装载器将使用这个内部名字。 nBase 基数,(引出序数- nBase)就是函数地址数组的索引值了。 NumberOfFunctions 模块引出的函数/符号总数。 NumberOfNames 通过名字引出的函数/符号数目。该值不是模块引出的函数/符号 总数,这是由上面的NumberOfFunctions给出。本域可以为0, 表示模块可能仅仅通过序数引出。如果模块根本不引出任何函 数/符号,那么数据目录中引出表的RVA为0。 AddressOfFunctions 模块中有一个指向所有函数/符号的RVAs数组,本域就是指向该 RVAs数组的RVA。简言之,模块中所有函数的RVAs都保存在一 个数组里,本域就指向这个数组的首地址。 AddressOfNames 类似上个域,模块中有一个指向所有函数名的RVAs数组,本域 就是指向该RVAs数组的RVA。 AddressOfNameOrdinals RVA,指向包含上述AddressOfNames数组中相关函数之序数的 16位数组
两类输出方式: Address OfFunctions FANumberOfFunctions Address ofNames FHNumberOfNames · Address ofNameOrdinals是用来统一上述 两类输出方式的。这就相当于一个别名。 它们的关联方式如下:
• 两类输出方式: – AddressOfFunctions和NumberOfFunctions – AddressOfNames和NumberOfNames • AddressOfNameOrdinals是用来统一上述 两类输出方式的。这就相当于一个别名。 • 它们的关联方式如下: