之所以发这个帖子,是因为在用PEditor添加了API之后不知道如何调用, 参看了《加密与解密(第二版)》,知道了LordPE,可以得到一个ThunkRAV值(IAT表的), 那么ThunkRAV到底是什么?如果不用LordPE,如何得到ThunkRAV呢? 认真看了PE文件格式一章,简单的分析了个简单的CM,终于有些明白了,贴出来,share一下。 注意:对于字和双字,按从右到左读,如:06 21 00 00 指的地址00002106H 程序用UltraEdit打开程序: 00000000h: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 ; MZ?.......... | 00000010h: B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ; ?......@....... | 00000020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000030h: 00 00 00 00 00 00 00 00 00 00 00 00 C8 00 00 00 ; ............?.. | 00000040h: 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68 ; ..?.???L?Th | 00000050h: 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F ; is program canno |Dos文件头 00000060h: 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 ; t be run in DOS | 00000070h: 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 ; mode....$....... | 00000080h: 7B E5 81 D7 3F 84 EF 84 3F 84 EF 84 3F 84 EF 84 ; {???? | 00000090h: B1 9B FC 84 2C 84 EF 84 C3 A4 FD 84 3E 84 EF 84 ; ,?? | 000000a0h: F8 82 E9 84 3E 84 EF 84 52 69 63 68 3F 84 EF 84 ; >ich?? | 000000b0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................| ……1、PE文件头标志 000000c0h: 00 00 00 00 00 00 00 00 50 45 00 00 2、这里开始的20个字节为映像文件头:IMAGE_FILE_HEADER) 4个块 000000c0h: [4C 01 04 00 ; ........PE..L...| 000000d0h: C0 6E 4C 45 00 00 00 00 00 00 00 00 E0 00 0F 01] ; LE........?.. | 3、下面6*16=96个字节是可选映像头(NumberOfRvaAndSizes) 000000e0h:[0B 01 05 0C 00 0C 00 00 00 16 00 00 00 00 00 00 ; ................ | 000000f0h: 00 10 00 00 00 10 00 00 00 20 00 00 00 00 40 00 ; ......... ....@. | 00000100h: 00 10 00 00 00 02 00 00 04 00 00 00 04 00 00 00 ; ................ | 00000110h: 04 00 00 00 00 00 00 00 00 50 00 00 00 04 00 00 ; .........P...... | 00000120h: 6E 5D 00 00 02 00 00 00 00 00 10 00 00 10 00 00 ; n].............. | 这里代表数据目录的项数为0010 00000130h: 00 00 10 00 00 10 00 00 00 00 00 00 10 00 00 00]; ................ |PE文件头 4、下面是数据目录表(DataDirectory),16项,每项8个字节, 特别注意输入表地址是虚拟地址,需要转换为磁盘文件的绝对偏移量再在十六进制编辑器中查找。 方法:首先用工具查看区段信息, 如图“各个段的信息.jpeg”(这个信息当然直接从PE头中可以读出)。 以2040为例,属于.rdata段, 计算它的绝对偏移 = 相对偏移 - (VOffset - ROffset); 则:绝对偏移 = 相对偏移 - (VOffset - ROffset)= 2040 - (2000 - 1000) = 1040 下面是数据目录表(DataDirectory),16项,每项8个字节, 输出表为全0代表没有 输入表地址为0x2040(RVA),大小为0x3C 00000140h: 00 00 00 00 00 00 00 00 40 20 00 00 3C 00 00 00 ; ........@ ..<... | 资源表0x4000,size:0x0D10异常表无 00000150h: 00 40 00 00 10 0D 00 00 00 00 00 00 00 00 00 00 ; .@.............. | 00000160h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000170h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000180h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000190h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 000001a0h: 00 20 00 00 40 00 00 00 00 00 00 00 00 00 00 00 ; . ..@........... | 000001b0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 5、块表(本程序4个块) Name VSize VAddress(VOffset) 000001c0h:[2E 74 65 78 74 00 00 00 FC 0B 00 00 00 10 00 00 ; .text...?...... | RSize ROffset ... 000001d0h: 00 0C 00 00 00 04 00 00 00 00 00 00 00 00 00 00 ; ................ | Flags(Characteristics) 000001e0h: 00 00 00 00 20 00 00 60/2E 72 64 61 74 61 00 00 ; .... ..`.rdata.. | 000001f0h: AC 01 00 00 00 20 00 00 00 02 00 00 00 10 00 00 ; ?... .......... | 00000200h: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 40 ; ............@..@ | 00000210h:/2E 64 61 74 61 00 00 00 28 05 00 00 00 30 00 00 ; .data...(....0.. | 00000220h: 00 04 00 00 00 12 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000230h: 00 00 00 00 40 00 00 C0/2E 72 73 72 63 00 00 00 ; ....@..?rsrc... | 00000240h: 10 0D 00 00 00 40 00 00 00 0E 00 00 00 16 00 00 ; .....@.......... | 00000250h: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 40]; ............@..@ | 00000260h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000270h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000280h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000290h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 000002a0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 000002b0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 000002c0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 000002d0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 000002e0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 000002f0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000300h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000310h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000320h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000330h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000340h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000350h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000360h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000370h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000380h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 00000390h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 000003a0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 000003b0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 000003c0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 000003d0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 000003e0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ | 000003f0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................| 下面是指令的机器码(代码段): 00000400h: 6A 00 E8 CB 0B 00 00 A3 A0 32 40 00 6A 00 68 2C ; j.杷...2@.j.h, 00000410h: 10 40 00 6A 00 68 E8 03 00 00 FF 35 A0 32 40 00 ; .@.j.h?..5?@. 00000420h: E8 89 0B 00 00 6A 00 E8 A0 0B 00 00 55 8B EC 8B ; ...j....U? …… …… …… 00000f30h: 52 6A 50 68 38 34 40 00 E8 A1 00 00 00 68 81 32 ; RjPh84@.琛...h? 00000f40h: 40 00 68 38 34 40 00 E8 A4 00 00 00 5A 01 35 38 ; @.h84@.瑜...Z.58 00000f50h: 34 40 00 01 3D 3C 34 40 00 01 15 40 34 40 00 01 ; 4@..=<4@...@4@.. 00000f60h: 1D 44 34 40 00 A1 44 34 40 00 6A 05 59 33 D2 F7 ; .D4@.4@.j.Y3吟 00000f70h: F1 33 D2 50 A1 38 34 40 00 C1 E8 02 50 A1 3C 34 ; ??4@.凌.P?4 00000f80h: 40 00 6A 03 59 F7 F1 50 A1 40 34 40 00 D1 E8 50 ; @.j.Y黢P4@.谚P 00000f90h: 50 68 7E 32 40 00 68 48 33 40 00 E8 08 00 00 00 ; Ph~2@.hH3@.?... 00000fa0h: 83 C4 0C 83 C4 10 61 C3 FF 25 38 20 40 00 FF 25 ; ..a?%8 @.% 00000fb0h: 34 20 40 00 FF 25 30 20 40 00 FF 25 2C 20 40 00 ; 4 @.%0 @.%, @. 00000fc0h: FF 25 28 20 40 00 FF 25 24 20 40 00 FF 25 1C 20 ; %( @.%$ @.%. 00000fd0h: 40 00 FF 25 00 20 40 00 FF 25 18 20 40 00 FF 25 ; @.%. @.%. @.% 00000fe0h: 14 20 40 00 FF 25 10 20 40 00 FF 25 0C 20 40 00 ; . @.%. @.%. @. 00000ff0h: FF 25 08 20 40 00 FF 25 04 20 40 00 00 00 00 00 ; %. @.%. @..... 到此指令的机器码结束 00001000h: 32 21 00 00 92 21 00 00 86 21 00 00 7A 21 00 00 ; 2!..?..?..z!.. 00001010h: 6E 21 00 00 5E 21 00 00 46 21 00 00 24 21 00 00 ; n!..^!..F!..$!.. 00001020h: 00 00 00 00 06 21 00 00 F8 20 00 00 E6 20 00 00 ; .....!..?..?.. 00001030h: DA 20 00 00 C8 20 00 00 BC 20 00 00 00 00 00 00 ; ?..?..?...... // 经过4的计算,下面开始是输入地址表(Import Table),每5个双字(20个字节)为一个IID,以一个全为0的IID结束 // 本程序的输入地址表包含两个IID,第三个为全0,作为结束 00001040h:[A0 20 00 00 00 00 00 00 00 00 00 00 18 21 00 00 ; ?...........!.. 00001050h: 24 20 00 00/7C 20 00 00 00 00 00 00 00 00 00 00 ; $ ..| .......... 00001060h: 9E 21 00 00 00 20 00/00 00 00 00 00 00 00 00 00 ; ?... .......... 00001070h: 00 00 00 00 00 00 00 00 00 00 00 00] 输入地址表结束 32 21 00 00 ; ............2!.. 简单分析下:OrignalFirstThunk TimeDateStamp ForwardChain Name FirstThunk 00001040h: A0 20 00 00 00 00 00 00 00 00 00 00 18 21 00 00 24 20 00 00 相对偏移: 0x20A0H 0x2118H 0x2024H 绝对偏移: 0x10A0H 0x1118H 在程序运时被初始化 user32.dll OrignalFirstThunk指向的是一个IMAGE_THUNK_DATA的结构,不可改写,叫INT(Hint-Name Table提名表) FirstThunk指向也是一个IMAGE_THUNK_DATA的结构,PE装载器重写,叫IAT(Import Address Table输入地址表) 程序执行的时候通过INT指向的名字寻址(如果赋值为0直接根据IAT的字符串寻址),并找到的输入函数入口地址改写IAT结构 因此在添加API之后,要使用IAT地址来调用API(在LordPE中勾选总是查看FirstThunk) FirstThunk中函数名的顺寻应该和OrignalFirstThunk相同,都是在FirstThunk(OrignalFirstThunk)的基础上加4(双字大小), 如本程序: OrignalFirstThunk FirstThunk API Name 000020A0 00002024 SetDlgItenTextA 000020A4 00002028 MessageBoxA 000020A8 0000202C GetDlgItenTextA 000020AC 00002030 EndDialog …… 顺序和IMAGE_THUNK_DATA数组的顺寻相同,和绝对地址的存放顺序相反(猜想可以推广) 那么解决了一个问题,用PEditor的时候,没有发现LordPE中“总是查看FirstThunk”的功能,好,现在可以自己计算了。 如图:计算ThunkRAV ( 用 Call [基址 +ThunkRAV] 调用API) 00001080h: 92 21 00 00 86 21 00 00 7A 21 00 00 6E 21 00 00 ; ?..?..z!..n!.. 00001090h: 5E 21 00 00 46 21 00 00 24 21 00 00 00 00 00 00 ; ^!..F!..$!...... 输入表的OrignalFirstThunk指向的IMAGE_THUNK_DATA数组,这个数组都是指针,以00结束: 000010a0h:[06 21 00 00 F8 20 00 00 E6 20 00 00 DA 20 00 00 ; .!..?..?..?.. 000010b0h: C8 20 00 00 BC 20 00 00 00 00 00 00] IMAGE_THUNK_DATA数组结束 62 02 77 73 ; ?..?......b.ws 06 21 00 00 F8 20 00 00 E6 20 00 00 DA 20 00 00 C8 20 00 00 BC 20 00 00 00 00 00 00 相对偏移: 2106 20F8 20E6 20DA 20C8 20BC 0000 绝对偏移: 1106 10F8 10E6 10DA 10C8 10BC 0000 对应函数:SetDlgItenTextA MessageBoxA SetDlgItenTextA EndDialog DialogBoxParamA wsprintfA 000010c0h: 70 72 69 6E 74 66 41 00 8A 00 44 69 61 6C 6F 67 ; printfA.?Dialog 000010d0h: 42 6F 78 50 61 72 61 6D 41 00 AD 00 45 6E 64 44 ; BoxParamA.?EndD 000010e0h: 69 61 6C 6F 67 00 F4 00 47 65 74 44 6C 67 49 74 ; ialog.?GetDlgIt 000010f0h: 65 6D 54 65 78 74 41 00 9D 01 4D 65 73 73 61 67 ; emTextA.?Messag 00001100h: 65 42 6F 78 41 00 F8 01 53 65 74 44 6C 67 49 74 ; eBoxA.?SetDlgIt 00001110h: 65 6D 54 65 78 74 41 00 75 73 65 72 33 32 2E 64 ; emTextA.user32.d 00001120h: 6C 6C 00 00 80 00 45 78 69 74 50 72 6F 63 65 73 ; ll...ExitProces 00001130h: 73 00 09 01 47 65 74 4D 6F 64 75 6C 65 48 61 6E ; s...GetModuleHan 00001140h: 64 6C 65 41 00 00 5C 01 47 65 74 56 6F 6C 75 6D ; dleA..\.GetVolum 00001150h: 65 49 6E 66 6F 72 6D 61 74 69 6F 6E 41 00 0B 02 ; eInformationA... 00001160h: 52 74 6C 5A 65 72 6F 4D 65 6D 6F 72 79 00 B5 02 ; RtlZeroMemory.? 00001170h: 6C 73 74 72 63 61 74 41 00 00 B7 02 6C 73 74 72 ; lstrcatA..?lstr 00001180h: 63 6D 70 41 00 00 BB 02 6C 73 74 72 63 70 79 41 ; cmpA..?lstrcpyA 00001190h: 00 00 BF 02 6C 73 74 72 6C 65 6E 41 00 00 6B 65 ; ..?lstrlenA..ke 000011a0h: 72 6E 65 6C 33 32 2E 64 6C 6C 00 00 00 00 00 00 ; rnel32.dll...... 000011b0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ 000011c0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ 000011d0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ 000011e0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ 000011f0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................ 00001200h: 20 20 20 20 2D 3D 41 75 74 68 6F 72 3A 20 6C 61 ; -=Author: la 00001210h: 6E 67 78 61 6E 67 3D 2D 0D 20 2D 3D 45 6D 61 69 ; ngxang=-. -=Emai 00001220h: 6C 3A 6C 61 6E 67 78 61 6E 67 40 31 32 36 2E 63 ; l:langxang@126.c 00001230h: 6F 6D 3D 2D 00 61 62 6F 75 74 00 C7 EB CA E4 C8 ; om=-.about.请输? 00001240h: EB D7 A2 B2 E1 C2 EB 3F 00 B9 D8 D3 DA 00 D7 A2 ; 胱⒉崧?.关于.注 00001250h: B2 E1 C2 EB B4 ED CE F3 A3 A1 00 B9 A7 CF B2 C4 ; 册码错误!.恭喜? 00001260h: E3 A3 AC D7 A2 B2 E1 B3 C9 B9 A6 A3 A1 00 00 00 ; 悖⒉岢晒Γ?.. …… …… ……