PE解析代码实现

打印PE文件头部和节区信息

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
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#include<Windows.h>

//宏定义,方便后续使用

//定义变量
IMAGE_DOS_HEADER myDOS;
LONG elf_new;
IMAGE_NT_HEADERS32 myNTheader;
IMAGE_OPTIONAL_HEADER32 myOPTIONheader;
IMAGE_SECTION_HEADER mysection[100];

int NUM_SECTION;

int main()
{
FILE* pfile;
pfile = fopen("D:\\new\\Notepadx32\\Notepad++.7.6.1.bin.x32\\Notepad++.7.6.1.bin.x32\\notepad++.exe", "r");//打开文件
fseek(pfile, 0, SEEK_SET);//参数说明,将fp指针从文件开头移动到0的位置
fread(&myDOS, sizeof(IMAGE_DOS_HEADER), 1, pfile);//表示从fp开始的地方读取一次长度为sizeof(IMAGE_DOS_HEADER)的字节,存储到myDOS中
//DOS
printf("==============IMAGE_DOS_HEADER==============\n");
printf("DOS头: %08X\n", myDOS.e_magic);
printf("NT头所在位置: %08X\n", myDOS.e_lfanew);
elf_new = myDOS.e_lfanew;//将NT头的偏移存储起来

//NT头
fseek(pfile, elf_new, SEEK_SET);//注意不是sizeof(elf_new)
fread(&myNTheader, sizeof(IMAGE_NT_HEADERS), 1, pfile);
printf("==============IMAGE_NT_HEADERS==============\n");
//打印PE标志
printf("PE标志: %08X\n", myNTheader.Signature);

//打印标准PE头信息
printf("==============IMAGE_FILE_HEADERS==============\n");
printf("节区数量: %08X\n", myNTheader.FileHeader.NumberOfSections);
NUM_SECTION = myNTheader.FileHeader.NumberOfSections;
printf("可选PE头大小: %08X\n", myNTheader.FileHeader.SizeOfOptionalHeader);
//打印ASLR的信息,方便查看和修改
printf("ASLR属性: %08X\n", (myNTheader.FileHeader.Characteristics ) & 1);

//打印可选PE头信息
printf("==============IMAGE_OPTIONAL_HEADERS==============\n");
fseek(pfile, elf_new+sizeof(IMAGE_FILE_HEADER)+sizeof(myNTheader.Signature), SEEK_SET);//因为标准PE头长度为20
fread(&myOPTIONheader, sizeof(IMAGE_OPTIONAL_HEADER), 1, pfile);
printf("DWORD AddressOfEntryPoint: %08llX\n", myOPTIONheader.AddressOfEntryPoint);
printf("基址: %08X\n", myOPTIONheader.ImageBase);//注意这里的可选PE头类型必须是IMAGE_OPTIONAL_HEADER32
printf("文件对齐大小: %08X\n", myOPTIONheader.FileAlignment);
printf("内存对齐大小: %08X\n", myOPTIONheader.SectionAlignment);
printf("文件头和节表大小: %08X\n", myOPTIONheader.SizeOfHeaders);
printf("内存拉伸大小: %08X\n", myOPTIONheader.SizeOfImage);

//打印节表信息,前面我们已经存储了节表数量了
printf("==============IMAGE_SECTION_HEADER SectionHeaders==============\n");
fseek(pfile, elf_new + sizeof(IMAGE_NT_HEADERS32), SEEK_SET);
fread(&mysection, sizeof(IMAGE_SECTION_HEADER) * NUM_SECTION, 1, pfile);
for (int i = 0; i < NUM_SECTION; ++i)
{
printf("NAME: %s\n", mysection[i].Name);
printf("DWORD VirtualAddress: %08X\n", mysection[i].VirtualAddress);
printf("DWORD SizeOfRawData: %08X\n", mysection[i].SizeOfRawData);
printf("DWORD PointerToRawData: %08X\n", mysection[i].PointerToRawData);
printf("DWORD VirtualSize: %08X\n", mysection[i].Misc.VirtualSize);
}
fclose(pfile);//关闭文件
return 0;
}

