分别打开.exe .dll .sys
等文件,观察特征前2个字节,都是4D5A,变成字母是MZ,是DOS系统开发人员的一个名字,再看3C字节是什么,3C存的是一个地址,这个地址对应的5045,变为字母就是PE。
对齐是为了读写速度,找起来快,用空间换时间
早期计算机硬盘水平比较低,只有很小的几个G,节与节之间的空隙比较小,硬盘对齐为200H,后来随着硬件水平提高了,硬盘对齐与内存对齐一样了为1000H
硬盘间隔小,内存间隔大,这是老的编译器
任何一个exe程序都会有一个自己独立的4G内存空间,虚拟内存
2G是平时写应用程序用的,2G是给操作系统用的
这里注意:还有一些exe程序 当我们用winhex打开时
它在硬盘上和内存中是一样的
这个时候我们要有两个概念 就是硬盘对齐(200h字节)和内存对齐(1000h字节),它是为了增加读写速度
比如一个qq程序有两个部分,数据1(可读),数据2(可读可写) ,都是100M,我运行一个账号就需要200M,我再开一个,数据1(可读)已经有了,就没必要在复制一份丢在内存中,只需要复制一份数据2就可以了
PE磁盘文件与内存映像图
PE文件头/DOS头:对当前整个exe程序做概要性描述
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
typedef struct IMAGE_DOS_HEADER{
WORD e_magic;
/
/
DOS头的标识,为
4Dh
和
5Ah
。分别为字母MZ
WORD e_cblp;
WORD e_cp;
WORD e_crlc;
WORD e_cparhdr;
WORD e_minalloc;
WORD e_maxalloc;
WORD e_ss;
WORD e_sp;
WORD e_csum;
WORD e_ip;
WORD e_cs;
WORD e_lfarlc;
WORD e_ovno;
WORD e_res[
4
];
WORD e_oemid;
WORD e_oeminfo;
WORD e_res2[
10
];
DWORD e_lfanew;
/
/
指向IMAGE_NT_HEADERS的所在(PE头相对于文件的偏移,用于定位PE文件)
}IMAGE_DOS_HEADER,
*
PIMAGE_DOS_HEADER;
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
0x00
WORD e_magic;
/
/
5A4D
*
MZ标记用于判断是否为可执行文件
0x02
WORD e_cblp;
/
/
0090
0x04
WORD e_cp;
/
/
0003
0x06
WORD e_crlc;
/
/
0000
0x08
WORD e_cparhdr;
/
/
0004
0x0a
WORD e_minalloc;
/
/
0000
0x0c
WORD e_maxalloc;
/
/
FFFF
0x0e
WORD e_ss;
/
/
0000
0x10
WORD e_sp;
/
/
00B8
0x12
WORD e_csum;
/
/
0000
0x14
WORD e_ip;
/
/
0000
0x16
WORD e_cs;
/
/
0000
0x18
WORD e_lfarlc;
/
/
0040
0x1a
WORD e_ovno;
/
/
0000
0x1c
WORD e_res[
4
];
/
/
0000000000000000
0x24
WORD e_oemid;
/
/
0000
0x26
WORD e_oeminfo;
/
/
0000
0x28
WORD e_res2[
10
];
/
/
20
0x3c
DWORD e_lfanew;
/
/
00000080
*
PE头相对于文件的偏移,用于定位PE文件
|
从文件开始的地方算,过80个字节,就是PE文件真正开始的地方
中间这一部分大小是不确定的
留了一块空间,可以放一些随意的数据
1
2
3
4
5
|
typedef struct IMAGE_NT_HEADERS{
0x00
DWORD Signature;
/
/
PE标识
0x04
IMAGE_FILE_HEADER FileHeader;
/
/
标准PE头(
20
字节)
0x18
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
/
/
扩展PE头(大小不确定)
}IMAGE_NT_HEADERS,
*
PIMAGE_NT_HEADERS;
|
1
2
3
4
5
6
7
|
0x00
WORD Machine;
/
/
014C
*
程序运行的CPU型号,
0x0
任何处理器
/
0x14C
Intel
386
及后续处理器
0x02
WORD NumberOfSections;
/
/
0008
*
文件中存在的节的总数,除了头,还有几节数据,如果要新增节或者合并节就要修改这个值.
0x04
DWORD TimeDateStamp;
/
/
3E22F0DF
*
时间戳:文件的创建时间(和操作系统的创建时间无关),编译器填写的
0x08
DWORD PointerToSymbolTable;
/
/
00000000
0x0c
DWORD NumberOfSymbols;
/
/
00000000
0x10
WORD SizeOfOptionalHeader;
/
/
00E0
*
可选PE头的大小,
32
位PE文件默认E0h
=
16
*
14
,
64
位PE文件默认为F0h,大小可以自定义
0x12
WORD Characteristics;
/
/
010E
*
每个位有不同的含义,可执行文件值为
10F
即
0
1
2
3
8
位置
1
|
TimeDateStamp
.map
文件是对.exe
文件中函数的描述,对.exe
文件的说明
当.map
文件和.exe
文件 不同步时
就是检查 时间戳是否 一致
Characteristics
打勾的 即为1
把所有值 对应起来 0 1 0 E
(第六位是标志保留位,但是没有显示出来)
1
|
0000
0001
0000
1110
|
程序入口 + 内存镜像基址 才是真正的地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
0x00
WORD Magic;
*
说明文件类型:
10B
-
>
32
位下的PE文件
20B
-
>
64
位下的PE文件
0x02
BYTE MajorLinkerVersion;
0x03
BYTE MinorLinkerVersion;
0x04
DWORD SizeOfCode;
*
代码大小
/
所有代码节的和,必须是FileAlignment的整数倍 编译器填的 没用
0x08
DWORD SizeOfInitializedData;
*
已初始化数据大小的和,必须是 FileAlignment的整数倍 编译器填的 没用
0x0c
DWORD SizeOfUninitializedData;
*
未初始化数据大小的和,必须是 FileAlignment的整数倍 编译器填的 没用
0x10
DWORD AddressOfEntryPoint;
*
程序入口
0x14
DWORD BaseOfCode;
*
代码开始的基址,编译器填的 没用
0x18
DWORD BaseOfData;
*
数据开始的基址,编译器填的 没用
0x1c
DWORD ImageBase;
*
内存镜像基址
0x20
DWORD SectionAlignment;
*
内存对齐,区段对齐
0x24
DWORD FileAlignment;
*
文件对齐
0x28
WORD MajorOperatingSystemVersion;
0x2a
WORD MinorOperatingSystemVersion;
0x2c
WORD MajorImageVersion;
0x2e
WORD MinorImageVersion;
0x30
WORD MajorSubsystemVersion;
0x32
WORD MinorSubsystemVersion;
0x34
DWORD Win32VersionValue;
0x38
DWORD SizeOfImage;
*
镜像大小
/
内存中整个PE文件的映射的尺寸,可以比实际的值大,但必须是SectionAlignment的整数倍,是拉伸之后的大小,,,
0x3c
DWORD SizeOfHeaders;
*
所有头
+
节表,技照‘文件对齐 FileAlignment’后的大小,否则加载会出错
0x40
DWORD CheckSum;
*
校验和,一些系统文件有要求,用来判断文件是否被修改
0x44
WORD Subsystem;
0x46
WORD DllCharacteristics;
0x48
DWORD SizeOfStackReserve;
*
初始化时保留的堆栈大小
0x4c
DWORD SizeOfStackCommit;
*
初始化时实际提交的大小
0x50
DWORD SizeOfHeapReserve;
*
初始化时保留的堆大小
0x54
DWORD SizeOfHeapCommit;
*
初始化时实践提交的大小
0x58
DWORD LoaderFlags;
0x5c
DWORD NumberOfRvaAndSizes;
*
目录项数目,RVA数目和大小
0x60
_IMAGE_DATA_DIRECTORY DataDirectory[
16
];
16
个结构体,每个结构体是
8
个字节
|
进行了拉伸,完成之后完全遵守操作系统,就可以执行了
程序入口 + 内存镜像基址 才是真正的入口点地址
代码有个极大的缺点,就是只能加载打印特定固定的notepad.exe文件,而且在
不同的操作系统下面会有异常,可移植性差
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
*
OpenFile()
{
FILE
*
PointToFile
=
NULL;
int
FileSize
=
0
;
int
*
StrBuffer
=
NULL;
int
Num
=
0
;
/
/
打开文件
if
((PointToFile
=
fopen(
"C:\\notepad.exe"
,
"rb"
))
=
=
NULL) {
printf(
"打开文件失败!\n"
);
exit(
1
);
}
/
/
获取文件大小
fseek(PointToFile,
0
,
2
);
FileSize
=
ftell(PointToFile);
/
/
重定位指针
fseek(PointToFile,
0
,
0
);
/
/
buffer
指向申请的堆
StrBuffer
=
(
int
*
)(malloc(FileSize));
if
(!StrBuffer)
{
printf(
"堆空间分配失败!\n"
);
free(StrBuffer);
return
0
;
}
/
/
读取文件内容
Num
=
fread(StrBuffer,FileSize,
1
,PointToFile);
if
(!Num)
{
printf(
"读取文件内容失败!\n"
);
free(StrBuffer);
return
0
;
}
/
/
关闭文件
fclose(PointToFile);
/
/
将缓冲区内的文件内容的地址返回到调用函数的地方
return
StrBuffer;
}
int
*
FileSizes
=
OpenFile();
int
PrintfNtHeaders()
{
/
/
文件指针
unsigned
int
*
PointBuffer
=
(unsigned
int
*
)FileSizes;
unsigned short
*
pBuffer
=
(unsigned short
*
)PointBuffer;
unsigned char
*
pcBuffer
=
(unsigned char
*
)PointBuffer;
/
/
判断MZ和PE的标志
unsigned short Cmp1
=
0x5A4D
;
unsigned
int
Cmp2
=
0x00004550
;
/
/
判断文件是否读取成功
if
(!PointBuffer)
{
printf(
"文件读取失败!\n"
);
free(PointBuffer);
return
0
;
}
/
/
判断是否为MZ标志
if
(
*
pBuffer !
=
Cmp1)
{
printf(
"不是有效MZ标志!\n"
);
printf(
"%X\n"
,
*
pBuffer);
free(PointBuffer);
return
0
;
}
printf(
"*********打印DOS头*********\n"
);
printf(
"e_magic:\t\t\t%X\n"
,
*
(pBuffer));
printf(
"e_ifanew:\t\t\t%08X\n\n\n"
,
*
(PointBuffer
+
15
));
/
/
判断是否为PE标志
if
(
*
(PointBuffer
+
56
) !
=
Cmp2)
{
printf(
"不是有效的PE标志!\n"
);
printf(
"%X\n"
,
*
(PointBuffer
+
56
));
free(PointBuffer);
return
0
;
}
printf(
"*********打印标准PE文件头*********\n"
);
printf(
"PE标志:\t\t\t\t%X\n"
,
*
(PointBuffer
+
56
));
printf(
"Machine:\t\t\t%04X\n"
,
*
(pBuffer
+
114
));
printf(
"NumberOfSection:\t\t%04X\n"
,
*
(pBuffer
+
115
));
printf(
"TimeDateStamp:\t\t\t%08X\n"
,
*
(PointBuffer
+
58
));
printf(
"PointerToSymbolTable:\t\t%08X\n"
,
*
(PointBuffer
+
59
));
printf(
"NumberOfSymbols:\t\t%08X\n"
,
*
(PointBuffer
+
60
));
printf(
"SizeOfOptionalHeader:\t\t%04X\n"
,
*
(pBuffer
+
122
));
printf(
"Chrarcteristics:\t\t%04X\n\n\n"
,
*
(pBuffer
+
123
));
printf(
"*********打印标准可选PE头*********\n"
);
printf(
"Magic:\t\t\t\t%04X\n"
,
*
(pBuffer
+
124
));
printf(
"MajorLinkerVersion:\t\t%02X\n"
,
*
(pcBuffer
+
250
));
printf(
"MinorLinkerVersion:\t\t%02X\n"
,
*
(pcBuffer
+
251
));
printf(
"SizeOfCode:\t\t\t%08X\n"
,
*
(PointBuffer
+
63
));
printf(
"SizeOfInitializedData:\t\t%08X\n"
,
*
(PointBuffer
+
64
));
printf(
"SizeOfUninitializedData:\t%08X\n"
,
*
(PointBuffer
+
65
));
printf(
"AddressOfEntryPoint:\t\t%08X\n"
,
*
(PointBuffer
+
66
));
printf(
"BaseOfCode:\t\t\t%08X\n"
,
*
(PointBuffer
+
67
));
printf(
"BaseOfData:\t\t\t%08X\n"
,
*
(PointBuffer
+
68
));
printf(
"ImageBase:\t\t\t%08X\n"
,
*
(PointBuffer
+
69
));
printf(
"SectionAlignment:\t\t%08X\n"
,
*
(PointBuffer
+
70
));
printf(
"FileAlignment:\t\t\t%08X\n"
,
*
(PointBuffer
+
71
));
printf(
"MajorOperatingSystemVersion:\t%04X\n"
,
*
(pBuffer
+
144
));
printf(
"MinorOperatingSystemVersion:\t%04X\n"
,
*
(pBuffer
+
145
));
printf(
"MajorImageVersion:\t\t%04X\n"
,
*
(pBuffer
+
146
));
printf(
"MinorImageVersion:\t\t%04X\n"
,
*
(pBuffer
+
147
));
printf(
"MajorSubsystemVersion:\t\t%04X\n"
,
*
(pBuffer
+
148
));
printf(
"MinorSubsystemVersion:\t\t%04X\n"
,
*
(pBuffer
+
149
));
printf(
"Win32VersionValue:\t\t%08X\n"
,
*
(PointBuffer
+
75
));
printf(
"SizeOfImage:\t\t\t%08X\n"
,
*
(PointBuffer
+
76
));
printf(
"SizeOfHeaders:\t\t\t%08X\n"
,
*
(PointBuffer
+
77
));
printf(
"CheckSum:\t\t\t%08X\n"
,
*
(PointBuffer
+
78
));
printf(
"Subsystem:\t\t\t%04X\n"
,
*
(pBuffer
+
158
));
printf(
"DllCharacteristics:\t\t%04X\n"
,
*
(pBuffer
+
159
));
printf(
"SizeOfStackReserve:\t\t%08X\n"
,
*
(PointBuffer
+
80
));
printf(
"SizeOfStackCommit:\t\t%08X\n"
,
*
(PointBuffer
+
81
));
printf(
"SizeOfHeapReserve:\t\t%08X\n"
,
*
(PointBuffer
+
82
));
printf(
"SizeOfHeapCommit:\t\t%08X\n"
,
*
(PointBuffer
+
83
));
printf(
"LoaderFlags:\t\t\t%08X\n"
,
*
(PointBuffer
+
84
));
printf(
"NumberOfRvaAndSizes:\t\t%08X\n"
,
*
(PointBuffer
+
85
));
free(PointBuffer);
return
0
;
}
int
main()
{
PrintfNtHeaders();
OpenFile();
return
0
;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <malloc.h>
#define F_PATH "C:\\cntflx\\ipmsg.exe"
FILE
*
open_file(char
*
file_path,char
*
open_mode);
int
compute_file_size(
FILE
*
file_address);
char
*
allocate_buffer(
int
file_size);
char
*
readfile2memory(char
*
file_buffer,
int
file_size,
FILE
*
file_address);
void analysis_PE_head(char
*
File_buffer);
VOID PrintNTHeaders()
{
/
/
初始化
/
/
char file_path[]
=
"C:\\Windows\\System32\\notepad.exe"
;
char file_path[]
=
F_PATH;
char open_mode[]
=
"rb"
;
/
/
打开文件,返回文件指针
FILE
*
file_address
=
open_file(file_path,open_mode);
/
/
计算文件长度
int
file_size
=
compute_file_size(file_address);
/
/
分配内存
char
*
File_buffer
=
allocate_buffer(file_size);
/
/
写入内存,返回内存地址
File_buffer
=
readfile2memory(File_buffer,file_size,file_address);
/
/
打印PE头部信息
analysis_PE_head(File_buffer);
/
/
释放内存、关闭文件流
free(File_buffer);
fclose(file_address);
}
FILE
*
open_file(char
*
file_path,char
*
open_mode)
{
FILE
*
file_address
=
fopen(file_path,open_mode);
/
/
fopen() 参数是字符串也就是常量指针类型
if
(!file_address)
{
printf(
"打开文件失败!\r\n"
);
return
0
;
}
return
file_address;
}
int
compute_file_size(
FILE
*
file_address)
{
int
size
=
0
;
fseek(file_address,
0
,SEEK_END);
size
=
ftell(file_address);
fseek(file_address,
0
,SEEK_SET);
return
size;
}
char
*
allocate_buffer(
int
file_size)
{
char
*
file_buffer
=
(char
*
)malloc(file_size);
if
(!file_buffer)
{
printf(
"申请内存失败!\r\n"
);
return
0
;
}
memset(file_buffer,
0
,file_size);
return
file_buffer;
}
char
*
readfile2memory(char
*
file_buffer,
int
file_size,
FILE
*
file_address)
{
if
(!(fread(file_buffer,file_size,
1
,file_address)))
{
printf(
"从文件向内存中读取数据失败!\r\n"
);
return
0
;
}
return
file_buffer;
/
/
如果写入内存成功,则返回内地址
}
void analysis_PE_head(char
*
File_buffer)
{
/
/
实例化PE文件头几个结构体
PIMAGE_DOS_HEADER pDosHeader
=
NULL;
PIMAGE_NT_HEADERS pNTHeader
=
NULL;
PIMAGE_FILE_HEADER pPEHeader
=
NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader
=
NULL;
PIMAGE_SECTION_HEADER pSectionHeader
=
NULL;
/
/
强制类型转换
pDosHeader
=
(PIMAGE_DOS_HEADER)File_buffer;
/
/
判断是不是有效的MZ标志
if
(
*
((PWORD)pDosHeader) !
=
IMAGE_DOS_SIGNATURE)
{
printf(
"不是有效的MZ标志!\r\n"
);
free(File_buffer);
return
;
}
/
/
强制类型转换 PIMAGE_DOS_HEADER结构体
pDosHeader
=
(PIMAGE_DOS_HEADER)File_buffer;
/
/
打印DOS头
printf(
"=============================DOS头信息如下=============================\r\n"
);
printf(
"MZ标志:\t\t\t%04X\r\n"
,pDosHeader
-
>e_magic);
printf(
"PE偏移:\t\t\t%08X\r\n"
,pDosHeader
-
>e_lfanew);
/
/
判断是不是有效的PE标志
if
(
*
((PDWORD)((DWORD)File_buffer
+
pDosHeader
-
>e_lfanew)) !
=
IMAGE_NT_SIGNATURE)
{
printf(
"不是有效的PE标志!\r\n"
);
free(File_buffer);
return
;
}
/
/
强制类型转换 PIMAGE_NT_HEADERS结构体
pNTHeader
=
PIMAGE_NT_HEADERS((DWORD)File_buffer
+
pDosHeader
-
>e_lfanew);
/
/
打印NT头
printf(
"=============================NT头信息如下===============================\r\n"
);
printf(
"NT:\t\t\t\t%04X\r\n"
,pNTHeader
-
>Signature);
/
/
强制类型转换 PIMAGE_FILE_HEADER结构体
pPEHeader
=
(PIMAGE_FILE_HEADER)((DWORD)pNTHeader
+
4
);
/
/
打印标准PE文件头
printf(
"=============================标准PE头信息如下============================\r\n"
);
printf(
"PE_machine:\t\t\t%04X\r\n"
,pPEHeader
-
>Machine);
printf(
"NumberOfSections:\t\t%04X\n"
,pPEHeader
-
>NumberOfSections);
printf(
"SizeOfOptionalHeader:\t\t%04X\r\n"
,pPEHeader
-
>SizeOfOptionalHeader);
/
/
强制类型转换
pOptionHeader
=
(PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader
+
IMAGE_SIZEOF_FILE_HEADER);
/
/
/
/
打印可选PE头
printf(
"==============================可选PE头信息如下==============================\r\n"
);
printf(
"Magic:\t\t\t\t%04X\r\n"
,pOptionHeader
-
>Magic);
printf(
"AddressOfEntryPoint:\t\t%08X\r\n"
,pOptionHeader
-
>AddressOfEntryPoint);
printf(
"ImageBase:\t\t\t%08X\r\n"
,pOptionHeader
-
>ImageBase);
printf(
"SizeOfImage:\t\t\t%08X\r\n"
,pOptionHeader
-
>SizeOfImage);
printf(
"SizeOfHeaders:\t\t\t%08X\r\n"
,pOptionHeader
-
>SizeOfHeaders);
printf(
"SectionAlignment:\t\t%08X\r\n"
,pOptionHeader
-
>SectionAlignment);
printf(
"FileAlignment:\t\t\t%08X\r\n"
,pOptionHeader
-
>FileAlignment);
/
/
强制类型转换
pSectionHeader
=
(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader
+
pPEHeader
-
>SizeOfOptionalHeader);
printf(
"==============================节表信息如下===============================\n"
);
/
/
printf(
"name:%s\n"
,pSectionHeader
-
>Misc);
DWORD dwNumberOfSection
=
pPEHeader
-
>NumberOfSections;
/
*
printf(
"%x\n"
,pPEHeader
-
>NumberOfSections);
printf(
"IMAGE_SIZEOF_SHORT_NAME:%x\n"
,IMAGE_SIZEOF_SHORT_NAME);
printf(
"option_add:%x\n"
,pOptionHeader);
printf(
"psection_add:%x\n"
,pSectionHeader);
printf(
"==============================================================\n"
);
*
/
for
(DWORD i
=
0
;i<dwNumberOfSection;i
+
+
,pSectionHeader
+
+
)
{
printf(
"========================第%d个节信息:===============================\n"
,i
+
1
);
printf(
"section_name:"
);
for
(DWORD j
=
0
;j<IMAGE_SIZEOF_SHORT_NAME;j
+
+
)
{
printf(
"%c"
,pSectionHeader
-
>Name[j]);
}
printf(
"\r\n"
);
printf(
"Misc:\t\t\t\t%08X\r\n"
,pSectionHeader
-
>Misc);
printf(
"VirtualAddress:\t\t\t%08X\r\n"
,pSectionHeader
-
>VirtualAddress);
printf(
"SizeOfRawData:\t\t\t%08X\r\n"
,pSectionHeader
-
>SizeOfRawData);
printf(
"PointerToRawData:\t\t%08X\r\n"
,pSectionHeader
-
>PointerToRawData);
printf(
"Characteristics:\t\t%08X\r\n"
,pSectionHeader
-
>Characteristics);
}
}
int
main(
int
argc, char
*
argv[])
{
PrintNTHeaders();
/
/
getchar();
return
0
;
}
|
更多【PE头解析-字段说明】相关视频教程:www.yxfzedu.com