要去看埃菲尔铁塔的顶
欢迎关注本人微博:t.cn/RGSLVUk
额,这个貌似来晚了.......
好了,开始PE文件浅析 , PE ( Portable Executable ) 是Windows下的可执行程序文件格式,
其采用的磁盘文件格式以及内存运行时格式具有“一致性”,具体信息请查询下其他资料。
32位系统下 为 PE,64位为PE+ ,其中扩充了部分字段,这里以PE32 为例子。
大致格式:
| DOS头 | 这里是为了兼容DOS系统
| NT头 | 这才是真正的PE头
| 节区表头 | 这是PE节区描述信息 ,大致有.idata .data .text .rsrc .reloc
| 节区 | 这里对应上面节区表中所描述的,
详细格式请翻看MSDN ,或者WinNt.H。
这里主要说一下 PE中导入\导出表。
导出表(模块向外界提供的API)
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;
DWORD Base;
DWORD NumberOfFunctions;
DWORD NumberOfNames;
DWORD AddressOfFunctions; // RVA from base of image
DWORD AddressOfNames; // RVA from base of image
DWORD AddressOfNameOrdinals; // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
其中
NumberOfFunctions 是导出函数个数,
Name 字段 是 所导出模块的 名称所在的 RVA ,
AddressOfFunctions 是导出函数的 RVA ,
AddressOfNames 是 导出函数的名称数组所在RVA
AddressOfNameOrdinals是 导出函数的ID 编号,需加上 Base 来确定
示例 输出 是这样的:
YunDb.DLL
[1] , DllCanUnloadNow , 0xc66d4a1
[2] , DllGetClassObject , 0xffec8b55
[3] , DllRegisterServer , 0xd4b9016a
[4] , DllUnregisterServer , 0xd4b9016a
导入表(模块引入的外界API)
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics; // 0 for terminating null import descriptor
DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
} DUMMYUNIONNAME;
DWORD TimeDateStamp; // 0 if not bound,
// -1 if bound, and real date\time 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;
导入表是个数组形式,每一个元素对应一个 IMAGE_IMPORT_DESCRIPTOR ,
就像 [ntdll.dll .....] [kernel32.dll ....] ... [gdi32.dll .....] 这样, 一个模块一个导入描述符
其中_IMAGE_IMPORT_DESCRIPTOR 的
union {
DWORD Characteristics;
DWORD OriginalFirstThunk;
} DUMMYUNIONNAME;
中 OriginalFirstThunk 是指向一个IMAGE_THUNK_DATA结构的 RVA,
IMAGE_THUNK_DATA 的结构
typedef struct _IMAGE_THUNK_DATA32 {
union {
DWORD ForwarderString; // PBYTE
DWORD Function; // PDWORD
DWORD Ordinal;
DWORD AddressOfData; // PIMAGE_IMPORT_BY_NAME
} u1;
} IMAGE_THUNK_DATA32;
这个结构是一个与所在环境有关的一个DWORD类型联合结构体,其中Ordinal
是在确定导入表序号时 有意义,
AddressOfData是一个
struct {
DWORD hint ; 这个是API编号
byte name[1]; 这个是API名称字符串的RVA
}*PIMAGE_IMPORT_BY_NAME ;
这里需要注意
AddressOfData的值 若 最高位是 1 ,也即 AddressOfData>>31 == 1 则是 序号导入,就是导入了 模块中API 编号,用的时候 AddressOfData & 0x7FFF后按编号找, 若不是,则是 名称导入,那么这个值就是 API RVA了。
在文件结构中 FirstThunk 和 OriginalFirstThunk 所指向的地址相同,
也即是导入名称表, 在PE文件加载时 FirstThunk 会被 装载程序 填充为
API真实地址,
IAT 原理 :
addr1 call MessageBox ; 实则为 call addN
..
..
addN JMP [ IAT表中对应API VA ]
HOOK IAT 也就是 修改了 " IAT表中对应API VA" 这个值
劫持了程序流程。
感觉能说的很少,是学的少了......
今天就到这里、