RVA转FOA

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
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<windows.h>
#include<string.h>
#include<stdlib.h>
/*
* RVA转FOA的思路
* 1、先判断所在节区,设计思路:首先我们必须拿的是内存对齐后的来比较大小,先把RVA-virtualaddress,再和max(MISC,SizeofRawData)按照内存对齐的值作比较
* 2、循环判断节区
* 3、计算FOA,偏移是一样的,那就是RVA-virtualaddress+节区的PointerOfdata
*/
IMAGE_NT_HEADERS32 myNTheader;
IMAGE_DOS_HEADER myDOS;//因为PE头长度不变,所以我们只需要找到elf_new的内容就可以知道节区的起始地址
IMAGE_SECTION_HEADER mysection[10];
int NUM_SECTION;//我们还需要知道节区的数量
int elf_new;
int RVA = 0x20d000;
long long MAX(DWORD a, DWORD b)
{//计算MISC和SizeOFRAWDATA,并返回按照内存对齐后的值
if (a > b)
{
return (a%myNTheader.OptionalHeader.SectionAlignment)?((a / myNTheader.OptionalHeader.SectionAlignment)+1) * myNTheader.OptionalHeader.SectionAlignment : ((a / myNTheader.OptionalHeader.SectionAlignment)) * myNTheader.OptionalHeader.SectionAlignment;
}
else
return (b % myNTheader.OptionalHeader.SectionAlignment) ? ((b / myNTheader.OptionalHeader.SectionAlignment) + 1) * myNTheader.OptionalHeader.SectionAlignment : ((b / myNTheader.OptionalHeader.SectionAlignment)) * myNTheader.OptionalHeader.SectionAlignment;;
}
int main()
{
FILE* pfile;
pfile = fopen("D:\\new\\Notepadx32\\Notepad++.7.6.1.bin.x32\\Notepad++.7.6.1.bin.x32\\notepad++.exe", "r");
fseek(pfile,0, SEEK_SET);
fread(&myDOS, sizeof(IMAGE_DOS_HEADER), 1, pfile);
elf_new = myDOS.e_lfanew;
fseek(pfile, elf_new, SEEK_SET);
fread(&myNTheader, sizeof(IMAGE_NT_HEADERS32), 1, pfile);
NUM_SECTION = myNTheader.FileHeader.NumberOfSections;

//得到节区
fseek(pfile, elf_new + sizeof(IMAGE_NT_HEADERS32), SEEK_SET);
fread(&mysection, sizeof(IMAGE_SECTION_HEADER) * NUM_SECTION, 1, pfile);
for (int i = 0; i < NUM_SECTION; ++i)
{
if (RVA - mysection[i].VirtualAddress < MAX(mysection[i].Misc.VirtualSize, mysection[i].SizeOfRawData))
{
printf("所在节区为:%s\n", mysection[i].Name);
printf("FOA为:%08X", RVA - mysection[i].VirtualAddress + mysection[i].PointerToRawData);
}
}
fclose(pfile);
return 0;
}

PE插入shellcode

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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<Windows.h>
#include<malloc.h>
#include<stdlib.h>

#define MessageBoxA_ADDR 0x76C20F40//MessageBoxA的地址
#define shellcode_len 0x12//定义shellcode的长度
//输入路径和输出路径
char file_path[] = "D:\\new\\Notepadx32\\Notepad++.7.6.1.bin.x32\\Notepad++.7.6.1.bin.x32\\notepad++.exe";
char final_path[] = "D:\\new\\Notepadx32\\Notepad++.7.6.1.bin.x32\\Notepad++.7.6.1.bin.x32\\5.exe";

