PE文件结构(六)

Last updated on October 7, 2023 pm

PE练习,扩大节、合并节

回顾

此前已经在一个节的空白区增加shellcode,而后又通过新增一个节的方式增加shellcode,实际上也可以通过对节进行合并、扩大操作来满足其他需求

练习

要求

1.扩大最后一个节

2.合并所有节

要求解决的问题

扩大最后一个节

Q1:为什么是扩大最后一个节

A1:如果扩大中间的节,那么后面的节的地址就会全部变化,所有地址就全都无法正常使用,而扩大最后一个节则不会影响已有地址

Q2:扩大多少合适

A2:最好也是文件对齐FileAlignmentr和内存对齐SectionAlignment的倍数,这样可以减少很多麻烦,就可以直接在原文件状态下扩大,而不需要再考虑对齐。

Q3:需要修改什么值

A3:跟大小有关的值都需要修改,OptionalHeader里的SizeOfImage,最后一个节目录项的Misc、SizeOfRawData、

合并所有节

Q1:应该在哪种状态下合并

A1:只能在内存状态下合并,因为合并所有节后,只有一个节目录项,只能通过这个去找节区。如果在文件状态下合并,那么后面的节区都不能正确放到它们该处的位置上。而后直接将内存状态保存为文件状态,也就是说这时候文件状态就已经是内存对齐的了。

Q2:需要修改哪些值

A2:FileHeader里的NumberOfSections改为1;因为文件状态就是内存状态所以第一个节目录项的Misc、PointerToRawData需要按照内存状态下改变。属性值也需要修改,因为是合并所有节,那么就应该具有所有节的属性

Q3:文件大小该如何确定

A3:可以很方便的使用OptionalHeader里的SizeOfImage减去第一个节表开始地方,剩下就都是合并节后的大小了,还需要将第一个节目录项的SizeOfRawData改为这个大小。

note:最后需要其他节目录项清零;fwrite的时候size要选为SizeOfImageHeader;实际上在Windows看来并不存在这些节的划分,只是人为通过不同的属性来划分,每一个节干特定的事,因此只需要把所有节属性都加上去,程序就一定可以正常运行,这是合并节可行的底层逻辑。

代码

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
#include<stdio.h>
#include<windows.h>
#include<malloc.h>

# define EnlargeSize 0x1000
DWORD Size(FILE* fp){
DWORD size = 0;
fseek(fp,0,SEEK_END);
size = ftell(fp);
fseek(fp,0,SEEK_SET);
return size;
}


char* FileToImage(char* filebuffer){

//定义一些指针
PIMAGE_DOS_HEADER DosHeader = NULL;
PIMAGE_NT_HEADERS NTHeader = NULL;
PIMAGE_FILE_HEADER FileHeader = NULL;
PIMAGE_OPTIONAL_HEADER OptionalHeader = NULL;
PIMAGE_SECTION_HEADER SectionHeader = NULL;
char* TemBuffer = NULL;

//简单判断有效性
if (!filebuffer)
{
printf("Invalid buffer!\n");
return 0;
}

if (*(PWORD)filebuffer != IMAGE_DOS_SIGNATURE)
{
printf("not a PE file!\n");
return 0;
}

//开始赋值相应指针
DosHeader = (PIMAGE_DOS_HEADER)filebuffer;
NTHeader = (PIMAGE_NT_HEADERS) (filebuffer + DosHeader->e_lfanew);
FileHeader = (PIMAGE_FILE_HEADER)(filebuffer + DosHeader->e_lfanew + 4);
OptionalHeader = (PIMAGE_OPTIONAL_HEADER)(filebuffer + DosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER);
SectionHeader = (PIMAGE_SECTION_HEADER)(filebuffer + DosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER + FileHeader->SizeOfOptionalHeader);

//申请内存中大小
TemBuffer = (char*)malloc(OptionalHeader->SizeOfImage);

//初始化并复制头部数据
memset(TemBuffer,0,OptionalHeader->SizeOfImage);
memcpy(TemBuffer,DosHeader,OptionalHeader->SizeOfHeaders);

//开始复制节区数据
for(int i=0;i<FileHeader->NumberOfSections;i++){
memcpy((TemBuffer + SectionHeader->VirtualAddress),(filebuffer + SectionHeader->PointerToRawData),SectionHeader->SizeOfRawData);
//更新为下一个节区的结构体
// SectionHeader = (PIMAGE_SECTION_HEADER)(filebuffer + DosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER + FileHeader->SizeOfOptionalHeader + 40 * (i + 1));
SectionHeader +=1;
}

return TemBuffer;
}

