Windows复习笔记

#Windows复习笔记
@()[PE]

文章目录


##1. PE结构
###1.1 DosHeader

###1.2 NtHeader
###1.3 Sections

  • 有多少个节就有多少个节表,节表的个数存在于文件头

节表描述了在内存中,每个节块的具体属性
节表结构体如下 :

typedef struct _IMAGE_SECTION_HEADER{
	BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; // 8个字节,一般情况下以"\0"结尾,内容可以自定义
	union{
		DWORD PhysicalAddress;
		DWORD VirtualSize;
	}Misc; // 双字,是该节块在内存中【没有】对齐前的真实尺寸,可以不准确
	DWORD VirtualAddress; // 节块在内存中的偏移地址,加上ImageBase才是内存中的真正地址
	DWORD SizeOfRawData; // 节块在文件中对齐后的尺寸
	DWORD PointerToRawData; // 节块在文件中的偏移
	DWORD PointerToRelocations; // 在obj文件中使用  对exe无意义
	DWORD PointerToLinenumbers; // 行号表的位置 调试的时候使用
	WORD  NumberOfRelocations; // 在obj文件中使用  对exe无意义
	WORD  NumberOfLinenumbers; // 行号表中行号的数量 调试的时候使用
	DWORD Characteristics; // 接的属性(可读\可写\可执行)
}

节块的类型如下 :

名称描述
.text段一般是代码段
.data段一般是数据段
.bss段表示未初始化的数据,如static变量,可能是进入一个函数才被初始化的
.rdata段表示只读的数据,比如字符串
.textbss段和代码有关
.idata和.edata段储存导入表和导出表的信息
.rsrc段存储资源的区段(节)
.reloc段存储重定位表信息的区段

-**节块从文件中到内存中拉伸视图, 如下 : **
在这里插入图片描述
###1.4 导出表
注意
-导入表可能有多个,但导出表只有一个
-数据目录项的第一个结构存储导出表的偏移
-真正导出的序号等于Base + 函数地址表下标
-函数名称表是按名称排列的,A 开头的函数在AddressOfNames中排在最前面,但A开头函数真正的地址可能排在B开头函数后面

导出表的结构体如下 :

typedef struct _IMAGE_EXPORT_DIRECTORY{
	DWORD   Characteristics;
	DWORD   TimeDateStamp; // 时间戳
	WORD    MajorVersion;
	WORD    MinorVersion;
	DWORD   Name; // 指向该导出表文件名字符串
	DWORD   Base; // 导出函数其实序号
	DWORD   NumberOfFunctions; // 所有导出函数的个数
	DWORD   NumberOfNames; // 以函数名称导出的函数个数
	DWORD   AddressOfFunctions;     // 导出函数地址表RVA
	DWORD   AddressOfNames;         // 导出函数名称表RVA
	DWORD   AddressOfNameOrdinals;  // 导出函数序号表RVA
}

Alt text
###1.5 导入表
注意

  • 数据目录项第二个结构存储导入表起始的偏移
  • **优点,启动程序速度快。缺点,若程序没有占到指定位置,需要修改IAT表中地址内容 **

导入表结构如下 :

typedef struct _IMAGE_IMPORT_DESCRIPTOR{
	union{
		DWORD  Characteristics;
		DWORD  OriginalFirstThunk; // RVA 指向IMAGE_THUNK_DATA结构数组
	};
	DWORD TimeDateStamp; // 时间戳, 若为0表示没有绑定导入表,为-1绑定了导入表, 而真正的绑定时间存在另外一张表里
	DWORD ForwarderChain; 
	DWORD   Name; // RVA, 指向dll名称,该名称已0结尾
	DWORD   FirstThunk; // RVA, 指向IMAGE_THUNK_DATA结构数组
}

PE文件加载前 :
Alt text
PE文件加载后 :
Alt text

  1. 从图中可以看出在文件中INT表和IAT表的内容是一致的(除去绑定导入表)
  2. 在内存中会根据INT表中函数名称查找函数对应的地址赋值给IAT表
    ####1.5.1 绑定导入表(了解就行)
  • 数据目录项第12个结构存储绑定导入表的偏移

绑定导入表的作用是加快程序的启动速度,一个PE程序在启动时回去加载导入表中的dll文件,根据INT表的内容依次查询函数地址,赋值给IAT。这需要消耗时间,绑定导入表中存储了导入函数真实地址,所以当PE在启动时检测到有绑定导入表,会直接将绑定导入表地址存入FirstThunk中。

绑定导入表结构 :

typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR{
	DWORD TimeDateStamp; // 时间戳
	WORD  OffsetModuleName; // 相对于绑定导入表首地址的RVA,存储的是DLL的名称
	WORD  NumberOfModuleForwarderRefs; // 后面跟随着的_IMAGE_BOUND_FORWARDER_REF个数
	// _IMAGE_BOUND_FORWARDER_REF[...];
}IMAGE_BOUND_IMPORT_DESCRIPTOR,  *PIMAGE_BOUND_IMPORT_DESCRIPTOR;
typedef struct _IMAGE_BOUND_FORWARDER_REF{
	DWORD TimeDateStamp;
	WORD  OffsetModuleName;
	WORD  Reserved;
}IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF;

###1.6 重定位表

注意 :
  一般情况下,EXE都是按照ImageBase的地址进行加载的,因为EXE拥有自己独立的4GB的虚拟内存空间,但DLL不是,DLL只有EXE使用它,才会被加载到相关EXE的进程空间。
  而无论是ImageBase还是RVA都在程序编译完成,已经被写入到文件中了。也就是说,如果程序能按照预定的ImageBase来加载的话,那么就不需要重定位表,这也是exe很少有重定位表,而Dll却大多数都有重定位表。


  • 数据目录项第6个结构存储重定位表的偏移
  • 重定位表不止一个
typedef struct _IMAGE_BASE_RELOCATION{
	DWORD VirtualAddress; // 偏移的基地址
	DWORD SizeOfBlock; // 当前块有多大
}IMAGE_BASE_RELOCATION;

Alt text
###1.7 资源表

  • 数据目录项第3个结构存储资源表的偏移

存储PE文件中的资源包括图片、菜单、图标等等。

###1.7 TLS表(线程本地存储表)

  • 数据目录项第10个结构存储TLS表的偏移

通常一个包含了TLS表的程序,它就会拥有".tls"段这个段里面保存了变量和回调函数的数据,但是TLS表本身的结构体一般存在于".rdata"段内
  TLS里面的变量和回调函数都在程序入口点(AddressOfEntry)之前执行,也就是说程序在被调试时,还没有在入口点处断下来之前,TLS中的变量和回调函数就已经执行完了,所以TLS可以用作反调试之类的操作

__declspec (thread) int g_nNum = 0x111; // 静态创建

typedef struct _IMAGE_TLS_DIRECTORY32 {
    DWORD   StartAddressOfRawData; // tls模板在内存中的起始VA,模板是用于创建线程时初始化TLS数据的
    DWORD   EndAddressOfRawData; // tls模板在内存中的结束VA
    PDWORD  AddressOfIndex; // 存储TLS索引的位置
    PIMAGE_TLS_CALLBACK *AddressOfCallBacks; // 指向TLS注册的回调函数的函数指针数组
    DWORD   SizeOfZeroFill; // 用0填充TLS变量区域的大小
    DWORD   Characteristics; // 保留
} IMAGE_TLS_DIRECTORY32;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值