//插入的shellcode
BYTE shellcode[] = {
0x6A,0x00,0x6A,0x00,0x6A,0x00,0x6A,0x00,
0xE8,0x00,0x00,0x00,0x00,
0xE9,0x00,0x00,0x00,0x00
};
int LoadPE(LPVOID*pFileBuffer)//二级指针存储的是一级指针的地址
{
FILE* pfile;
DWORD FileSize = 0;
LPVOID pTempBuffer;
pfile = fopen(file_path, "rb");
//通过fseek和ftell返回文件长度,fseek将fp指针设置在文件尾,ftell获取当前fp指针的位置与文件首的偏移
fseek(pfile, 0, SEEK_END);
FileSize = ftell(pfile);

//重新设置回开头
fseek(pfile, 0, SEEK_SET);
//开辟空间,malloc函数返回开辟空间的起始地址
pTempBuffer = malloc(FileSize);

//将文件中的内容读取到临时Buffer中
fread(pTempBuffer, FileSize, 1, pfile);

//将分配返回的地址存储到FileBuffer中
*pFileBuffer = pTempBuffer;
//temp指针指向空
pTempBuffer = NULL;
fclose(pfile);
return FileSize;
}

int CopyFileBufferToImageBuffer(LPVOID pFileBuffer,LPVOID* pImageBuffer)//pImageBuffer是void类型指针,指向的是读取到内存中的文件内容首地址
{
//初始化PE结构体指针
PIMAGE_DOS_HEADER pDOSHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
//初始化tempBuffer
LPVOID pTempBuffer = NULL;
//通过强制转换类型来限制长度,转为Dos头的指针那么得到的就是Dos头的信息
pDOSHeader = PIMAGE_DOS_HEADER(pFileBuffer);
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDOSHeader->e_lfanew);//因为void类型的指针不能直接运算,所以将其转为int整型,再做加减得到其他地址
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);

//分配ImageBuffer内存
pTempBuffer = malloc(pOptionalHeader->SizeOfImage);
//初始化ImageBuffer内存
memset(pTempBuffer, 0, pOptionalHeader->SizeOfImage);
//拷贝数据
memcpy(pTempBuffer, pDOSHeader, pOptionalHeader->SizeOfHeaders);//参数说明,目标数据、被使用数据,长度

//循环拷贝节表信息
PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
for (int i = 0; i < pFileHeader->NumberOfSections; i++,pTempSectionHeader++)
{
//因为memcpy只接受void类型的指针,所以要先强制转换
memcpy((void*)((DWORD)pTempBuffer + pTempSectionHeader->VirtualAddress), (void*)((DWORD)pFileBuffer + pTempSectionHeader->PointerToRawData), pTempSectionHeader->SizeOfRawData);
}
//赋值给pImageBuffer
*pImageBuffer = pTempBuffer;
pTempBuffer = NULL;
return pOptionalHeader->SizeOfImage;
}

int CopyImageBufferToNewBuffer(LPVOID pImageBuffer,LPVOID* pNewBuffer)
{
//初始化PE结构体指针
PIMAGE_DOS_HEADER pDOSHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
//初始化TempBuffer
LPVOID pTempBuffer = NULL;

//结构体强制转换
pDOSHeader = PIMAGE_DOS_HEADER(pImageBuffer);
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDOSHeader->e_lfanew);//因为void类型的指针不能直接运算,所以将其转为int整型,再做加减得到其他地址
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);

