New section of PE document

Keywords: C C++ security security hole

catalogue

What values in the PE file will be affected by the new section?

To add a new section:

Add section manually

Code new section

If you need to build a shellcode at one end in the PE file (when the remaining space in the default section area is insufficient), you can solve this problem by adding a section. Usually, most shelling software will add a section to move or back up various directory item data

What values in the PE file will be affected by the new section?

  • IMAGE_FILE_HEADER → numberofsections (the current number of PE file sections. If a new section is added, this value needs to be corrected)
  • IMAGE_OPTIONAL_HEADER  → sizeofimage (the size in memory after adding a section needs to be corrected)
  • In the default last IMAGE_SECTION_HEADER After that, add a section table structure and correct its data

To add a new section:

  • By judgment IMAGE_OPTIONAL_HEADER  → sizeofheaders (the size of all header + section table files aligned) to check whether there is enough space to add a section table data. If not, erase the DOS_STUB data and move nt and section data to DOS as a whole_ Stub position and correct IMAGE_DOS_HEADER → e_lfanew.
  • Add a new section after the current last section IMAGE_SECTION_HEADER Structure, and modify its properties according to the size of the new section
  • repair IMAGE_FILE_HEADER→NumberOfSections.
  • repair IMAGE_OPTIONAL_HEADER → SizeOfImage.
  • Reallocate the file cache of the corresponding size after adding
  • Copy previous data

Add section manually

View the default properties of PE file through WinHex tool

1) . judge whether the space is enough to add a new section

Currently, there is idle data of size of (image_section_header) * 2 (80byte) after the last section

2) . a section table structure is added at the last section

It is more convenient to set the size of memory and file to 0x1000 (the size in file is the size after file alignment)

The offset between memory and file is set to pointertorawdata + size of rawdata in the previous section

Section properties can be set according to actual requirements View the data point corresponding to this flag bit.

3) . repair IMAGE_FILE_HEADER→NumberOfSections.

4. Repair IMAGE_OPTIONAL_HEADER → SizeOfImage.

5. Add corresponding section data in the document

Move to the end of the file, select the last byte, select WinHex, edit in the menu bar, select the menu item, and paste 0 data

The new section size is 1000h, and the corresponding decimal system is 4096

After adding data, save it as a file and view its data through PE tool

Whether the program can run normally knows whether the new section is successful or not

Code new section

Read file code

PVOID FileToMem(IN PCHAR szFilePath, OUT LPDWORD dwFileSize)
{
	//Open file
	FILE* pFile = fopen(szFilePath, "rb");
	if (!pFile)
	{
		printf("FileToMem fopen Fail \r\n");
		return NULL;
	}

	//Get file length
	fseek(pFile, 0, SEEK_END);			//SEEK_END file end
	DWORD Size = ftell(pFile);
	fseek(pFile, 0, SEEK_SET);			//SEEK_ Start of set file

	//Request to store file data buffer
	PCHAR pFileBuffer = (PCHAR)malloc(Size);
	if (!pFileBuffer)
	{
		printf("FileToMem malloc Fail \r\n");
		fclose(pFile);
		return NULL;
	}

	//Read file data
	fread(pFileBuffer, Size, 1, pFile);

	//Determine whether it is an executable file
	if (*(PSHORT)pFileBuffer != IMAGE_DOS_SIGNATURE)
	{
		printf("Error: MZ \r\n");
		fclose(pFile);
		free(pFileBuffer);
		return NULL;
	}

	if (*(PDWORD)(pFileBuffer + *(PDWORD)(pFileBuffer + 0x3C)) != IMAGE_NT_SIGNATURE)
	{
		printf("Error: PE \r\n");
		fclose(pFile);
		free(pFileBuffer);
		return NULL;
	}

	if (dwFileSize)
	{
		*dwFileSize = Size;
	}

	fclose(pFile);

	return pFileBuffer;
}

Output file code

VOID MemToFile(IN PCHAR szFilePath, IN PVOID pFileBuffer, IN DWORD dwFileSize)
{
	//Open file
	FILE* pFile = fopen(szFilePath, "wb");
	if (!pFile)
	{
		printf("MemToFile fopen Fail \r\n");
		return;
	}

	//output file
	fwrite(pFileBuffer, dwFileSize, 1, pFile);

	fclose(pFile);
}

New section code

