IMAGE_DOS_HRADER_STRUCT ----- { Size 40H } -> e_lfanew 指向PE文件头
nt!_IMAGE_NT_HEADERS
+0x000 Signature : Uint4B /PE文件标识
+0x004 FileHeader : _IMAGE_FILE_HEADER
+0x018 OptionalHeader : _IMAGE_OPTIONAL_HEADER
nt!_IMAGE_FILE_HEADER
+0x000 Machine : Uint2B //运行平台
+0x002 NumberOfSections : Uint2B //文件的区块数目
+0x004 TimeDateStamp : Uint4B //文件创建日期与时间
+0x008 PointerToSymbolTable : Uint4B //指向符号表
+0x00c NumberOfSymbols : Uint4B //符号表中符号个数
+0x010 SizeOfOptionalHeader : Uint2B //IMAGE_OPTIONAL_HEADER结构大小
+0x012 Characteristics : Uint2B //文件属性
nt!_IMAGE_OPTIONAL_HEADER
+0x000 Magic : Uint2B //标志字
+0x002 MajorLinkerVersion : UChar //连接器主版本号
+0x003 MinorLinkerVersion : UChar //连接器次版本号
+0x004 SizeOfCode : Uint4B //所有含有代码区块的总大小
+0x008 SizeOfInitializedData : Uint4B //所有初始化数据区块总大小
+0x00c SizeOfUninitializedData : Uint4B //所有未初始化数据区块总大小
+0x010 AddressOfEntryPoint : Uint4B //程序执行入口RVA
+0x014 BaseOfCode : Uint4B //代码区块起始RVA
+0x018 BaseOfData : Uint4B //数据区块起始RVA
+0x01c ImageBase : Uint4B //程序默认装载基地址
+0x020 SectionAlignment : Uint4B //内存中区块的对齐值
+0x024 FileAlignment : Uint4B //文件中区块的对齐值
+0x028 MajorOperatingSystemVersion : Uint2B //操作系统主版本号
+0x02a MinorOperatingSystemVersion : Uint2B //操作系统次版本号
+0x02c MajorImageVersion : Uint2B //用户自定义主版本号
+0x02e MinorImageVersion : Uint2B //用户自定义次版本号
+0x030 MajorSubsystemVersion : Uint2B //所需要子系统的版本号
所需要子系统的次版本号
+0x034 Win32VersionValue : Uint4B //保留
+0x038 SizeOfImage : Uint4B //映像装入后的总尺寸
+0x03c SizeOfHeaders : Uint4B //Dos头,Pe头部,区块表总大小
+0x040 CheckSum : Uint4B //映像效验和
+0x044 Subsystem : Uint2B //文件子系统
+0x046 DllCharacteristics : Uint2B //显示DLL特征的旗标
+0x048 SizeOfStackReserve : Uint4B //初始化堆栈大小
+0x04c SizeOfStackCommit : Uint4B //初始化实际提交堆栈大小
+0x050 SizeOfHeapReserve : Uint4B //初始化保留堆栈大小
+0x054 SizeOfHeapCommit : Uint4B //初始化实际保留堆栈大小
+0x058 LoaderFlags : Uint4B //与调试相关,通常设置0
+0x05c NumberOfRvaAndSizes : Uint4B //数据目录表的项数
+0x060 DataDirectory : [16] _IMAGE_DATA_DIRECTORY //指向导出导入表 重定位表等.
nt!_IMAGE_DATA_DIRECTORY
+0x000 VirtualAddress : Uint4B //数据块初始的RVA
+0x004 Size : Uint4B //数据块的长度
_IMAGE_NT_HEADERS后面紧跟着——IMAGE_SECTION_HEADER结构
nt!_IMAGE_SECTION_HEADER
+0x000 Name : [8] UChar //8个字节的块名
+0x008 Misc : __unnamed //区块尺寸
+0x00c VirtualAddress : Uint4B //区块的RVA地址
+0x010 SizeOfRawData : Uint4B //在文件中对齐后的尺寸
+0x014 PointerToRawData : Uint4B //在文件中偏移
+0x018 PointerToRelocations : Uint4B //在OBJ文件中使用。重定位的偏移
+0x01c PointerToLinenumbers : Uint4B //行号表的偏移
+0x020 NumberOfRelocations : Uint2B //在OBJ文件中使用,重定位项数目
+0x022 NumberOfLinenumbers : Uint2B //行号表中行号的数目
+0x024 Characteristics : Uint4B // 区块的属性
输入表
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
DWORD OriginalFirstThunk; //它指向first thunk,IMAGE_THUNK_DATA,该thunk拥有Hint和Function name的地址。
DWORD TimeDateStamp; //如果那里有绑定的话它包含时间/数据戳
DWORD ForwarderChain; //在老版的绑定中,它引用API的第一个forwarder chain(传递器链表)。
DWORD Name; //DLL 名称的相对虚地址
DWORD FirstThunk; //IMAGE_THUNK_DATA定义的 first thunk数组的相对地址
} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR;
#define IMAGE_NT_SIGNATURE 0X00004550
"PE\0\0" 字串是PE文件头的开始
IMAGE_FILE_HEADER ---- { Size 14H }
IMAGE_OPTIONAL_HEADER ---- { Size 60H}
IMAGE_DATA_DIRECTORY ---- { Size 80H}
区块
IMAGE_SECTION_HEADER ---- { Size 28H}
输入表结构
IMAGE_IMPORT_DESCRIPTOR -- FirstThunk 包含指向输入地址表的RVA。
IMAGE_THUNK_DATA 值得最高位为1时,表示函数以序号方式输入,这时低31位被看做是一个函数富豪。当双子的最高位为0时,表示函数以字符串类型的函数名方式输入,这时双子的值是一个RVA,指向一个IMAGE_IMPORT_BY_NAME结构
IMAGE_IMPORT_BY_NAME - Name的大小定义为字节 它是可变长寸域。
文件偏移 = RVA(相对虚拟地址) - (Voffset(虚拟偏移)-Roffset(物理偏移))
![图片]()
![图片]()
640H(文件偏移)=2040H - (2000H-600H)
![图片]()
输入表 IID 数组 每个IID包含5个双字
OrignalFirstThunk TimeDataStmp ForwardChan Name FirstThunk
0000208C 00000000 00000000 00002174 00002010
................
Name的文件偏移 774 = 2174-1A00
![图片]()
输入表分析
绑定输入
IMAGE_BOUND_IMPORT_DESCRIPTOR
typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR {
DWORD TimeDateStamp;//包含一个呗输入DLL的时间/日期;允许加载器快速判断绑定是不是新的
WORD OffsetModuleName;//包含一个指向被输入DLL的名称的偏移。这个字段是与第一个IBID结构之间的偏移.
WORD NumberOfModuleForwarderRefs; //它包含紧跟在这个结构后面的IMAGE_BOUND_PORWARDER_REF结构的数目。
} IMAGE_BOUND_IMPORT_DESCRIPTOR, *PIMAGE_BOUND_IMPORT_DESCRIPTOR;
基地址重定义
在.reloc区段
![图片]()
资源结构
该指针具体位置是在PE文件头的88H 资源结构RVA = PE头起始位置+88H
typedef struct _IMAGE_RESOURCE_DIRECTORY {
DWORD Characteristics;//理论上是资源的属性标志,但通常为0
DWORD TimeDateStamp;//资源建立的时间
WORD MajorVersion;//理论上放置资源的版本,但通常为0
WORD MinorVersion;
WORD NumberOfNamedEntries;//使用名字的资源条目的个数
WORD NumberOfIdEntries;//使用ID数字资源条目的个数
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
union {
//该字段目录项的名称字符串指针或ID。当结构用于第一层目录时,定义的是资源类型;
//当结构用于第二层目录时,定义的是资源的名称;当结构用于第三层目录时,定义的是代码
//页编码,当最高位是0时,表示字段的值作为ID使用;而最高位为1时,字段的地位作为指针
//使用,资源名称字符串是食用UNICODE编码,这个指针并不是直接指向字符串,而是指向一个
//IMAGE_RESOURCE_DIR_STRING_U结构.
struct {
DWORD NameOffset:31;
DWORD NameIsString:1;
};
DWORD Name;
WORD Id;
};
union {
DWORD OffsetToData;//资源数据偏移地址或目录偏移地址
//该字段是一个指针,最高位为1时,低位数据指向下一层目录块的起始地址;而最高位为1
//时,指针指向IMAGE_RESOURCE_DATA_ENTRY结构.
struct {
DWORD OffsetToDirectory:31;
DWORD DataIsDirectory:1;
};
};
} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;
typedef struct _IMAGE_RESOURCE_DIR_STRING_U {
WORD Length;//字符串长度
WCHAR NameString[ 1 ];//UNICODE字符串,字对其的,长度是可变的,由Length指明长度.
} IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U;
![图片]()
下一10H _IMAGE_RESOURCE_DIRECTORY_ENTRY 分别是 800000A8
表示下面有资源 继续进入第三层
分别指向 资源的地址 和 大小
TLS初始化
typedef struct _IMAGE_TLS_DIRECTORY32 {
DWORD StartAddressOfRawData;//内存起始地址,用于初始化一个新线程的TLS
DWORD EndAddressOfRawData;//内存终止地址,用于初始化一个新线程的TLS
PDWORD AddressOfIndex;//运行库使用这个索引来定位线程局部变量
PIMAGE_TLS_CALLBACK *AddressOfCallBacks;//PIMAGE_TLS_CALLBACK函数指针数组的地址
DWORD SizeOfZeroFill;//后面跟零个数
DWORD Characteristics;//保留
} IMAGE_TLS_DIRECTORY32;
AddressOfCallBack是iancheng简历和退出iho的回调函数,包括主线程哦其他线程。当一个线程诶创建或销毁时,在列表中的每一个函数被调用,一般程序都没有回调函数,这个列表是空的。有一点特别注意,程序运行时,TLS数据初始化和TLS回调函数都在入口点之前执行,也就是说,TLS是程序最开始运行的ifa那个,许多病毒或外壳程序就是利用这点执行一些特殊操作,程序退出时,TLS回调函数再次被执行一次。
在IMAGE_TLS_DIRECTORY结构中的中的地址是虚拟地址,而不是RVA。这样,如果可执行文件不是从基地址装入,那么这些地址就会用过基址定位来修改,而且,IMAGE_TLS_DIRECTORY本身并不在.TLS区块中,它存在与.rdata区块中.
输出表结构
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;//未使用,总是未0
DWORD TimeDateStamp;//文件生成时间
WORD MajorVersion;//主版本号
WORD MinorVersion;//次版本号
DWORD Name;//模块的真是名称
DWORD Base;//基数,加上学术就是函数地址数组的索引值
DWORD NumberOfFunctions;//AddressOfFunctions阵列中的元素个数
DWORD NumberOfNames;//AddressOfNames阵列中的元素个数
DWORD AddressOfFunctions; //指向函数地址数组
DWORD AddressOfNames; //函数名字的指针地址
DWORD AddressOfNameOrdinals; //指向输出序列号数组
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
PE结构 结构分布
IMAGE_FILE_HEADER 从 50 45 00 00 开始 Size 14H
![图片]()
IMAGE_OPTIONAL_HEADER 从IMAGE_FILE_HEADER 尾部开始 Size 60H
![图片]()
IMAGE_DATA_DIRECTORY 从IMAGE_OPTIONAL_HEADER 尾部开始 Size 80H
![图片]()
区块 前8个字节为块名 IMAGE_SECTION_HEADER
![图片]()