菜鸟也学输入表
2147 点击·0 回帖
![]() | ![]() | |
![]() | 关于导入表: 可执行文件使用来自于其他dll的代码或数据时,称为输入。当PE文件装入时, Windows加载器的工作之一就是定位所有被输入的函数和数据,并且让正在被装入的 PE文件可以使用那些地址。这个过程是通过PE文件的输入表(Import Tab 也称之为 导入表)完成的,输入表中保存的是函数名和其驻留的dll名等,动态连接所需输信息, 输入表在软件外壳技术上的地位十分重要,因此在研究外壳的技术时一定要掌握这部分 知识。 学习输入表要先从整个PE文件说起, -------------*-------------------------------------------------* | DOS Header(IMAGE_DOS_HEADER) | -->64 Byte DOS头部 -------------------------------------------------- | DOS Stub | -->112 Byte -------------*-------------------------------------------------* | "PE"00 (Signature) | -->4 Byte ------------------------------------------------- | IMAGE_FILE_HEADER | -->20 Byte PE文件头-------------------------------------------------- | IMAGE_OPTIONAL_HEADER32 | -->96 Byte --------------------------------------------------- | 数据目录表 | -->128 Byte -------------*--------------------------------------------------* | IMAGE_SECTION_HEADER | -->40 Byte --------------------------------------------------- 块表 | IMAGE_SECTION_HEADER | -->40 Byte -------------------------------------------------- | IMAGE_SECTION_HEADER | -->40 Byte -------------*--------------------------------------------------* |.text | -->512 Byte --------------------------------------------------- 块 |.rdata | -->512 Byte --------------------------------------------------- |.data | -->512 Byte -------------*-------------------------------------------------* | COFF行号 | -->NULL --------------------------------------------------- 调试信息| COFF符号表 | -->NULL --------------------------------------------------- | Code View 调试信息 | -->NULL -------------*--------------------------------------------------* --------->>>摘自互联网(方舟子把我们搞的人心惶惶的,我等菜鸟写点东西都心惊胆战)上面就是一个简单的PE结构图(附件里我会附带一个比较详细的PE结构图供菜菜们娱乐), 我们来找出和输入表有关的区段和数据结构以及他们在PE文件中的位置。 1.IMAGE_NT_HEADER->IMAGE_OPTIONAL_HEADER32->第104个字节(也就是数据目录表的IMAGE_DIRECTORY_ENTRY_IMPORT) :struct _IMAGE_DATA_DIRECTORY{Dword VirtualAdress; Dword Size;}; 该结构第一个成员是指向.idata区段首地址。 2.节表 .idata typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; union { Dword PhysicalAddress; Dword VirtualSize; } Misc; Dword VirtualAddress; Dword SizeOfRawData; Dword PointerToRawData; Dword PointerToRelocations; Dword PointerToLinenumbers; word NumberOfRelocations; word NumberOfLinenumbers; Dword Characteristics; }; 第五个成员表示该区段在文件中的起始地址。 3. .idata区段中 参考附件中的图片。 typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { Dword Characteristics; // 0 for terminating null import descriptor Dword OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA) }; 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; //传说中的IID结构。 这个结构很重要,我们一个一个成员来分析 1)指向输入名称表(简称INT)的RVA,INT是一个IMAGE_THUNK_DATA结构数组,数组中的每一个IMAGE_THUNK_DATA结构指向IMAGE_IMPORT_BY_NAME结构,数组最后一个内容是内容为0的IMAGE_THUNK_DATA。 typedef struct _IMAGE_IMPORT_BY_NAME { word Hint; BYTE Name[1]; } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; 成员1: word Hint;指示本函数在其所驻留dll的输入表中的序号。该域被PE装载器 用来在DLL的输出表里快速查询函数。该值不是必须的,一些链接器将此值设为0. 成员2: BYTE Name[1];含有输入函数的函数名,函数名是一个ASCII码字符串 2)32位时间标志。 3)这个是第一个被转向的API的索引,一般为0。 4)DLL的名字的指针,是一个以00结尾的ASCII字符的RVA地址,例如”kernel32.dll” 5)包含指向输入地址表(IAT)的RVA。IAT是一个IMAGE_THUNK_DATA数组。 成员1同成员5非常相似,他们指向两个本质上相同的数组IMAGE_THUNK_DATA。 以上便是PE中和输入表相关的数据结构 ![]() ![]() ![]() ![]() | |
![]() | ![]() |