PVOID AddNewSection(PCHAR pBuffer, DWORD dwSectionSize, LPDWORD pNewFileSize)
{
	//Positioning structure
	PIMAGE_DOS_HEADER        pDos = (PIMAGE_DOS_HEADER)pBuffer;
	PIMAGE_NT_HEADERS        pNth = (PIMAGE_NT_HEADERS)(pBuffer + pDos->e_lfanew);
	PIMAGE_FILE_HEADER		 pFil = (PIMAGE_FILE_HEADER)((PUCHAR)pNth + 4);
	PIMAGE_OPTIONAL_HEADER   pOpo = (PIMAGE_OPTIONAL_HEADER)((PUCHAR)pFil + IMAGE_SIZEOF_FILE_HEADER);
	PIMAGE_SECTION_HEADER    pSec = (PIMAGE_SECTION_HEADER)((PUCHAR)pOpo + pFil->SizeOfOptionalHeader);

	//Judge whether there is space for adding new sections in the head
	if (pBuffer + pOpo->SizeOfHeaders - &pSec[pFil->NumberOfSections + 1] < IMAGE_SIZEOF_SECTION_HEADER )
	{
		//Erase DOS_STUB data and move nt and section up
		BOOL bRet = MoveNtAndSectionToDosStub(pBuffer);
		if (!bRet)
		{
			printf("AddNewSection MoveNtAndSectionToDosStub Fail \r\n");
			free(pBuffer);
			return NULL;
		}

		pDos = (PIMAGE_DOS_HEADER)pBuffer;
		pNth = (PIMAGE_NT_HEADERS)(pBuffer + pDos->e_lfanew);
		pFil = (PIMAGE_FILE_HEADER)((PUCHAR)pNth + 4);
		pOpo = (PIMAGE_OPTIONAL_HEADER)((PUCHAR)pFil + IMAGE_SIZEOF_FILE_HEADER);
		pSec = (PIMAGE_SECTION_HEADER)((PUCHAR)pOpo + pFil->SizeOfOptionalHeader);

	}

	//Fill in new section data
	CHAR szName[] = ".Kernel";
	memcpy(pSec[pFil->NumberOfSections].Name, szName,8);
	pSec[pFil->NumberOfSections].Misc.VirtualSize = dwSectionSize;//Size before alignment in memory
	pSec[pFil->NumberOfSections].VirtualAddress = Align(pOpo->SectionAlignment, pSec[pFil->NumberOfSections - 1].Misc.VirtualSize + pSec[pFil->NumberOfSections - 1].VirtualAddress);//Offset in memory
	pSec[pFil->NumberOfSections].SizeOfRawData = Align(pOpo->FileAlignment, dwSectionSize);//Aligned size in file
	pSec[pFil->NumberOfSections].PointerToRawData = Align(pOpo->FileAlignment, pSec[pFil->NumberOfSections - 1].PointerToRawData + pSec[pFil->NumberOfSections - 1].SizeOfRawData);//Offset in file
	pSec[pFil->NumberOfSections].PointerToRelocations = 0;
	pSec[pFil->NumberOfSections].PointerToLinenumbers = 0;
	pSec[pFil->NumberOfSections].NumberOfRelocations = 0;
	pSec[pFil->NumberOfSections].NumberOfLinenumbers = 0;
	pSec[pFil->NumberOfSections].Characteristics |= pSec->Characteristics;//Default code section
	pSec[pFil->NumberOfSections].Characteristics |= 0xC0000040;
	
	//The supplementary size after the new section is image_ SECTION_ 0 data of header structure
	memset(&pSec[pFil->NumberOfSections + 1], 0, IMAGE_SIZEOF_SECTION_HEADER);

	//Fix default number of sections
	pFil->NumberOfSections++;

	//Fix memory image size
	pOpo->SizeOfImage += Align(pOpo->SectionAlignment, dwSectionSize);

	//Default file size
	DWORD dwOldSize = pSec[pFil->NumberOfSections - 2].SizeOfRawData + pSec[pFil->NumberOfSections - 2].PointerToRawData;

	//Current file size
	DWORD dwNewSize = pSec[pFil->NumberOfSections - 1].SizeOfRawData + pSec[pFil->NumberOfSections - 1].PointerToRawData;
	if (pNewFileSize)
	{
		*pNewFileSize = dwNewSize;
	}

	//Reallocate buffer
	PUCHAR pTemp = (PUCHAR)malloc(dwNewSize);
	if (!pTemp)
	{
		printf("AddNewSection malloc Fail \r\n");
		free(pBuffer);
		return NULL;
	}
	memset(pTemp,0, dwNewSize);
	memcpy(pTemp, pBuffer, dwOldSize);
	free(pBuffer);

	return pTemp;
}

Test code

int main()
{
	//Read file binary data
	DWORD dwFileSize = 0;
	PCHAR pFileBuffer = FileToMem(FILE_PATH_IN, &dwFileSize);
	if (!pFileBuffer)
	{
		return;
	}

	//New section
	pFileBuffer = AddNewSection(pFileBuffer, 0x2222, &dwFileSize);

	//Output binary data to a file
	MemToFile(FILE_PATH_OUT, pFileBuffer, dwFileSize);

	return 0;
}

Posted by mastermike707 on Thu, 28 Oct 2021 05:27:54 -0700