//计算NewBuffer大小
DWORD new_buffer_size = pOptionalHeader->SizeOfHeaders;
//节表大小计算
PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
//注意这里要使用临时变量,否则循环的时候,结构体指针后移,指向改变
for (int i = 0; i < pFileHeader->NumberOfSections; i++, pTempSectionHeader++)
{
new_buffer_size += pTempSectionHeader->SizeOfRawData;
//printf("%X\n", pSectionHeader->SizeOfRawData);
}
printf("%X\n", new_buffer_size);
//开辟空间并且设置为0
pTempBuffer = malloc(new_buffer_size);
memset(pTempBuffer, 0, new_buffer_size);
//复制ImageBuffer信息
memcpy(pTempBuffer, pDOSHeader, pOptionalHeader->SizeOfHeaders);
//复制节表信息
pTempSectionHeader = pSectionHeader;
for (int i = 0; i < pFileHeader->NumberOfSections; i++, ++pTempSectionHeader)
{
//因为memcpy只接受void类型的指针,所以要先强制转换
memcpy((PWORD)((DWORD)pTempBuffer + pTempSectionHeader->PointerToRawData), (PWORD)((DWORD)pImageBuffer + pTempSectionHeader->VirtualAddress), pTempSectionHeader->SizeOfRawData);
}
//赋值给pImageBuffer
*pNewBuffer = pTempBuffer;
pTempBuffer = NULL;
return new_buffer_size;
}
void newbuffer_write2_exe(PVOID NewFileBuffer, DWORD FileSize, char* FilePath)
{
FILE* fp1 = fopen(FilePath, "wb");
if (fp1 != NULL)
{
fwrite(NewFileBuffer, FileSize, 1, fp1);
printf("成功存盘");
}
fclose(fp1);
return ;

}
void ADD_Opcode(LPVOID pImageBuffer, LPVOID* pNewBuffer)
{
//初始化PE结构体指针
PIMAGE_DOS_HEADER pDOSHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
//通过强制转换类型来限制长度,转为Dos头的指针那么得到的就是Dos头的信息
pDOSHeader = PIMAGE_DOS_HEADER(pImageBuffer);
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDOSHeader->e_lfanew);//因为void类型的指针不能直接运算,所以将其转为int整型,再做加减得到其他地址
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
//判断能否插入
if (shellcode_len > pSectionHeader->SizeOfRawData - pSectionHeader->Misc.VirtualSize)
{
printf("长度不足,无法插入\n");
free(pImageBuffer);
}

//计算空白位置,转为char*指针
PBYTE code_begin = (PBYTE)((DWORD)pImageBuffer + pSectionHeader->VirtualAddress+ pSectionHeader->Misc.VirtualSize);
//插入shellcode
memcpy(code_begin, shellcode, shellcode_len);
//计算E8地址
DWORD callADDr = (MessageBoxA_ADDR - (pOptionalHeader->ImageBase + pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize + 0xD));
//将callADDR插入到E8之后,填充数据
*(PDWORD)((DWORD)code_begin + 0x09) = callADDr;

//计算jmp地址,跳转的值=真实地址-下一条指令地址
DWORD jmpADDr = pOptionalHeader->ImageBase + pOptionalHeader->AddressOfEntryPoint - ((DWORD)code_begin + pOptionalHeader->ImageBase + shellcode_len-(DWORD)pImageBuffer);
*(PDWORD)((code_begin + 14)) = jmpADDr;

//修改OEP
pOptionalHeader->AddressOfEntryPoint = ((DWORD)code_begin - (DWORD)pImageBuffer);//也可以使用VirtualAddress+VirtualSize

//还原为NewBuffer
DWORD ret2=CopyImageBufferToNewBuffer(pImageBuffer, pNewBuffer);

//存盘
newbuffer_write2_exe(*pNewBuffer,ret2, final_path);
return ;
}
void operate_pe()
{
LPVOID pFileBuffer = NULL;//LPVOID相当于void*
LPVOID pNewBuffer = NULL;
LPVOID pImageBuffer = NULL;
//读取文件内容到FileBuffer中d
DWORD file_size = LoadPE(&pFileBuffer);//二级指针void**,将存储指针的地址传过去
printf("文件长度为: %08X\n", file_size);

//将FileBuffer拉伸为ImageBuffer
DWORD Image_Size = CopyFileBufferToImageBuffer(pFileBuffer,&pImageBuffer);
printf("拉伸后的大小为: %08X\n",Image_Size);

//添加opcode
ADD_Opcode(pImageBuffer, &pNewBuffer);

//开辟的内存需要free掉
free(pFileBuffer);
free(pNewBuffer);
free(pImageBuffer);
return;
}
int main()
{
operate_pe();
return 0;
}

PE文件新增节

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
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<windows.h>
#include<stdlib.h>
#include<malloc.h>


