糖果派对官方网站_可以赌钱的糖果游戏_手机版
[PE结构深入解析] 8.输入表结商谈输入地址表(IAT)

[PE结构深入解析] 8.输入表结商谈输入地址表(IAT)

作者:操作系统    来源:未知    发布时间:2019-12-24 20:43    浏览量:

在 PE文件头的 IMAGE_OPTIONAL_HEADE福睿斯 构造中的 DataDirectory(数据目录表卡塔尔国的第二个成员就是指向输入表的。种种被链接进来的 DLL文件都各自对应一个IMAGE_IMPORT_DESC奥迪Q5IPTOTiguan (简单称谓IID卡塔尔 数组布局。

【pker / CVC.GB】 
[PE结构深入解析] 8.输入表结商谈输入地址表(IAT)。5、关于FASM 
----------- 
下边大家用FASM来编排我们的第二个程序。我们能够编写如下代码: 
format  PE GUI 4.0 
entry   __start 
section '.text' code    readable executable 
    __start: 
            ret 
我们把那一个文件存为test.asm并编写翻译它: 
fasm test.asm test.exe 
还未任何烦人的参数,很有益,不是么? :P 
我们先来看一下以此顺序的构造。第一句是format提醒字,它钦命了程序的体系,PE表示自身 
们编写的是二个PE文件,前边的GUI提醒编写翻译器大家将动用Windows图形分界面。假如要编写制定生龙活虎 
个调控台应用程序则足以钦点为CONSOLE。假诺要写二个基石驱动,可以钦点为NATIVE,表示 
不须要子系统援助。最终的4.0点名了子系统的版本号(还记得前边的MajorSubsystemVersion 
和MinorSubsystemVersion么?)。 
上边风姿罗曼蒂克行钦定了前后相继的输入为__start。 
section提醒字表示大家要起始多个新节。大家的前后相继独有二个节,即代码节,大家将其命名 
为.text,并点名节属性为只读(readable)和可进行(executable)。 
从今将来正是大家的代码了,大家唯有用一条ret指令回到系统,这时候宾馆里的回来地址为Exit- 
Thread,所以程序直接退出。 
上面运营它,程序只是简单地退出了,大家成功地用FASM编写了叁个顺序!大家曾经迈出了 
率先步,上边要让大家的次第能够做点什么。大家想要调用四个API,大家要怎么做啊?让 
我们再来充充电吧 :D 

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;                  // 0 if not bound,
                                            // -1 if bound, and real datetime stamp
                                            // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                            // O.W. date/time stamp of DLL bound to (Old BIND)

    DWORD   ForwarderChain;                 // -1 if no forwarders
    DWORD   Name;
    DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;

5.1、导入表 
----------- 
咱俩编辑如下代码并用TASM编写翻译: 

; tasm32 /ml /m5 test.asm 
; tlink32 -Tpe -aa test.obj ,,, import32.lib 

        ideal 
        p586 
        model   use32 flat 
extrn   MessageBoxA:near 
        dataseg 
str_hello       db      'Hello',0 
        codeseg 
__start: 
        push    0 
        push    offset str_hello 
        push    offset str_hello 
        push    0 
        call    MessageBoxA 
        ret 
        end     __start 
上面我们用w32dasm反汇编,获得: 
:00401000   6A00                    push    00000000 
:00401002   6800204000              push    00402000 
:00401007   6800204000              push    00402000 
:0040100C   6A00                    push    00000000 
:0040100E   E801000000              call    00401014 
:00401013   C3                      ret 
:00401014   FF2530304000            jmp     dword ptr [00403030] 
能够见见代码中的call MessageBoxA被翻译成了call 00401014,在这里个地方处是多个跳转 
指令jmp dword ptr [00403030],大家得以分明在地址00403030处存放的是MessageBoxA的 
真的地址。 
实际那几个地点是坐落于PE文件的导入表中的。下边大家继续大家的PE文件的上学。大家先来看 
时而导入表的构造。导入表是由风流倜傥雨后春笋的IMAGE_IMPORT_DESCCRUISERIPTOENVISION构造组成的。布局的个 
数由文件援引的DLL个数调节,文件引用了不怎么个DLL就有稍许个IMAGE_IMPORT_DESCRIPTOR 
布局,最终还也许有八个全为零的IMAGE_IMPORT_DESC奥迪Q7IPTOTiguan作为完毕。 
typedef struct _IMAGE_IMPORT_DESCRIPTOR { 
    union { 
        DWORD   Characteristics; 
        DWORD   OriginalFirstThunk; 
    }; 
    DWORD   TimeDateStamp; 
    DWORD   ForwarderChain; 
    DWORD   Name; 
    DWORD   FirstThunk; 
} IMAGE_IMPORT_DESCRIPTOR; 
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR; 
Name字段是三个LX570VA,内定了引进的DLL的名字。 
OriginalFirstThunk和FirstThunk在三个PE未有加载到内部存储器中的时候是相像的,都是指向后生可畏 
个IMAGE_THUNK_DATA布局数组。最终以七个内容为0的布局结束。其实这些构造正是一个双 
字。这么些结构很有意思,因为在分裂的时候那个构造意味着着差别的意思。当这些双字的最高 
位为1时,表示函数是以序号的措施导入的;当最高位为0时,表示函数是以名称格局导入的, 
那是其一双字是二个TiggoVA,指向叁个IMAGE_IMPORT_BY_NAME构造,那个组织用来钦点导入函数 
名称。 
typedef struct _IMAGE_IMPORT_BY_NAME { 
    WORD    Hint; 
    BYTE    Name[1]; 
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; 
Hint字段表示一个序号,可是因为是按名称导入,所以那一个序号经常为零。 
Name字段是函数的称谓。 
上边大家用一张图来声明这几个复杂的经过。倘使八个PE援用了kernel32.dll中的LoadLibraryA 
和GetProcAddress,还应该有三个按序号导入的函数80010002h。 
IMAGE_IMPORT_DESCRIPTOR                                  IMAGE_IMPORT_BY_NAME 
+--------------------+   +--> +------------------+     +-----------------------+ 
| OriginalFirstThunk | --+    | IMAGE_THUNK_DATA | --> | 023B |  ExitProcess   | <--+ 
+--------------------+        +------------------+     +-----------------------+    | 
|   TimeDataStamp    |        | IMAGE_THUNK_DATA | --> | 0191 | GetProcAddress | <--+--+ 
+--------------------+        +------------------+     +-----------------------+    |  | 
|   ForwarderChain   |        |     80010002h    |                                  |  | 
+--------------------+        +------------------+    +---> +------------------+    |  | 
|        Name        | --+    |         0        |    |     | IMAGE_THUNK_DATA | ---+  | 
+--------------------+   |    +------------------+    |     +------------------+       | 
|     FirstThunk     |-+ |                            |     | IMAGE_THUNK_DATA | ------+ 
+--------------------+ | |    +------------------+    |     +------------------+ 
                       | +--> |   kernel32.dll   |    |     |     80010002h    | 
                       |      +------------------+    |     +------------------+ 
                       |                              |     |         0        | 
                       +------------------------------+     +------------------+ 
还记得前面我们说过在叁个PE未有被加载到内存中的时候IMAGE_IMPORT_DESCRIPTOR中的 
OriginalFirstThunk和FirstThunk是一模一样的,那么为啥Windows要据有多个字段呢?其实 
是那样的,在PE文件被PE加载器加载到内部存款和储蓄器中的时候这几个加载器会自动把FirstThunk的值替 
换为API函数的真的入口,也正是非凡前面jmp的真的地址,而OriginalFirstThunk只然则是 
用来反向查找函数名而已。 
好了,又讲了那样多是要做怎么样吗?你立即就能够看出。下边大家就来协会大家的导入表。 
大家用来下代码来早先大家的引进节: 
section '.idata' import data    readable 
section提示字表示大家要从头多个新节。.idata是这几个新节的称号。import data表示那是 
三个引进节。readable表示那些节的节属性是只读的。 
后生可畏旦大家的前后相继只须要引进user32.dll中的MessageBoxA函数,那么大家的引入节唯有八个 
汇报这几个dll的IMAGE_IMPORT_DESCEscortIPTOEscort和叁个全0的组织。思谋如下代码: 
    dd      0                   ; 大家并无需OriginalFirstThunk 
    dd      0                   ; 大家也无需管这一个日子戳 
    dd      0                   ; 大家也不关怀这些链 
    dd      RVA usr_dll         ; 指向大家的DLL名称的LANDVA 
    dd      RVA usr_thunk       ; 指向大家的IMAGE_IMPORT_BY_NAME数组的RVA 
                                ; 注意这么些数组也是以0最后的 
    dd      0,0,0,0,0           ; 截至标记 
上面用到了三个途乐VA伪指令,它钦定的地点在编写翻译时被自动写为相应的昂CoraVA值。上边定义大家 
要引入的动态链接库的名字,这是二个以0末尾的字符串: 
    usr_dll     db      'user32.dll',0 
再有大家的IMAGE_THUNK_DATA: 
    usr_thunk: 
        MessageBox      dd      RVA __imp_MessageBox 
                        dd      0                   ; 停止标识 
上面的__imp_MessageBox在编译时出于前边有LANDVA提示,所以表示是IMAGE_IMPORT_BY_NAME的 
KugaVA。下边我们定义这一个结构: 
    __imp_MessageBox    dw      0                   ; 大家不按序号导入,所以能够 
                                                    ; 简单地置0 
                        db      'MessageBoxA',0     ; 导入的函数名 
好了,我们成功了导入表的创设。上边大家来看三个整机的程序,看看一个总体的FASM程序 
是何其的优良 :P 
format  PE GUI 4.0 
entry   __start 

在这里个 IID数组中,并不曾提议有个别许个项(正是未有明显指明有多少个链接文件卡塔尔,但它聊到底是以三个全为NULL(0卡塔尔的 IID 作为达成的申明。


; data section... 

section '.data' data    readable 
    pszText         db      'Hello, FASM world!',0 
    pszCaption      db      'Flat Assembler',0 

下边只摘录十三分主要的字段:


; code section... 

section '.text' code    readable executable 
    __start: 
            push    0 
            push    pszCaption 
            push    pszText 
            push    0 
            call    [MessageBox] 
            push    0 
            call    [ExitProcess] 

OriginalFirstThunk

bb电子糖果派对,它指向first thunk,IMAGE_THUNK_DATA,该 thunk 拥有 Hint 和 Function name 的地址。


; import section... 

section '.idata' import data    readable 
    ; image import descriptor 
    dd      0,0,0,RVA usr_dll,RVA usr_thunk 
    dd      0,0,0,RVA krnl_dll,RVA krnl_thunk 
    dd      0,0,0,0,0 
    ; dll name 
    usr_dll     db      'user32.dll',0 
    krnl_dll    db      'kernel32.dll',0 
    ; image thunk data 
    usr_thunk: 
        MessageBox      dd      RVA __imp_MessageBox 
                        dd      0 
    krnl_thunk: 
        ExitProcess     dd      RVA __imp_ExitProcess 
                        dd      0 
    ; image import by name 
    __imp_MessageBox    dw      0 
                        db      'MessageBoxA',0 
    __imp_ExitProcess   dw      0 
                        db      'ExitProcess',0 
观望此间自个儿信赖我们都对FASM这几个编写翻译器有了一个带头的认知,也势必有多数读者会说:“ 
这么辛勤啊,干啊要用这么些编写翻译器呢?”。是的,恐怕上面包车型地铁代码看起来很复杂,编写起来 
也很辛勤,但FASM的二个益处在于大家能够更积南北极垄断大家转移的PE文件结构,同一时间能对 
PE文件有更理性的认知。可是每种人的口味各异,嘿嘿,恐怕下面的说辞还远远不足说服各位读 
者,没涉及,选择大器晚成款符合您的编写翻译器吧,它们都如出生机勃勃辙能够 :P 

Name

它表示DLL 名称的相对虚地址(译注:绝对叁个用null作为完成符的ASCII字符串的三个宝马7系VA,该字符串是该导入DLL文件的名号。如:KEHavalNEL32.DLL)。

5.2、导出表 
----------- 
透过导入表的就学,小编想各位读者已经对PE文件的求学进程有了和睦认知和章程,所以下边 
至于导出表的焕发青新禧自己将加速局地速度。“朋友们注意啦!!! @#$%$%&#^”  :D 
在导出表的原初地点是二个IMAGE_EXPORT_DIRECTO汉兰达Y构造,但与引入表分化的是在导出表中 
唯有三个那一个组织。上面大家来看一下以此结构的概念: 
typedef struct _IMAGE_EXPORT_DIRECTORY { 
    DWORD   Characteristics; 
    DWORD   TimeDateStamp; 
    WORD    MajorVersion; 
    WORD    MinorVersion; 
    DWORD   Name; 
    DWORD   Base; 
    DWORD   NumberOfFunctions; 
    DWORD   NumberOfNames; 
    DWORD   AddressOfFunctions;     // RVA from base of image 
    DWORD   AddressOfNames;         // RVA from base of image 
    DWORD   AddressOfNameOrdinals;  // RVA from base of image 
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; 
Characteristics、MajorVersion和MinorVersion不使用,一般为0。 
TimeDataStamp是时刻戳。 
Name字段是一个奥迪Q5VA值,它指向了那些模块的原盛名称。这些称号与编写翻译后的文本名无关。 
Base字段钦定了导出函数序号的发端序号。假设Base的值为n,那么导出函数入口地址表中 
的率先个函数的序号正是n,第二个正是n+1... 
NumberOfFunctions钦定了导出函数的总和。 
NumberOfNames钦定了按名称导出的函数的总和。按序号导出的函数总的数量正是那几个值与外地 
总数NumberOfFunctions的差。 
AddressOfFunctions字段是叁个大切诺基VA值,指向四个大切诺基VA数组,数组中的每一个LANDVA均指向三个导 
出函数的入口地址。数组的项数等于NumberOfFuntions。 
AddressOfNames字段是叁个RAV4VA值,相同指向叁个翼虎VA数组,数组中的每种双字是贰个针对函 
数名字符串的中华VVA。数组的项数等于NumberOfNames。 
AddressOfNameOrdinals字段是多少个中华VVA值,它指向三个篇幅组,注意这里不再是双字了!! 
那一个数组起着很主要的功能,它的项数等于NumberOfNames,并与AddressOfNames指向的数组 
次第对应。其每种门类的值代表了这几个函数在入口地址表中索引。现在大家来看叁个事例, 
假诺三个导出函数Foo在导出入口地址表中居于第m个职务,大家索求Ordinal数组的第m项, 
若是这些值为x,大家把这一个值与导出序号的开头值Base的值n相加获得的值就是函数在入口 
地点表中索引。 
下图表示了导出表的组织和上述进度: 
+-----------------------+         +-----------------+ 
|    Characteristics    |  +----> | 'dlltest.dll',0 | 
+-----------------------+  |      +-----------------+ 
|     TimeDataStamp     |  | 
+-----------------------+  |  +-> +-----------------+ 
|      MajorVersion     |  |  | 0 | 函数进口地址宝马7系VA | ==> 函数Foo,序号n+0    <--+ 
+-----------------------+  |  |   +-----------------+                            | 
|      MinorVersion     |  |  |   |       ...       |                            | 
+-----------------------+  |  |   +-----------------+                            | 
|         Name          | -+  | x | 函数输入地址逍客VA | ==> 按序号导出,序号为n+x  | 
+-----------------------+     |   +-----------------+                            | 
|    Base(借使值为n)  |     |   |       ...       |                            | 
+-----------------------+     |   +-----------------+                            | 
|   NumberOfFunctions   |     |                                                  | 
+-----------------------+     |  +-> +-----+     +----------+      +-----+ <-+   | 
|     NumberOfNames     |     |  |   | RVA | --> | '_foo',0 | <==> |  0  | --+---+ 
+-----------------------+     |  |   +-----+     +----------+      +-----+   | 
|   AddressOfFunctions  | ----+  |   | ... |                       | ... |   | 
+-----------------------+        |   +-----+                       +-----+   | 
|     AddressOfNames    | -------+                                           | 
+-----------------------+                                                    | 
| AddressOfNameOrdinals | ---------------------------------------------------+ 
+-----------------------+ 
好了,下边大家来看构键大家的导出表。假若大家按名称导出叁个函数_foo。大家以如下代 
码开始: 
section '.edata' export data    readable 
接着是IMAGE_EXPORT_DIRECTORY结构: 
    dd      0                   ; Characteristics 
    dd      0                   ; TimeDataStamp 
    dw      0                   ; MajorVersion 
    dw      0                   ; MinorVersion 
    dd      RVA dll_name        ; RVA,指向DLL名称 
    dd      0                   ; 伊始序号为0 
    dd      1                   ; 只导出叁个函数 
    dd      1                   ; 那么些函数是按名称方式导出的 
    dd      RVA addr_tab        ; 本田UR-VVA,指向导出函数入口地址表 
    dd      RVA name_tab        ; 翼虎VA,指向函数名称地址表 
    dd      RVA ordinal_tab     ; RubiconVA,指向函数索引表 
上边咱们定义DLL名称: 
    dll_name    db      'foo.dll',0     ; DLL名称,编写翻译的文件名能够与它差异 
接下去是导出函数入口地址表和函数名称地址表,大家要导出二个叫_foo的函数: 
    addr_tab    dd      RVA _foo        ; 函数入口地址 
    name_tab    dd      RVA func_name 
    func_name   db      '_foo',0        ; 函数名称 
最终是函数索引表: 
    ordinal_tab     dw      0           ; 独有八个按名称导出函数,序号为0 
上边我们看四个整机的前后相继: 
format  PE GUI 4.0 DLL at 76000000h 
entry   _dll_entry 

下一篇:没有了
友情链接: 网站地图
Copyright © 2015-2019 http://www.tk-web.com. bb电子糖果派对有限公司 版权所有