Someone posted an answer, but later was deleted before I could make it the official answer, anyways, we just need to grab the DOS headers, get the e_lfanew value from DOS headers, use it to calculate start address from NT headers, sum the NT headers and DOS headers address to get the section table, add a new IMAGE_SECTION_HEADER structure calculate SizeOfHeaders and SizeOfImage alignment from FileAlignment and SectionAlignment. This is the code plus some editions I made:
#include <Windows.h>
#include <stdio.h>
PIMAGE_DOS_HEADER lpDosHeader;
PIMAGE_NT_HEADERS lpNtHeaders;
PIMAGE_FILE_HEADER lpFileHeader;
PIMAGE_OPTIONAL_HEADER lpOptionalHeader;
PIMAGE_SECTION_HEADER lpImageSections;
IMAGE_SECTION_HEADER ourSection;
FILE* fileStream = NULL;
char* peFileBuffer = NULL;
char* fileName = NULL;
char* outputFileName = NULL;
char* binaryFileName = NULL;
char* sectionName = NULL;
char* sectionData = NULL;
int sizeofNewSectionData = 0;
int nextArg = 1;
int align(int value, int alignment);
int main(int argc, char* argv[])
{
PIMAGE_SECTION_HEADER lpLastSection = NULL;
int newFileSize = 0;
int fileAlignmentOfPEImage = 0;
int sectionAlignmentOfPEImage = 0;
if (argc != 5)
{
return -1;
}
fileName = argv[nextArg++];
outputFileName = argv[nextArg++];
sectionName = argv[nextArg++];
if (strlen(sectionName) + 1 > 8)
{
return -1;
}
binaryFileName = argv[nextArg++];
FILE* pre_SectionData = fopen(binaryFileName, "rb"); // Read beacon binary
fseek(pre_SectionData, 0, SEEK_END); // Seek to SEEK_END
size_t sizeofNewSectionData = ftell(pre_SectionData); // Get size of new section
fseek(pre_SectionData, 0, SEEK_SET); // Seek to SEEK_SET
sectionData = (char*)malloc(sizeofNewSectionData); // Allocate enough heap memory
fread(sectionData, 1, sizeofNewSectionData, pre_SectionData);
sizeofNewSectionData = (int)sizeofNewSectionData;
fileStream = fopen(fileName, "rb"); // Read stub binary
fseek(fileStream, 0, SEEK_END);
size_t fileSize = ftell(fileStream);
fseek(fileStream, 0, SEEK_SET);
peFileBuffer = (char*)malloc(fileSize);
if (!peFileBuffer)
return NULL;
fread(peFileBuffer, 1, fileSize, fileStream);
fclose(fileStream);
lpDosHeader = (PIMAGE_DOS_HEADER)peFileBuffer;
if (lpDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
return -2;
}
lpNtHeaders = (PIMAGE_NT_HEADERS)(peFileBuffer + lpDosHeader->e_lfanew);
if (lpNtHeaders->Signature != IMAGE_NT_SIGNATURE)
{
return -3;
}
lpFileHeader = (PIMAGE_FILE_HEADER) & (lpNtHeaders->FileHeader);
lpOptionalHeader = (PIMAGE_OPTIONAL_HEADER) & (lpNtHeaders->OptionalHeader);
lpImageSections = (PIMAGE_SECTION_HEADER)((char*)lpOptionalHeader + lpFileHeader->SizeOfOptionalHeader);
fileAlignmentOfPEImage = lpOptionalHeader->FileAlignment;
sectionAlignmentOfPEImage = lpOptionalHeader->SectionAlignment;
lpLastSection = lpImageSections + lpFileHeader->NumberOfSections - 1;
fileStream = fopen(outputFileName, "wb");
lpFileHeader->NumberOfSections++;
lpOptionalHeader->SizeOfInitializedData += sizeofNewSectionData;
// Edit: Size Of Headers is the sum of the NT Header and the Section Headers.
lpOptionalHeader->SizeOfHeaders = align(lpOptionalHeader->SizeOfHeaders + sizeof(IMAGE_SECTION_HEADER), fileAlignmentOfPEImage);
lpOptionalHeader->SizeOfImage = align(lpOptionalHeader->SizeOfImage + sizeofNewSectionData, sectionAlignmentOfPEImage);
fwrite(peFileBuffer, 1, lpDosHeader->e_lfanew +
sizeof(IMAGE_NT_HEADERS) +
(lpFileHeader->NumberOfSections - 1) * sizeof(IMAGE_SECTION_HEADER), fileStream);
memset(&ourSection, 0, sizeof(IMAGE_SECTION_HEADER));
strcpy((char*)&ourSection.Name[0], sectionName);
ourSection.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
ourSection.SizeOfRawData = ourSection.Misc.VirtualSize = sizeofNewSectionData;
ourSection.PointerToRawData = align(lpLastSection->PointerToRawData + lpLastSection->SizeOfRawData, fileAlignmentOfPEImage);
ourSection.VirtualAddress = align(lpLastSection->VirtualAddress + lpLastSection->Misc.VirtualSize, sectionAlignmentOfPEImage);
fwrite(&ourSection, 1, sizeof(IMAGE_SECTION_HEADER), fileStream);
int fileOffset = ftell(fileStream);
fileOffset = align(fileOffset, fileAlignmentOfPEImage);
for (int i = 0; i < lpFileHeader->NumberOfSections - 1; i++)
{
PIMAGE_SECTION_HEADER lpSection = lpImageSections + i;
fseek(fileStream, fileOffset, SEEK_SET);
fwrite(peFileBuffer + lpSection->PointerToRawData, 1, lpSection->SizeOfRawData, fileStream);
fileOffset += align(lpSection->SizeOfRawData, fileAlignmentOfPEImage);
}
fseek(fileStream, fileOffset, SEEK_SET);
fwrite(sectionData, 1, ourSection.SizeOfRawData, fileStream);
fclose(fileStream);
return 0;
}
int align(int value, int alignment)
{
int remainder = value % alignment;
if (remainder != 0)
{
int returnvalue = value + alignment - (value % alignment);
return value + alignment - remainder;
}
else
{
int returnvalue = value;
return value;
}
}