Skip to content

Commit 8cd2db3

Browse files
committed
Extend PE packing functions to 64bits architectures.
1 parent 8a0852c commit 8cd2db3

File tree

9 files changed

+693
-53
lines changed

9 files changed

+693
-53
lines changed

TODO.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ TODO
44
General
55
-------
66

7+
* Find a nice way to factorize code between 32 and 64bits structures for PE files
8+
79
Specific
810
--------
911

@@ -12,7 +14,6 @@ Specific
1214
* Extend peviewer (Directories, Symbols, etc.)
1315
* Add print function to sum up the PE file
1416
2. PEPacker
15-
* Extends the code to deal with 64bits architecture
1617

1718
2. ELF
1819
* Everything

pts/pe/pepacker/pepacker32.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ int pack32(PE32 *pe32, Loader loader) {
2424
unsigned int free_space = 0;
2525
unsigned int error = 0;
2626

27-
free_space = get_available_section_space(*pe32);
27+
free_space = get_available_section_space32(*pe32);
2828
printf("[+] Packing method:\n");
2929
if (free_space >= (loader->length * sizeof(*loader->payload))) {
3030
printf("\tAppend payload to the code section\n");
@@ -55,7 +55,7 @@ int append_loader32(PE32 *pe32, Loader loader) {
5555
unsigned int id = 0;
5656
uint32_t oep = 0;
5757

58-
id = get_code_section(*pe32);
58+
id = get_code_section32(*pe32);
5959
offset_start_free_space = (*pe32)->sections_headers[id]->PointerToRawData + \
6060
(*pe32)->sections_headers[id]->Misc.VirtualSize;
6161

@@ -105,7 +105,7 @@ int add_section32(PE32 *pe32, Loader loader) {
105105
uint32_t file_alignment = 0;
106106
uint32_t oep = 0;
107107

108-
if (!check_free_sections_headers_space(*pe32)) {
108+
if (check_free_sections_headers_space32(*pe32)) {
109109
fputs("Error: not enough space to add a new section", stderr);
110110
return NO_FREE_SPACE_IN_SECTIONS_HEADERS;
111111
}

pts/pe/pepacker/pepacker64.c

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
#include <stdlib.h>
2+
#include <stdio.h>
3+
#include <stdint.h>
4+
#include <string.h>
5+
6+
#include <errors.h>
7+
#include <pepacker64.h>
8+
#include <pestruct.h>
9+
#include <peviewer.h>
10+
#include <peviewer64.h>
11+
12+
/**
13+
* \fn int pack64(PE64 *pe64, Loader loader)
14+
* \brief Pack the PE file with the loader.
15+
*
16+
* \todo Process the errors.
17+
*
18+
* \param pe64 Dump of the PE headers.
19+
* \param loader Payload to add in pe64.
20+
*
21+
* \return The error code from the called functions.
22+
*/
23+
int pack64(PE64 *pe64, Loader loader) {
24+
unsigned int free_space = 0;
25+
unsigned int error = 0;
26+
27+
free_space = get_available_section_space64(*pe64);
28+
printf("[+] Packing method:\n");
29+
if (free_space >= (loader->length * sizeof(*loader->payload))) {
30+
printf("\tAppend payload to the code section\n");
31+
error = append_loader64(pe64, loader);
32+
}
33+
else {
34+
printf("\tAdd a new section for the payload\n");
35+
error = add_section64(pe64, loader);
36+
error = write_loader64(*pe64, loader);
37+
}
38+
39+
return error;
40+
}
41+
42+
/**
43+
* \fn int append_loader64(PE64 *pe64, Loader loader)
44+
* \brief Append the payload at the end of the code section.
45+
*
46+
* \param pe64 Dump of the PE headers.
47+
* \param loader Payload to add in pe64.
48+
*
49+
* \return FILE_ERROR if it cannot handle the file.
50+
* \return SUCCESS if it succeeds.
51+
*/
52+
int append_loader64(PE64 *pe64, Loader loader) {
53+
FILE *pe_file = NULL;
54+
unsigned int offset_start_free_space = 0;
55+
unsigned int id = 0;
56+
uint32_t oep = 0;
57+
58+
id = get_code_section64(*pe64);
59+
offset_start_free_space = (*pe64)->sections_headers[id]->PointerToRawData + \
60+
(*pe64)->sections_headers[id]->Misc.VirtualSize;
61+
62+
/* Update payload */
63+
oep = (*pe64)->optional_header->ImageBase + (*pe64)->optional_header->AddressOfEntryPoint;
64+
memcpy(&loader->payload[loader->offset_oep], &oep, sizeof(uint32_t));
65+
66+
/* Update headers */
67+
(*pe64)->optional_header->AddressOfEntryPoint = (*pe64)->sections_headers[id]->VirtualAddress + \
68+
(*pe64)->sections_headers[id]->Misc.VirtualSize;
69+
(*pe64)->sections_headers[id]->Misc.VirtualSize = (*pe64)->sections_headers[id]->Misc.VirtualSize + \
70+
loader->length * sizeof(*loader->payload);
71+
72+
save_dump64(*pe64);
73+
74+
pe_file = fopen((*pe64)->filename, "rb+");
75+
if (pe_file == NULL) {
76+
perror("Error: Cannot open the file");
77+
return FILE_ERROR;
78+
}
79+
80+
fseek(pe_file, offset_start_free_space, SEEK_SET);
81+
fwrite((void *)loader->payload, loader->length * sizeof(*loader->payload), 1, pe_file);
82+
83+
fclose(pe_file);
84+
return SUCCESS;
85+
}
86+
87+
/**
88+
* \fn int add_section64(PE64 *pe64, Loader loader)
89+
* \brief Create a new section for the payload.
90+
*
91+
* \param pe64 Dump of the PE headers.
92+
* \param loader Payload to add in pe64.
93+
*
94+
* \return NO_FREE_SPACE_IN_SECTIONS_HEADERS if there is no available space for a new section header.
95+
* \return ALLOCATION_ERROR if it cannot allocate memory.
96+
* \return SUCCESS if it succeeds.
97+
*/
98+
int add_section64(PE64 *pe64, Loader loader) {
99+
PIMAGE_SECTION_HEADER new_section = NULL;
100+
PIMAGE_OPTIONAL_HEADER64 optional_header = NULL;
101+
PIMAGE_FILE_HEADER coff_header = NULL;
102+
PIMAGE_SECTION_HEADER last_section_header = NULL;
103+
const uint32_t section_size = loader->length * sizeof(*loader->payload) + sizeof(uint32_t) + 1;
104+
uint32_t section_alignment = 0;
105+
uint32_t file_alignment = 0;
106+
uint32_t oep = 0;
107+
108+
if (check_free_sections_headers_space64(*pe64)) {
109+
fputs("Error: not enough space to add a new section", stderr);
110+
return NO_FREE_SPACE_IN_SECTIONS_HEADERS;
111+
}
112+
113+
/* Allocate the new section for the binary */
114+
new_section = (PIMAGE_SECTION_HEADER)calloc(1, sizeof(IMAGE_SECTION_HEADER));
115+
if (new_section == NULL) {
116+
perror("Error: cannot allocate memory for the new section");
117+
return ALLOCATION_ERROR;
118+
}
119+
120+
121+
section_alignment = (*pe64)->optional_header->SectionAlignment;
122+
file_alignment = (*pe64)->optional_header->FileAlignment;
123+
124+
last_section_header = (*pe64)->sections_headers[(*pe64)->number_of_sections - 1];
125+
126+
/* Fields of the new section */
127+
memcpy(new_section->Name, ".packer", 7);
128+
new_section->VirtualAddress = get_alignment(
129+
last_section_header->VirtualAddress + last_section_header->Misc.VirtualSize,
130+
section_alignment
131+
);
132+
/* TODO: check if VirtualSize needs to be aligned */
133+
new_section->Misc.VirtualSize = section_size;
134+
new_section->SizeOfRawData = get_alignment(
135+
section_size,
136+
file_alignment
137+
);
138+
new_section->PointerToRawData = get_alignment(
139+
last_section_header->PointerToRawData + last_section_header->SizeOfRawData,
140+
file_alignment
141+
);
142+
new_section->Characteristics = IMAGE_SCN_MEM_EXECUTE | \
143+
IMAGE_SCN_MEM_READ | \
144+
IMAGE_SCN_CNT_CODE;
145+
new_section->PointerToRelocations = 0x0;
146+
new_section->PointerToLinenumbers = 0x0;
147+
new_section->NumberOfRelocations = 0x0;
148+
new_section->NumberOfLinenumbers = 0x0;
149+
150+
/* Update the payload */
151+
oep = (*pe64)->optional_header->ImageBase + (*pe64)->optional_header->AddressOfEntryPoint;
152+
memcpy(&loader->payload[loader->offset_oep], &oep, sizeof(uint32_t));
153+
154+
/* Update the PE header */
155+
(*pe64)->number_of_sections = (*pe64)->number_of_sections + 1;
156+
(*pe64)->coff_header->NumberOfSections = (*pe64)->coff_header->NumberOfSections + 1;
157+
(*pe64)->optional_header->SizeOfImage = get_alignment(
158+
(*pe64)->optional_header->SizeOfImage + section_size,
159+
section_alignment
160+
);
161+
(*pe64)->optional_header->SizeOfHeaders = get_alignment(
162+
(*pe64)->optional_header->SizeOfHeaders + sizeof(IMAGE_SECTION_HEADER),
163+
file_alignment
164+
);
165+
(*pe64)->optional_header->AddressOfEntryPoint = new_section->VirtualAddress;
166+
167+
/* Add the new section to the PE headers */
168+
(*pe64)->sections_headers = (PIMAGE_SECTION_HEADER *)realloc((void *)(*pe64)->sections_headers, (*pe64)->number_of_sections * sizeof(PIMAGE_SECTION_HEADER));
169+
if ((*pe64)->sections_headers == NULL) {
170+
perror("Error: cannot re-allocate memory for the new section in PE64");
171+
free(new_section);
172+
return ALLOCATION_ERROR;
173+
}
174+
175+
(*pe64)->sections_headers[(*pe64)->number_of_sections - 1] = (PIMAGE_SECTION_HEADER)calloc(1, sizeof(IMAGE_SECTION_HEADER));
176+
if ((*pe64)->sections_headers[(*pe64)->number_of_sections - 1] == NULL) {
177+
perror("Error: cannot allocate memory for the new section in PE64");
178+
free(new_section);
179+
return ALLOCATION_ERROR;
180+
}
181+
memcpy(
182+
(void *)(*pe64)->sections_headers[(*pe64)->number_of_sections - 1],
183+
new_section,
184+
sizeof(IMAGE_SECTION_HEADER)
185+
);
186+
187+
save_dump64(*pe64);
188+
save_section64(*pe64);
189+
190+
free(new_section);
191+
free(optional_header);
192+
free(last_section_header);
193+
free(coff_header);
194+
return SUCCESS;
195+
}
196+
197+
/**
198+
* \fn int save_section64(const PE64 pe64)
199+
* \brief Save the last section header into the file.
200+
*
201+
* \param pe64 Dump of the PE headers.
202+
*
203+
* \return FILE_ERROR if it cannot handle the file.
204+
* \return SUCCESS if it succeeds.
205+
*/
206+
int save_section64(const PE64 pe64) {
207+
FILE *pe_file = NULL;
208+
unsigned int offset_last_section = 0;
209+
210+
pe_file = fopen(pe64->filename, "rb+");
211+
if (pe_file == NULL) {
212+
perror("Error: cannot open the file");
213+
return FILE_ERROR;
214+
}
215+
216+
/* Compute offset of the last section */
217+
offset_last_section = pe64->offset_first_section_header + (pe64->number_of_sections - 1) * sizeof(IMAGE_SECTION_HEADER);
218+
fseek(pe_file, offset_last_section, SEEK_SET);
219+
/* TODO: add the section without overwritting the file */
220+
fwrite((void *)pe64->sections_headers[pe64->number_of_sections - 1], sizeof(IMAGE_SECTION_HEADER), 1, pe_file);
221+
printf("[+] New section header has been saved (offset: 0x%X)\n", offset_last_section);
222+
printf("\tName of the new section: %s\n", pe64->sections_headers[pe64->number_of_sections - 1]->Name);
223+
224+
fclose(pe_file);
225+
226+
return SUCCESS;
227+
}
228+
229+
/**
230+
* \fn int write_loader64(const PE64 pe64, const Loader loader)
231+
* \brief Save the payload into the file.
232+
*
233+
* \param pe64 Dump of the PE headers.
234+
* \param loader Payload to add in pe64.
235+
*
236+
* \return FILE_ERROR if it cannot handle the file.
237+
* \return SUCCESS if it succeeds.
238+
*/
239+
int write_loader64(const PE64 pe64, const Loader loader) {
240+
FILE *pe_file = NULL;
241+
unsigned int filled = 0;
242+
unsigned int i = 0;
243+
const uint8_t null = 0x00;
244+
245+
pe_file = fopen(pe64->filename, "rb+");
246+
if (pe_file == NULL) {
247+
perror("Error: cannot open the file");
248+
return FILE_ERROR;
249+
}
250+
251+
fseek(pe_file, 0, SEEK_END);
252+
fwrite((void *)loader->payload, loader->length * sizeof(*loader->payload), 1, pe_file);
253+
printf("[+] Save payload\n");
254+
255+
/* Fill the rest of the section */
256+
filled = pe64->optional_header->FileAlignment - loader->length * sizeof(*loader->payload);
257+
for (i = 0; i < filled; i = i + 1)
258+
fwrite(&null, sizeof(null), 1, pe_file);
259+
260+
fclose(pe_file);
261+
return SUCCESS;
262+
}
263+
264+
/**
265+
* \fn int save_dump64(const PE64 pe64)
266+
* \brief Save all the PE headers into the file.
267+
*
268+
* \param pe64 Dump of the PE headers.
269+
*
270+
* \return FILE_ERROR if it cannot handle the file.
271+
* \return SUCCESS if it succeeds.
272+
*/
273+
int save_dump64(const PE64 pe64) {
274+
FILE *pe_file = NULL;
275+
unsigned int i = 0;
276+
277+
pe_file = fopen(pe64->filename, "rb+");
278+
if (pe_file == NULL) {
279+
perror("Error: cannot open the file");
280+
return FILE_ERROR;
281+
}
282+
283+
printf("[+] Save the new PE headers:\n");
284+
fseek(pe_file, pe64->offset_dos_header, SEEK_SET);
285+
fwrite((void *)pe64->dos_header, sizeof(IMAGE_DOS_HEADER), 1, pe_file);
286+
printf("\tDOS header saved\n");
287+
288+
fseek(pe_file, pe64->offset_pe_header, SEEK_SET);
289+
fwrite((void *)pe64->pe_header, sizeof(IMAGE_NT_HEADERS64), 1, pe_file);
290+
printf("\tPE header saved\n");
291+
292+
fseek(pe_file, pe64->offset_coff_header, SEEK_SET);
293+
fwrite((void *)pe64->coff_header, sizeof(IMAGE_FILE_HEADER), 1, pe_file);
294+
printf("\tCOFF header saved\n");
295+
296+
fseek(pe_file, pe64->offset_optional_header, SEEK_SET);
297+
fwrite((void *)pe64->optional_header, sizeof(IMAGE_OPTIONAL_HEADER64), 1, pe_file);
298+
printf("\tOPTIONAL header saved\n");
299+
300+
fseek(pe_file, pe64->offset_first_section_header, SEEK_SET);
301+
for (i = 0; i < pe64->number_of_sections; i = i + 1) {
302+
fwrite((void *)pe64->sections_headers[i], sizeof(IMAGE_SECTION_HEADER), 1, pe_file);
303+
printf("\tSECTION header saved (%s)\n", pe64->sections_headers[i]->Name);
304+
}
305+
306+
fclose(pe_file);
307+
return SUCCESS;
308+
}

pts/pe/pepacker/pepacker64.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#ifndef PEPACKER64_H_INCLUDED
2+
#define PEPACKER64_H_INCLUDED
3+
4+
#include <pestruct.h>
5+
#include <peloader.h>
6+
7+
int pack64(PE64 *pe64, Loader loader);
8+
int append_loader64(PE64 *pe64, Loader loader);
9+
int add_section64(PE64 *pe64, Loader loader);
10+
int save_section64(const PE64 pe64);
11+
int write_loader64(const PE64 pe64, const Loader loader);
12+
int save_dump64(const PE64 pe64);
13+
14+
#endif /* PEPACKER64_H_INCLUDED */

pts/pe/peviewer/peviewer32.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ void delete_pe32(PE32 *pe32) {
348348
* \return SUCCESS if there is enough space for a new section header.
349349
* \return NO_FREE_SPACE_IN_SECTIONS_HEADERS otherwise.
350350
*/
351-
int check_free_sections_headers_space(const PE32 pe32) {
351+
int check_free_sections_headers_space32(const PE32 pe32) {
352352
unsigned int offset_end_sections_headers = 0;
353353
unsigned int offset_start_raw_code = 0;
354354
unsigned int i = 0;
@@ -385,10 +385,10 @@ int check_free_sections_headers_space(const PE32 pe32) {
385385
* \return NO_CODE_SECTION_FOUND if the code section cannot be found.
386386
* \return The amount of free space otherwise.
387387
*/
388-
int get_available_section_space(const PE32 pe32) {
388+
int get_available_section_space32(const PE32 pe32) {
389389
int id = 0;
390390

391-
id = get_code_section(pe32);
391+
id = get_code_section32(pe32);
392392
if (id == NO_CODE_SECTION_FOUND) {
393393
fputs("Invalid ID of the code section", stderr);
394394
return NO_CODE_SECTION_FOUND;
@@ -411,7 +411,7 @@ int get_available_section_space(const PE32 pe32) {
411411
* \return NO_CODE_SECTION_FOUND if the code section cannot be found.
412412
* \return The id of the code section.
413413
*/
414-
int get_code_section(const PE32 pe32) {
414+
int get_code_section32(const PE32 pe32) {
415415
unsigned int i = 0;
416416
int id = NO_CODE_SECTION_FOUND;
417417

0 commit comments

Comments
 (0)