PE文件的一般格式如下
IMAGE_DOS_HEADER
DOS STUB
NT Signature
IMAGE_FILE_HEADER
IMAGE_OPTIONAL_HEADER
IMAGE_SECTION_HEADER(.text段结构属性) 28H字节 //.text段
IMAGE_SECTION_HEADER(.idata段结构属性)28H字节
IMAGE_SECTION_HEADER
.text段的代码开始
.idata段的导入表开始 200H字节
.data段的数据开始
我们用十六进制编辑器打开的一个DOS文件,我们发现有好多都为00只是为了对齐用的。
相对虚拟地址RVA(Relative Virtual Address)= 虛址地址VA(VirtualAddress)) - 基址BA(Base Address)
例VA=0x405000
在十六进制编辑器里面:如果是2字节的地址0X7899 在十六进制工具里面为99 87低地址在前,高地址在后,如果是4字节的的地址OX55667788在十六进制工具里面则为88 77 66 55 我们取地址的也是高位在前低位在后。
--->DOS模式开始:IMAGE_DOS_HEADER
typedef struct _IMAGE_DOS_HEADER{
//共占64个字节其中上面两个和最下面四个是固定的 其它可以用00填充…… 如下图
上IMAGE_DOS_HEADER这个结构最重要的是第一个成员e_magic和最后一个成员e_lfanew图大红色矩形为IMAGE_DOS_HEADER的范围工64字节
IMAGE_DOS_HEADER这个结构最重要的是第一个成员e_magic和最后一个成员e_lfanew
文件编移00000040—000000A0的共70H字节为DOS STUB,WINDOWS下并不用,我们相应保留绿色矩形的范围。
-->PE开始
Characteristics:
0:置1表示文件中没有重定向信息
1:置1表示文该件是可执行文件EXE
2:置1表示没有行数信息
3:置1表示没有局部符号信息
8:表示希望机器为32位机
9:表示没有调试信息
11:置1表示程序不能上网运行
12:置1表示文件是一个系统文件,如驱动…………
13:置1表示文件是一个动态链接库DLL
-->PE可选头
IMAGE_OPTIONAL_HEADER结构
typedef struct _IMAGE_OPTIONAL_HEADER {
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
SectionAlignment 在内存中是以1000倍往上前进的如果不足则用1000的倍数填充,如:如果对齐值是800 我们要填写为1000
FileAlignment
SizeOfHeaders
OEP的RVA=.text段在内存中的偏移地址-.text段在文件中的偏移地址+.text段FirstThunk在文件中的偏移地址。
VirtualAddress=.idata段在内存中的偏移地址-.idata在文件中的偏移地址+。idata段FirstThunk在文件中的偏移地址。
Size:我们只引入了二个结构数组,每个20个字节+最后一个全为00结尾,共60字节所以为:3C 00 00 00,全部填写00 应该可行的
--> NumberOfRvaAndSizes目录个数(可以从下面定义看到有16个,16进制值0x10)
#define IMAGE_DIRECTORY_ENTRY_EXPORT
#define IMAGE_DIRECTORY_ENTRY_IMPORT
#define IMAGE_DIRECTORY_ENTRY_RESOURCE
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION
#define IMAGE_DIRECTORY_ENTRY_SECURITY
#define IMAGE_DIRECTORY_ENTRY_BASERELOC
#define IMAGE_DIRECTORY_ENTRY_DEBUG
#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR
#define IMAGE_DIRECTORY_ENTRY_TLS
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
#define IMAGE_DIRECTORY_ENTRY_IAT
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14
可以看到我们上面只列到了二个表,IMAGE_DIRECTORY_ENTRY_EXPORT和IMAGE_DIRECTORY_ENTRY_IMPORT
并且只有IMAGE_DIRECTORY_ENTRY_IMPORT表有值(看00000130外的前8字节),可以知道一个表占可选头的8字节,它们按数组排列
现在我们要关注的是第二个
-->IMAGE_DATA_DIRECTORY DataDirectory
typedef struct _IMAGE_DATA_DIRECTORY{
DWORD VirtualAddress
DWORD Size;表的大小,我们只引入二个结构数组每个20字节+最后一个全0结尾
}IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;
上面16个只有第二个表8字节有数字,其它全为00
我们暂时不知道第二是什么我们先用AA来代替了…………
-->各个段
就以.text为例
typedef struct_IMAGE_SECTION_HEADER{
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];节名称.text 8字节 2E 74 65 78 74 00 00 00
union{
}Misc;
DWORD VitualAddress;//文件.text段在内存的偏移地址
DWORD SizeOfRawData;//.text段在文件中的长度(对齐后 以200为倍数)一般是00 02 00 00
DWORD PointerToRawData;//.text在文件中的偏移,就是十六进制编辑器里面的offset
DWORD PointerToRelocation;
DWORD PointerTOLinenmbers;
WORD
WORD
DWORD Characteristics;//节属性可执行...可读可写设置为:20 00 00 60
}IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;
***********
IMAGE_SECTION_HEADER的最后一个成员Characteristics是段的属性代表如这段是否可读可写等
#define IMAGE_SCN_CNT_CODE
#define IMAGE_SCN_CNT_INITIALIZED_DATA
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA
#define IMAGE_SCN_LNK_NRELOC_OVFL
#define IMAGE_SCN_MEM_DISCARDABLE
#define IMAGE_SCN_MEM_NOT_CACHED
#define IMAGE_SCN_MEM_NOT_PAGED
#define IMAGE_SCN_MEM_SHARED
#define IMAGE_SCN_MEM_EXECUTE
#define IMAGE_SCN_MEM_READ
#define IMAGE_SCN_MEM_WRITE
.text段000001CC处的4字节 20 00 00 60 是从下面的三个标志与得来的
#define IMAGE_SCN_CNT_CODE
#define IMAGE_SCN_CNT_INITIALIZED_DATA
#define IMAGE_SCN_MEM_EXECUTE
.idata段000001F4处的4字节 40 00 00 40 是从下面的三个标志与得来的
#define IMAGE_SCN_CNT_INITIALIZED_DATA
#define IMAGE_SCN_MEM_READ
.data段0000021C处的4字节 40 00 00 C0 是从下面的三个标志与得来的
#define IMAGE_SCN_CNT_INITIALIZED_DATA
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA
#define IMAGE_SCN_MEM_READ
*************************
上面只包含了.text .idata .data三段,这些段名是可以改成别的名称。因为三段所以上面IMAGE_FILE_HEADER结构第二个成员NumberOfSections文件编移000000B6处二字节为03 00
如果有更多的段可以跟在上面三段的后面也是相同的结构
以前应该有注意到。文件对齐度为200 不足200的用00填充到200 有上图可以看到文件的偏移地址为210所以我们必须要填充到偏移地址为400的地方,OX00000400这行不填充…………
-->机器码(.text段)
机器码:前五个字节为MeaageBoxA的机器码,接着4个字节为字符串的地址 ,然后是一个CALL 一个导入表的地址,接着是call一个ex的地址,地址为4个字节
-->导入表处理(就是idata段)
Typedef struct——IMAGE_IMPORT_DESCRIPTOR{
}
}IMAGE_IMPORT_DESCRIPTOR;
_IMAGE_IMPROT_DESCRIPTOR第一个成员指向的机构,最后以一个全00的4字节结尾
Typedef struct_IMAGE_THUNK_DATA32{
}IMAGE_THUNK_DATA32;
上面这个结构共20个字节。
--->然后是kernel32结构
和上面的那个结构是一样的 都占20个字节
--->最后是以一个全00结束的20字节。。。就是导入表结束要以全00结尾
_IMAGE_IMPROT_DESCRIPTOR第一个成员指向MessageBoxA地址,最后以一个全00的4字节结尾
Typedef struct_IMAGE_THUNK_DATA32{
}IMAGE_THUNK_DATA32;
----最后只剩下一个data段了。。