/*
思路:
1、读取文件信息到buffer中
判断节区信息够不够大小,两个节表的大小
2、找到节区的最后位置,开辟指定大小的空间
3、修改信息-NumberOfSection、SizeOfRawData、VirtualSize(注意要对齐)
*/
#define New_Buffer_Size 0x1000
#define File_Path "D:\\new\\Notepadx32\\Notepad++.7.6.1.bin.x32\\Notepad++.7.6.1.bin.x32\\notepad++.exe"
#define Final_Path "D:\\new\\Notepadx32\\Notepad++.7.6.1.bin.x32\\Notepad++.7.6.1.bin.x32\\6++.exe"
int Open_File(LPVOID *pFileBuffer)
{
FILE* pfile = NULL;

LPVOID TempBuffer = NULL;
pfile = fopen(File_Path, "rb");
fseek(pfile, 0, SEEK_END);
DWORD file_size = ftell(pfile);
//设置文件指针到文件头
fseek(pfile, 0, SEEK_SET);
TempBuffer = malloc(file_size);
fread(TempBuffer , file_size, 1, pfile);

*pFileBuffer = TempBuffer;
TempBuffer = NULL;
fclose(pfile);
return file_size;
}
int Add_Section(LPVOID FileBuffer, LPVOID* pNewBuffer,DWORD file_size)
{
//定义结构体指针
PIMAGE_DOS_HEADER pDOSHeader = NULL;
PIMAGE_NT_HEADERS32 pNTHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = NULL;
PIMAGE_SECTION_HEADER pSection = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PVOID pNewTempBuffer = NULL;
DWORD New_File_Size = 0;


//新增节
New_File_Size = file_size + 0x1000;
pNewTempBuffer = (PVOID)malloc(New_File_Size);
// 判断开辟空间是否成功
if (!pNewTempBuffer)
{
printf("pNewTempBuffer开辟空间失败!\n");
return 0;
}
// 初始化内存
memset(pNewTempBuffer, 0, New_File_Size);
// 将旧空间的内容copy到新的空间
memcpy(pNewTempBuffer, FileBuffer, file_size);

//读取信息
pDOSHeader = (PIMAGE_DOS_HEADER)(pNewTempBuffer);
pNTHeader = (PIMAGE_NT_HEADERS32)((DWORD)pNewTempBuffer + pDOSHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + sizeof(IMAGE_FILE_HEADER));
pSection = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER32));

//找到节表的最后位置
PIMAGE_SECTION_HEADER pfinal_Section = &(pSection[pFileHeader->NumberOfSections - 1]);

//判断能否插入节表,因为在文件和内存中PE头和DOS头大小不变,直接计算即可
DWORD remain_size = (pOptionalHeader->SizeOfHeaders - pDOSHeader->e_lfanew - 4 - sizeof(IMAGE_FILE_HEADER) - sizeof(IMAGE_OPTIONAL_HEADER32) - sizeof(IMAGE_SECTION_HEADER) * pFileHeader->NumberOfSections);
if (remain_size < 2 * sizeof(IMAGE_SECTION_HEADER))
{
printf("位置不够捏,想想其他办法吧~\n");
}


//修改信息
// 初始化新增节信息
PVOID pSecName = &pSection[pFileHeader->NumberOfSections].Name;
PDWORD pSecMisc = &pSection[pFileHeader->NumberOfSections].Misc.VirtualSize;
PDWORD pSecVirtualAddress = &pSection[pFileHeader->NumberOfSections].VirtualAddress;
PDWORD pSecSizeofRawData = &pSection[pFileHeader->NumberOfSections].SizeOfRawData;
PDWORD pSecPointerToRawData = &pSection[pFileHeader->NumberOfSections].PointerToRawData;
PDWORD pSecCharacteristic = &pSection[pFileHeader->NumberOfSections].Characteristics;
//名字
memcpy(pSecName, ".mycode", 8);
//Misc
*pSecMisc = 0x1000;
//计算VirtualAddress=前一个节的VA+sizeofrawdata或者virtualSize内存对齐大小
DWORD Sec_Size = (pfinal_Section->SizeOfRawData > pfinal_Section->Misc.VirtualSize) ? pfinal_Section->SizeOfRawData : pfinal_Section->Misc.VirtualSize;
//内存对齐
Sec_Size= (Sec_Size % pOptionalHeader->SectionAlignment) ? ((Sec_Size / pOptionalHeader->SectionAlignment) + 1) * pOptionalHeader->SectionAlignment : Sec_Size;
//修改VirtualAddress
*pSecVirtualAddress = pfinal_Section->VirtualAddress + Sec_Size;
//修改sizeofRawData
*pSecSizeofRawData = 0x1000;
//修改Pointer
DWORD size = pfinal_Section->SizeOfRawData;
DWORD File_Size= (size % pOptionalHeader->FileAlignment) ? ((size / pOptionalHeader->FileAlignment) + 1) * pOptionalHeader->FileAlignment : size;
*pSecPointerToRawData = pfinal_Section->PointerToRawData + File_Size;