char* Enlage(char* buffer){
//原buffer的头部信息
PIMAGE_DOS_HEADER DosHeader = NULL;
PIMAGE_NT_HEADERS NTHeader = NULL;
PIMAGE_FILE_HEADER FileHeader = NULL;
PIMAGE_OPTIONAL_HEADER OptionalHeader = NULL;
PIMAGE_SECTION_HEADER SectionHeader = NULL;

DosHeader = (PIMAGE_DOS_HEADER)buffer;
NTHeader = (PIMAGE_NT_HEADERS) (buffer + DosHeader->e_lfanew);
FileHeader = (PIMAGE_FILE_HEADER)(buffer + DosHeader->e_lfanew + 4);
OptionalHeader = (PIMAGE_OPTIONAL_HEADER)(buffer + DosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER);
SectionHeader = (PIMAGE_SECTION_HEADER)(buffer + DosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER + FileHeader->SizeOfOptionalHeader);


// char* ImageBuffer = FileToImage(buffer);

char* NewBuffer = (char*)malloc(OptionalHeader->SizeOfImage + EnlargeSize);
memset(NewBuffer,0,OptionalHeader->SizeOfImage + EnlargeSize);
memcpy(NewBuffer,buffer,OptionalHeader->SizeOfImage);

DosHeader = (PIMAGE_DOS_HEADER)NewBuffer;
NTHeader = (PIMAGE_NT_HEADERS) (NewBuffer + DosHeader->e_lfanew);
FileHeader = (PIMAGE_FILE_HEADER)(NewBuffer + DosHeader->e_lfanew + 4);
OptionalHeader = (PIMAGE_OPTIONAL_HEADER)(NewBuffer + DosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER);
SectionHeader = (PIMAGE_SECTION_HEADER)(NewBuffer + DosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER + FileHeader->SizeOfOptionalHeader);


PIMAGE_SECTION_HEADER LastSectionHeader = SectionHeader + FileHeader->NumberOfSections -1;
DWORD LastSize = LastSectionHeader->Misc.VirtualSize > LastSectionHeader->SizeOfRawData?LastSectionHeader->Misc.VirtualSize : LastSectionHeader->SizeOfRawData;

LastSectionHeader->Misc.VirtualSize = LastSize + EnlargeSize;
LastSectionHeader->SizeOfRawData = LastSize + EnlargeSize;
OptionalHeader->SizeOfImage += EnlargeSize;

return NewBuffer;

}

char* Merge(char* buffer,DWORD &size){

char* ImageBuffer = FileToImage(buffer);

PIMAGE_DOS_HEADER DosHeader = NULL;
PIMAGE_NT_HEADERS NTHeader = NULL;
PIMAGE_FILE_HEADER FileHeader = NULL;
PIMAGE_OPTIONAL_HEADER OptionalHeader = NULL;
PIMAGE_SECTION_HEADER SectionHeader = NULL;
PIMAGE_SECTION_HEADER NextSectionHeader =NULL;

DosHeader = (PIMAGE_DOS_HEADER)ImageBuffer;
NTHeader = (PIMAGE_NT_HEADERS) (ImageBuffer + DosHeader->e_lfanew);
FileHeader = (PIMAGE_FILE_HEADER)(ImageBuffer + DosHeader->e_lfanew + 4);
OptionalHeader = (PIMAGE_OPTIONAL_HEADER)(ImageBuffer + DosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER);
SectionHeader = (PIMAGE_SECTION_HEADER)(ImageBuffer + DosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER + FileHeader->SizeOfOptionalHeader);


SectionHeader->Misc.VirtualSize = OptionalHeader->SizeOfImage - SectionHeader->VirtualAddress;
SectionHeader->SizeOfRawData = OptionalHeader->SizeOfImage - SectionHeader->VirtualAddress;
SectionHeader->PointerToRawData = SectionHeader->VirtualAddress;
NextSectionHeader = SectionHeader;
for(int i=0;i<FileHeader->NumberOfSections;i++){
NextSectionHeader += 1;
SectionHeader->Characteristics |= NextSectionHeader->Characteristics;
}

FileHeader->NumberOfSections = 1;

memset(NextSectionHeader,0,IMAGE_SIZEOF_SECTION_HEADER * (FileHeader->NumberOfSections -1));
size = OptionalHeader->SizeOfImage;
return ImageBuffer;
}
int main(){
char* buffer;

FILE* fp1 = NULL;
FILE* fp2 = NULL;
errno_t err_1 = fopen_s(&fp1, "C:\\Users\\yongrin\\Desktop\\PE_info.exe", "rb");
errno_t err_2 = fopen_s(&fp2, "C:\\Users\\yongrin\\Desktop\\PE_info_changed.exe", "wb");

DWORD size = Size(fp1);
buffer = (char*)malloc(size);
fread(buffer,size,1,fp1);

char* newbuffer;
// newbuffer = Enlage(buffer);
newbuffer = Merge(buffer,size);

fwrite(newbuffer,size,1,fp2);

return 0;
}

PE文件结构(六)
http://example.com/2023/07/04/PE_5/
Author
yring
Posted on
July 4, 2023
Licensed under