PE文件结构(三) 输入表

PE文件结构(三)

參考

书:《加密与解密》

视频:小甲鱼 解密系列 视频

输入表

输入函数,表示被程序调用可是它的代码不在程序代码中的,而在dll中的函数。对于这些函数。磁盘上的可执行文件仅仅是保留相关的函数信息,如函数名,dll文件名称等。

在程序执行前。程序是没有保存这些函数在内存中的地址。当程序执行起来时。windows载入器会把相关的dll装入内存。而且将输入函数的指令与函数真在内存中正的地址联系起来。输入表(导入表)就是用来保存这些函数的信息的。

在   IMAGE_OPTIONAL_HEADER 中的 DataDirectory[16]  数组保存了 输入表的RVA跟大小。

通过RVA能够在OD中载入程序通过 ImageBase+RVA 找到 输入表,或者通过RVA计算出文件偏移地址,查看磁盘中的可运行文件,通过文件偏移地址找到输入表。

输入表是以一个IMAGE_IMPORT_DESCRIPTOR(IID)数组 開始的。每个被PE文件隐式的链接进来的dll都有一个IID。IID数组的最后一个单元用NULL表示。

IMAGE_IMPORT_DESCRIPTOR 结构:

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
	_ANONYMOUS_UNION union {              //00h
		DWORD Characteristics;
		DWORD OriginalFirstThunk;
	} DUMMYUNIONNAME;
	DWORD TimeDateStamp;                  //04h
	DWORD ForwarderChain;                 //08h
	DWORD Name;                           //0Ch
	DWORD FirstThunk;                     //10h
} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;

当中Name是dll名字的指针。OriginalFirstThunk指向一个IMAGE_THUNK_DATA数组叫做输入名称表Import Name Table(INT),用来保存函数,FirstThunk也指向IMAGE_THUNK_DATA数组叫做输入地址表Import Address Table(IAT)。

IMAGE_THUNK_DATA 结构:

typedef struct _IMAGE_THUNK_DATA32 {
	union {
		DWORD ForwarderString;
		DWORD Function;
		DWORD Ordinal;
		DWORD AddressOfData;
	} u1;
} IMAGE_THUNK_DATA32,*PIMAGE_THUNK_DATA32;

当IMAGE_THUNK_DATA 的值最高位为1时,表示函数是以序号方式输入。这时低31为被当作函数序号。当最高位是0时,表示函数是以字符串类型的函数名方式输入的,这时。IMAGE_THUNK_DATA 的值为指向 IMAGE_IMPORT_BY_NAME 的结构的RVA。

typedef struct _IMAGE_IMPORT_BY_NAME {
	WORD Hint;
	BYTE Name[1];
} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME;

Hint 表示这个函数在其所驻留dll的输出表的序号。不是必须的。

Name 表示 函数名,是一个ASCII字符串以0结尾,大小不固定。

INT保存的是这个程序导入这个dll中函数信息,它是固定的不会被改动。可是IAT会在程序载入时被重写,当程序载入时,它会被PE载入器重写成 这些函数的在内存中的真正地址。

即把它原来指向的IMAGE_IMPORT_BY_NAME 改成 函数真正的地址。

那为什么要两个 IMAGE_THUNK_DATA 数组?

当程序载入时,IAT 会被PE载入器重写。PE载入器先搜索INT,PE载入器迭代搜索INT数组中的每一个指针。找出 INT所指向的IMAGE_IMPORT_BY_NAME结构中的函数在内存中的真正的地址。并把它替代原来IAT中的值。

当完毕后,INT就没实用了,程序仅仅须要IAT就能够正常执行了。

看以下图,这个是可运行程序在磁盘中的时候:

这个是当程序被载入的是后:

实例分析:

先找到输入表RVA,通过IMAGE_OPTIONAL_HEADER 中的最后一个项  IMAGE_DATA_DIRECTORY 能够知道 输入表相对与PE文件头的偏移量为80h能够找到输入表达RVA。

图片1

但这个是RVA不是文件偏移地址。

通过转换能够知道。输入表的文件偏移地址为850h。

查看850h。即IID,能够看到这个程序有两个IID。即链接了 两个dll,看到一个IID,能够知道它的OriginalFirstThunk 是 2098h  FirstThunk  为200Ch,它们转换后的文件偏移地址分别为898h 和 80Ch

图片2  IID数组

查看OriginalFirstThunk跟FirstThunk 。能够发现这里INT跟IAT的内容是一样的。先看看第一个函数的信息,由于第一位为1,所以这里00002122h 表示 IMAGE_IMPORT_BY_NAME 的RVA,转化为文件偏移值为922h

图片3  INT跟IAT

查看922h 能够看函数名。

图片4:

我们能够从上面看到程序在磁盘中时 INT 与IAT内容一样,都是指向 IMAGE_IMPORT_BY_NAME 。

用OD载入程序,查看INT与IAT的内容

图片5 INT

图片6 IAT

能够发现INT没有发生变化。IAT变成了比如77D3C702h,IAT中的RVA被改成了函数的真正的地址。

查看77D3C702h,就能够看到这个函数

图片7

时间: 2024-10-21 21:15:17

PE文件结构(三) 输入表的相关文章

获取PE文件的输入表信息