*pSecCharacteristic = 0xFFFFFFFF;

//头部信息,先计算增加的长度在内存和文件拉伸的长度
DWORD Sec_ADD = (New_Buffer_Size % pOptionalHeader->SectionAlignment) ? ((New_Buffer_Size / pOptionalHeader->SectionAlignment) + 1) * pOptionalHeader->SectionAlignment : New_Buffer_Size;
DWORD File_ADD =
pOptionalHeader->SizeOfImage += Sec_ADD;
pFileHeader->NumberOfSections += 1;

*pNewBuffer = pNewTempBuffer;
pNewTempBuffer = NULL;
return New_File_Size;
}
void Write_To_Newfile(DWORD New_File_Size, LPVOID pNewBuffer)
{
FILE* fp;
fp = fopen(Final_Path, "wb");
fwrite(pNewBuffer, New_File_Size, 1, fp);
fclose(fp);
return ;
}
void PE_operate()
{
DWORD new_file_size = 0;
PVOID pNewBuffer = NULL;
PVOID FileBuffer = NULL;
DWORD file_size = 0;
DWORD New_File_Size = 0;
//打开文件读取信息
file_size = Open_File(&FileBuffer);
//新增节并且修改信息
New_File_Size=Add_Section(FileBuffer,&pNewBuffer,file_size);

Write_To_Newfile(New_File_Size, pNewBuffer);
}
int main()
{
PE_operate();
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
#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<windows.h>
#include<string.h>
#include<stdlib.h>
#define FilePath "D:\\OneDrive\\桌面\\reverse\\吾爱破解专用版Ollydbg\\DBGHELP.DLL"

void ReadFileToBuffer(LPVOID *FileBuffer)
{
LPVOID pTempBuffer;
//打开文件并读取到Buffer中
FILE* pfile = NULL;
pfile = fopen(FilePath, "r");
fseek(pfile, 0, SEEK_END);
//读取文件大小
DWORD file_size = ftell(pfile);
//设置到开头进行读取
fseek(pfile, 0, SEEK_SET);
//先开辟空间
pTempBuffer = (void*)malloc(file_size);
//读取信息
fread(pTempBuffer, file_size, 1, pfile);
//如果是一级指针,读取完之后就会被释放掉
*FileBuffer = pTempBuffer;
pTempBuffer = NULL;
fclose(pfile);
return ;
}

/*
* RVA转FOA
* 先看在哪个节区,减去该节区的RVA+该节区的PointerOfRawData
*/
DWORD RVATOFOA(PIMAGE_SECTION_HEADER pSectionHeader, DWORD RVA,DWORD NumberOfSection)
{
DWORD FOA = 0;
for (int i = 0; i < NumberOfSection; i++, pSectionHeader++)
{
//如果小于RVA+节区的大小,说明在节区内
if (RVA < pSectionHeader->VirtualAddress + max(pSectionHeader->SizeOfRawData, pSectionHeader->Misc.VirtualSize))
{
FOA = RVA - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
return FOA;
}
}
}

void PrintExportTable(LPVOID FileBuffer)
{
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS32 pNtHeader = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
PIMAGE_EXPORT_DIRECTORY pExportTable = NULL;
PIMAGE_DATA_DIRECTORY pDataTable= NULL;
//读取DLL信息
pDosHeader = (PIMAGE_DOS_HEADER)(FileBuffer);
pNtHeader = (PIMAGE_NT_HEADERS32)((DWORD)FileBuffer + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeader + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + sizeof(IMAGE_FILE_HEADER));
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER32));
//获取导出表基本信息
pDataTable = (PIMAGE_DATA_DIRECTORY)(pOptionalHeader->DataDirectory);
printf("导出表的RVA为:%X\n", pDataTable[0].VirtualAddress);
printf("导出表的大小为:%X\n", pDataTable[0].Size);
//打印导出表
DWORD ExportTable_FOA = RVATOFOA(pSectionHeader, pDataTable[0].VirtualAddress,pFileHeader->NumberOfSections);
printf("导出表在文件中的位置为:%X\n", ExportTable_FOA);
//获取导出表信息
pExportTable = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pDosHeader + ExportTable_FOA);

