catalogue
What values in the PE file will be affected by the 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; }