输入表是PE文件结构中不可或缺的部分,输入表也称之为"导入表". 要想了解输入表,首先还得先从DLL文件入手.日常生活中我们会看见一些大型软件有很多的DLL格式的文件,这些文件中有很多的导入函数,这些函数不会直接被执行.当一个程序(EXE)运行时,导入函数是被程序调用执行的,其执行的代码是不在主程序(EXE)中的一小部分函数,其真正的代码却在DLL文件中.这时我们就会想,那么EXE主程序是如何找到这些需要导入的函数呢,这就要归结于“输入表”了,输入表就相当于EXE文件与DLL文件沟通的

PE文件结构学习

PE:Portable Executable File Format(可移植的执行体).Windows平台主流可执行文件格式..exe与.dll文件都是PE格式.32位的叫做PE32,64位的叫做PE32+.PE文件格式定义在winnt.h头文件中. PE文件格式总览: PE文件使用的是一个平面地址空间,所有代码和数据都被合并在一起,组成一个很大的结构.文件的内容被分割为不同的区块(Section,又名区段,节等),区块中包含代码或数据,各个区块按页边界来对齐,区块没有大小限制,是一个连续的结构

PE文件结构详解(四)PE导入表

PE文件结构详解(二)可执行文件头的最后展示了一个数组,PE文件结构详解(三)PE导出表中解释了其中第一项的格式,本篇文章来揭示这个数组中的第二项:IMAGE_DIRECTORY_ENTRY_IMPORT,即导入表. 也许大家注意到过,在IMAGE_DATA_DIRECTORY中,有几项的名字都和导入表有关系,其中包括:IMAGE_DIRECTORY_ENTRY_IMPORT,IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,IMAGE_DIRECTORY_ENTRY_IAT

[DLL注入的方法]静态修改PE输入表法

1.三种DLL加载时机: 进程创建加载输入表中的DLL(静态输入) 通过调用LoadLibrary主动加载(动态加载) 系统预设加载 通过干预输入表处理过程加载目标dll 1.静态修改PE输入表法(测试程序 Notepad.exe) 准备工作:自行编写一个MsgDLL,到处一个函数Msg(); #include "stdafx.h" BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpRe

小甲鱼PE详解之输入表(导入表)详解(PE详解07)

捷径并不是把弯路改直了,而是帮你把岔道堵上! 走得弯路跟成长的速度是成正比的!不要害怕走上弯路,弯路会让你懂得更多,最终还是会在终点交汇! 岔路会将你引入万劫不复的深渊,并越走越深…… 在开始讲解输入表(导入表)概念之前,请允许小甲鱼童鞋用简短的几句话来总结之前我们学过的内容,并做进一步的思想综合提升,注意咯! 首先,我们知道PE 文件中的数据被载入内存后根据不同页面属性被划分成很多区块(节),并有区块表(节表)的数据来描述这些区块.这里我们需要注意的问题是:一个区块中的数据仅仅只是由于属性相同

PE文件结构(四) 输出表

PE文件结构(四) 参考 书:<加密与解密> 视频:小甲鱼 解密系列 视频 输出表 一般来说输出表存在于dll中.输出表提供了 文件中函数的名字跟这些函数的地址, PE装载器通过输出表来修改IAT. IMAGE_OPTIONAL_HEADER中的 DataDirectory[0] 提供了输出表的RVA.输出表是以一个IMAGE_EXPORT_DIRECTORY结构 开始的. IMAGE_EXPORT_DIRECTORY结构: typedef struct _IMAGE_EXPORT_DIREC

PE文件结构(三)

参考 书:<加密与解密> 视频:小甲鱼 解密系列 视频 输入表 输入函数,表示被程序调用但是它的代码不在程序代码中的,而在dll中的函数.对于这些函数,磁盘上的可执行文件只是保留相关的函数信息,如函数名,dll文件名等.在程序运行前,程序是没有保存这些函数在内存中的地址.当程序运行起来时,windows加载器会把相关的dll装入内存,并且将输入函数的指令与函数真在内存中正的地址联系起来.输入表(导入表)就是用来保存这些函数的信息的. 在   IMAGE_OPTIONAL_HEADER 中的 D

PE文件结构详解(三)PE导出表

上篇文章 PE文件结构详解(二)可执行文件头 的结尾出现了一个大数组,这个数组中的每一项都是一个特定的结构,通过函数获取数组中的项可以用RtlImageDirectoryEntryToData函数,DataDirectory中的每一项都可以用这个函数获取,函数原型如下: PVOID NTAPI RtlImageDirectoryEntryToData(PVOID Base, BOOLEAN MappedAsImage, USHORT Directory, PULONG Size); Base:模

PE文件结构详解(五)延迟导入表

PE文件结构详解(四)PE导入表讲 了一般的PE导入表,这次我们来看一下另外一种导入表:延迟导入(Delay Import).看名字就知道,这种导入机制导入其他DLL的时机比较“迟”,为什么要迟呢?因为有些导入函数可能使用的频率比较低,或者在某些特定的场 合才会用到,而有些函数可能要在程序运行一段时间后才会用到,这些函数可以等到他实际使用的时候再去加载对应的DLL,而没必要再程序一装载就初始化好. 这个机制听起来很诱人,因为他可以加快启动速度,我们应该如何利用这项机制呢?VC有一个选项,可以让我