//打印导出表信息,获取DLL名称,导出函数名称表,导出函数地址表,导出函数序号表
//先打印导出表按名字导出函数的个数
printf("按名称导出的函数个数为:%X\n", pExportTable->NumberOfFunctions);
printf("按名称导出的函数个数为:%X\n", pExportTable->NumberOfNames);

//打印DLL名称,导出函数名称表,导出函数地址表,导出函数序号表
DWORD NameFOA = RVATOFOA(pSectionHeader, pExportTable->Name, pFileHeader->NumberOfSections);
char* nameofdll = (char*)((DWORD)pDosHeader + NameFOA);
printf("DLL的名称为:%s\n", nameofdll);
DWORD FOAOfName= RVATOFOA(pSectionHeader,pExportTable->AddressOfNames, pFileHeader->NumberOfSections);
DWORD FOAOfNameOdinals= RVATOFOA(pSectionHeader, pExportTable->AddressOfNameOrdinals, pFileHeader->NumberOfSections);
DWORD FOAOfFunctions= RVATOFOA(pSectionHeader, pExportTable->AddressOfFunctions, pFileHeader->NumberOfSections);
printf("文件中导出函数地址表为:%X\n文件中函数名称地址表为:%X\n文件中函数序号地址表为:%X\n", FOAOfFunctions, FOAOfName, FOAOfNameOdinals);
int * FuncTable = (int*)((DWORD)pDosHeader + FOAOfFunctions);
int* NameTable = (int*)((DWORD)pDosHeader + FOAOfName);
short* Ordinals = (short*)((DWORD)pDosHeader + FOAOfNameOdinals);

////注意下面是随机打印的
//for(int i = 0; i < pExportTable->NumberOfNames; ++i)
//{
// printf("导出函数地址为:%X ", RVATOFOA(pSectionHeader, *FuncTable, pFileHeader->NumberOfSections));
//
// char*name=(char*)pDosHeader + (RVATOFOA(pSectionHeader, *NameTable, pFileHeader->NumberOfSections));
// printf("名称为:%s ", name);
// //函数序号存储的不是RVA,而是序号,直接解引用即可,但是要注意是short型
// printf("函数序号为:%X\n", *Ordinals);
// NameTable++;
// FuncTable++;
// Ordinals++;
//}


//按函数名称导出
char funcname[] = "WinDbgExtensionDllInit";
for (int i = 0; i < pExportTable->NumberOfNames; ++i)
{
char* name = (char*)pDosHeader + (RVATOFOA(pSectionHeader, *NameTable, pFileHeader->NumberOfSections));
//printf("函数名称为:%s\n", name);
//如果找到我们的函数名时,先把下标去序号表找,然后取出里面的值,再拿去函数地址表找
if (strcmp(funcname, name) == 0)
{
Ordinals += i;
printf("函数名称为:%s\n", name);
printf("函数序号为:%X\n", *Ordinals);
printf("导出函数地址为:%X ", RVATOFOA(pSectionHeader, *(FuncTable+*Ordinals), pFileHeader->NumberOfSections));
break;
}
else//否则就是按照序号导出的,只需要将
{

}
NameTable++;
}
return;
}
void oprate_pe()
{
LPVOID FileBuffer = NULL;
ReadFileToBuffer(&FileBuffer);
PrintExportTable(FileBuffer);
return ;
}
int main()
{
oprate_pe();
return 0;
}