• data directory(数据目录)之 引入表


    (一)IMAGE_DATA_DIRECTORY STRUCT
      VirtualAddress dd ?
      isize dd ?
    IMAGE_DATA_DIRECTORY ENDS

    (二)data directory数组第二项(Import symbols)的IMAGE_DATA_DIRECTORY中的VirtualAddress包含引入表地址,这块地址是一个 IMAGE_IMPORT_DESCRIPTOR结构数组。每个结构包含PE文件引入函数的一个相关DLL的信息。比如,如果该PE文件从10个不同的DLL中引入函数,那么这个数组就有10个成员。该数组以一个全0的成员结尾。

    IMAGE_IMPORT_DESCRIPTOR STRUCT
      union
        Characteristics dd ?
        OriginalFirstThunk dd ?
      ends
      TimeDateStamp dd ?
      ForwarderChain dd ?
      Name1 dd ?
      FirstThunk dd ?
    IMAGE_IMPORT_DESCRIPTOR ENDS

    1、 结构第一项是一个union子结构。事实上,这个union子结构只是给 OriginalFirstThunk增添了个别名,您也可以称其为"Characteristics"。OriginalFirstThunk是一个指向一个IMAGE_THUNK_DATA结构数组的RVA(指针)。而IMAGE_THUNK_DATA是一个dword集合,通常我们将其解释为指向一个IMAGE_IMPORT_BY_NAME结构的指针。

    IMAGE_IMPORT_BY_NAME STRUCT
      Hint dw ?
      Name1 db ?
    IMAGE_IMPORT_BY_NAME ENDS

       Hint 指示本函数在其所驻留DLL的引出表中的索引号。该域被PE装载器用来在DLL的引出表里快速查询函数。该值不是必须的,一些连接器将此值设为0
      Name1
    含有引入函数的函数名。函数名是一个ASCIIZ字符串。注意这里虽然将Name1的大小定义成字节,其实它是可变尺寸域,只不过我们没有更好方法来表示结构中的可变尺寸域。

    2、TimeDateStampForwarderChain可是高级东东: 让我们精通其他成员后再来讨论它们吧。

    3、FirstThunkOriginalFirstThunk非常相似,它也包含指向一个 IMAGE_THUNK_DATA结构数组的RVA(当然这是另外一个IMAGE_THUNK_DATA结构数组)

    OriginalFirstThunk IMAGE_IMPORT_BY_NAME FirstThunk

    |

          |
    IMAGE_THUNK_DATA
    IMAGE_THUNK_DATA
    IMAGE_THUNK_DATA
    IMAGE_THUNK_DATA
    ...
    IMAGE_THUNK_DATA
    --->
    --->
    --->
    --->
    --->
    --->
    Function 1
    Function 2
    Function 3
    Function 4
    ...
    Function n
    <---
    <---
    <---
    <---
    <---
    <---
    IMAGE_THUNK_DATA
    IMAGE_THUNK_DATA
    IMAGE_THUNK_DATA
    IMAGE_THUNK_DATA
    ...
    IMAGE_THUNK_DATA

    问题: 为什么我们需要两个完全相同的数组? 为了回答该问题,我们需要了解当PE文件被装载到内存时,PE装载器将查找IMAGE_THUNK_DATAIMAGE_IMPORT_BY_NAME这些结构数组,以此决定引入函数的地址。然后用引入函数真实地址来替代由FirstThunk指向的IMAGE_THUNK_DATA数组里的元素值。因此当PE文件准备执行时,上图已转换成:

    OriginalFirstThunk IMAGE_IMPORT_BY_NAME FirstThunk

    |

          |
    IMAGE_THUNK_DATA
    IMAGE_THUNK_DATA
    IMAGE_THUNK_DATA
    IMAGE_THUNK_DATA
    ...
    IMAGE_THUNK_DATA
    --->
    --->
    --->
    --->
    --->
    --->
    Function 1
    Function 2
    Function 3
    Function 4
    ...
    Function n
       
     
     
     
     
     
    Address of Function 1
    Address of Function 2
    Address of Function 3
    Address of Function 4
    ...
    Address of Function n

    (三)些情况下一些函数仅由序数引出,也就是说您不能用函数名来调用它们: 您只能用它们的位置来调用。此时,调用者模块中就不存在该函数的IMAGE_IMPORT_BY_NAME结构。不同的,对应该函数的 IMAGE_THUNK_DATA值的低位字指示函数序数,而最高二进位 (MSB)设为1。例如,如果一个函数只由序数引出且其序数是1234h,那么对应该函数的 IMAGE_THUNK_DATA值是80001234hMicrosoft提供了一个方便的常量来测试dword值的MSB位,就是 IMAGE_ORDINAL_FLAG32,其值为80000000h

    (四)如果要列出某个PE文件的所有引入函数,可以照着下面步骤走: 

    1. 校验文件是否是有效的PE
    2. DOS header 定位到 PE header
    3. 获取位于 OptionalHeader 数据目录地址。
    4. 转至数据目录的第二个成员提取其VirtualAddress值。
    5. 利用上值定位第一个 IMAGE_IMPORT_DESCRIPTOR结构。
    6. 检查 OriginalFirstThunk值。若不为0,顺着 OriginalFirstThunk里的RVA值转入那个RVA数组。若 OriginalFirstThunk0,就改用FirstThunk值。有些连接器生成PE文件时会置OriginalFirstThunk值为0,这应该算是个bug。不过为了安全起见,我们还是检查 OriginalFirstThunk值先。
    7. 对于每个数组元素,我们比对元素值是否等于IMAGE_ORDINAL_FLAG32如果该元素值的最高二进位为1, 那么函数是由序数引入的,可以从该值的低字节提取序数。
    8. 如果元素值的最高二进位为0,就可将该值作为RVA转入 IMAGE_IMPORT_BY_NAME 数组,跳过 Hint就是函数名字了。
    9. 再跳至下一个数组元素提取函数名一直到数组底部(它以null结尾)。现在我们已遍历完一个DLL的引入函数,接下去处理下一个DLL
    10. 即跳转到下一个 IMAGE_IMPORT_DESCRIPTOR并处理之,如此这般循环直到数组见底。(IMAGE_IMPORT_DESCRIPTOR数组以一个全0域元素结尾)
  • 相关阅读:
    kmeans 初步学习小结
    CAVASS使用经验
    分类之数据集导入matlab方法
    彩色图转化成灰度图
    阈值分割之迭代选择阈值法
    初步学习之FCM
    特征提取学习之HOG原理讲解
    特征提取初步学习之LBP算法
    CodePen.io网站前端设计开发平台
    阿里负责人揭秘面试潜规则
  • 原文地址:https://www.cnblogs.com/wang-can/p/3280515.html
Copyright © 2020-2023  润新知