Created
May 27, 2021 15:17
-
-
Save Noxwizard/17d823a49729bfe63b0643136591c98f to your computer and use it in GitHub Desktop.
Building PE files from scratch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Windows.h> | |
#include <iostream> | |
int main(int argc, char** argv) | |
{ | |
IMAGE_DOS_HEADER dos; | |
memset(&dos, 0, sizeof(IMAGE_DOS_HEADER)); | |
// Only these two fields are actually parsed | |
dos.e_magic = 0x5A4D; // "MZ" | |
dos.e_lfanew = sizeof(IMAGE_DOS_HEADER); // File address of new exe header (NT) | |
IMAGE_NT_HEADERS32 nt_header; | |
nt_header.Signature = 0x4550; // "PE" | |
nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_I386; | |
nt_header.FileHeader.NumberOfSections = 3; // text, data, rdata | |
nt_header.FileHeader.TimeDateStamp = 0x1234; | |
nt_header.FileHeader.PointerToSymbolTable = 0; | |
nt_header.FileHeader.NumberOfSymbols = 0; | |
nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32); | |
nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE; | |
nt_header.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC; | |
nt_header.OptionalHeader.MajorLinkerVersion = 0; | |
nt_header.OptionalHeader.MinorLinkerVersion = 0; | |
nt_header.OptionalHeader.SizeOfCode = 66560; // Size of .text section | |
nt_header.OptionalHeader.SizeOfInitializedData = 93696; // Size of .text + data sections | |
nt_header.OptionalHeader.SizeOfUninitializedData = 0; | |
nt_header.OptionalHeader.AddressOfEntryPoint = 0x1CBD; | |
nt_header.OptionalHeader.BaseOfCode = 0x1000; //FIX if VA of .text is not 0x1000 | |
nt_header.OptionalHeader.BaseOfData = 0x012000; // Start of .rdata section (RVA) | |
nt_header.OptionalHeader.ImageBase = 0x00400000; | |
nt_header.OptionalHeader.SectionAlignment = 0x1000; | |
nt_header.OptionalHeader.FileAlignment = 0x200; | |
nt_header.OptionalHeader.MajorOperatingSystemVersion = 6; | |
nt_header.OptionalHeader.MinorOperatingSystemVersion = 0; | |
nt_header.OptionalHeader.MajorImageVersion = 0; | |
nt_header.OptionalHeader.MinorImageVersion = 0; | |
nt_header.OptionalHeader.MajorSubsystemVersion = 6; | |
nt_header.OptionalHeader.MinorSubsystemVersion = 0; | |
nt_header.OptionalHeader.Win32VersionValue = 0; | |
nt_header.OptionalHeader.SizeOfImage = 0x27000; | |
nt_header.OptionalHeader.SizeOfHeaders = 0x400; | |
nt_header.OptionalHeader.CheckSum = 0; | |
nt_header.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI; | |
nt_header.OptionalHeader.DllCharacteristics = 0; // IMAGE_DLLCHARACTERISTICS_NO_SEH; // | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT; | |
nt_header.OptionalHeader.SizeOfStackReserve = 0x100000; | |
nt_header.OptionalHeader.SizeOfStackCommit = 0x1000; | |
nt_header.OptionalHeader.SizeOfHeapReserve = 0x100000; | |
nt_header.OptionalHeader.SizeOfHeapCommit = 0x1000; | |
nt_header.OptionalHeader.LoaderFlags = 0; | |
nt_header.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; | |
memset(nt_header.OptionalHeader.DataDirectory, 0, sizeof(IMAGE_DATA_DIRECTORY) * IMAGE_NUMBEROF_DIRECTORY_ENTRIES); | |
// Import directory | |
nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = 0x017004; | |
nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = 0x28; | |
// Import Address Table (IAT) | |
nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0x012000; | |
nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0x144; | |
IMAGE_EXPORT_DIRECTORY d; | |
IMAGE_SECTION_HEADER text_section; | |
memset(&text_section, 0, sizeof(IMAGE_SECTION_HEADER)); | |
const char* text_name = ".text"; | |
memcpy(text_section.Name, text_name, 5); | |
text_section.VirtualAddress = 0x1000; | |
text_section.SizeOfRawData = 0x10400; | |
text_section.Misc.VirtualSize = text_section.SizeOfRawData; | |
text_section.PointerToRawData = 0x400; | |
text_section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ; | |
IMAGE_SECTION_HEADER rdata_section; | |
memset(&rdata_section, 0, sizeof(IMAGE_SECTION_HEADER)); | |
const char* rdata_name = ".rdata"; | |
memcpy(rdata_section.Name, rdata_name, 6); | |
rdata_section.VirtualAddress = 0x012000; | |
rdata_section.SizeOfRawData = 0x5800; | |
rdata_section.Misc.VirtualSize = rdata_section.SizeOfRawData; | |
rdata_section.PointerToRawData = 0x10800; | |
rdata_section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; | |
IMAGE_SECTION_HEADER data_section; | |
memset(&data_section, 0, sizeof(IMAGE_SECTION_HEADER)); | |
const char* data_name = ".data"; | |
memcpy(data_section.Name, data_name, 5); | |
data_section.VirtualAddress = 0x18000; | |
data_section.SizeOfRawData = 0x1200; | |
data_section.Misc.VirtualSize = data_section.SizeOfRawData+0x1E00; // Add a pseudo BSS section at the end of this segment | |
data_section.PointerToRawData = 0x16000; | |
data_section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; | |
// DOS header | |
// DOS Stub (optional) | |
// NT header | |
// Optional header (not optional) | |
// Section table | |
// .text | |
// .rdata | |
// .data | |
// Binary data | |
// .text @ 0x400 - size: 0x10400 - VA: 0x401000-4113FF | |
// .rdata @ 0x10800 - size: 0x5800 - VA: 0x412000-4177FF | |
// .data @ 0x16000 - size: 0x1200 - VA: 0x418000-4191FF | |
size_t header_size = sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS32) + sizeof(IMAGE_SECTION_HEADER) * 3; | |
size_t padding_size = 0x400 - header_size; | |
size_t total_size = header_size + padding_size + text_section.SizeOfRawData + data_section.SizeOfRawData + rdata_section.SizeOfRawData; | |
std::cout << total_size << std::endl; | |
unsigned char* buf = (unsigned char*)VirtualAlloc(NULL, total_size, MEM_COMMIT, PAGE_READWRITE); | |
unsigned char* start = buf; | |
// Headers | |
memcpy(buf, &dos, sizeof(IMAGE_DOS_HEADER)); | |
buf += sizeof(IMAGE_DOS_HEADER); | |
memcpy(buf, &nt_header, sizeof(IMAGE_NT_HEADERS32)); | |
buf += sizeof(IMAGE_NT_HEADERS32); | |
memcpy(buf, &text_section, sizeof(IMAGE_SECTION_HEADER)); | |
buf += sizeof(IMAGE_SECTION_HEADER); | |
memcpy(buf, &rdata_section, sizeof(IMAGE_SECTION_HEADER)); | |
buf += sizeof(IMAGE_SECTION_HEADER); | |
memcpy(buf, &data_section, sizeof(IMAGE_SECTION_HEADER)); | |
buf += sizeof(IMAGE_SECTION_HEADER); | |
// Padding | |
buf += padding_size; | |
// Binary data | |
FILE* fp = fopen("C:\\Users\\User\\Desktop\\eset\\.text", "rb"); | |
fread(buf, 1, text_section.SizeOfRawData, fp); | |
buf += text_section.SizeOfRawData; | |
fclose(fp); | |
fp = fopen("C:\\Users\\User\\Desktop\\eset\\.rdata", "rb"); | |
fread(buf, 1, rdata_section.SizeOfRawData, fp); | |
buf += rdata_section.SizeOfRawData; | |
fclose(fp); | |
fp = fopen("C:\\Users\\User\\Desktop\\eset\\.data", "rb"); | |
fread(buf, 1, data_section.SizeOfRawData, fp); | |
buf += data_section.SizeOfRawData; | |
fclose(fp); | |
fp = fopen("C:\\Users\\User\\Desktop\\eset\\new.exe", "wb"); | |
fwrite(start, 1, total_size, fp); | |
fclose(fp); | |
VirtualFree(buf, 0, MEM_RELEASE); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment