步骤
- 将读取到的文件拉伸到内存,头和节区按照SectionAlignment对齐,如果直接按照文件大小合并,合并为一个节后在内存中没办法对每个节进行拉伸。
头部直接按照SizeOfHeaders写入到ImageBuffer就行了,没必要对齐,因为节区是从VA开始写入的
将第一个节的内存大小、文件大小改成一样
Max = SizeOfRawData > VirtualSize ? SizeOfRawData : VirtualSize
SizeOfRawData = VirtualSize = 最后一个节的VirtualAddress + Max - SizeOfHeaders内存对齐后的大小
将第一个节的属性修改为包含所有节的属性
修改节的数量为1
将ImageBuffer重新构建为FileBuffer
由于拉伸内存时将PointerToRawData写到VirtualAddress,在ImageBuffer中合并节后,第一个节的PointerTorawData实际为VirtualAddress,所以合并节后需要调整下,否则程序无法正常运行。有两种方法,一是直接修改PointerTorawData的值,或者将ImageBuffer重新构建为FileBuffer
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
| #include<Windows.h> #include<stdio.h> #include<stdlib.h> #include<PETool.h> #pragma comment(lib,"PETool.lib") #define FILEPATH TEXT("D:\\absolution\\temporary\\test.exe") #define OUTFILEPATH TEXT("D:\\absolution\\temporary\\output.exe")
LPVOID createImageBuffer(LPVOID lpFileBuffer) { PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)lpFileBuffer; PIMAGE_NT_HEADERS pNT = (PIMAGE_NT_HEADERS)((DWORD)lpFileBuffer + pDos->e_lfanew); PIMAGE_FILE_HEADER pFile = (PIMAGE_FILE_HEADER)((DWORD)pNT + 4); PIMAGE_OPTIONAL_HEADER pOption = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFile + IMAGE_SIZEOF_FILE_HEADER); PIMAGE_SECTION_HEADER pFirstSection = PIMAGE_SECTION_HEADER((DWORD)pOption + pFile->SizeOfOptionalHeader);
LPVOID lpImageBuffer = malloc(pOption->SizeOfImage);
memset(lpImageBuffer, 0, pOption->SizeOfImage);
memcpy(lpImageBuffer, lpFileBuffer, pOption->SizeOfHeaders);
PIMAGE_SECTION_HEADER pSectionHeader = pFirstSection; for (int i = 0; i < pFile->NumberOfSections; i++) { memcpy( (LPVOID)((DWORD)lpImageBuffer + pSectionHeader->VirtualAddress), (LPVOID)((DWORD)lpFileBuffer + pSectionHeader->PointerToRawData), pSectionHeader->Misc.VirtualSize ); pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pSectionHeader + IMAGE_SIZEOF_SECTION_HEADER); }
return lpImageBuffer; }
LPVOID mergeSection(LPVOID lpImageBuffer) { PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)lpImageBuffer; PIMAGE_NT_HEADERS pNT = (PIMAGE_NT_HEADERS)((DWORD)lpImageBuffer + pDos->e_lfanew); PIMAGE_FILE_HEADER pFile = (PIMAGE_FILE_HEADER)((DWORD)pNT + 4); PIMAGE_OPTIONAL_HEADER pOption = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFile + IMAGE_SIZEOF_FILE_HEADER); PIMAGE_SECTION_HEADER pFirstSection = (PIMAGE_SECTION_HEADER)((DWORD)pOption + pFile->SizeOfOptionalHeader);
DWORD alignHeaderSize = PEAlign(pOption->SizeOfHeaders, pOption->SectionAlignment); PIMAGE_SECTION_HEADER pLastSection = PIMAGE_SECTION_HEADER((DWORD)pFirstSection + ((pFile->NumberOfSections - 1) * IMAGE_SIZEOF_SECTION_HEADER));
DWORD max = pLastSection->SizeOfRawData < pLastSection->Misc.VirtualSize ? pLastSection->Misc.VirtualSize : pLastSection->SizeOfRawData;
pFirstSection->SizeOfRawData = pFirstSection->Misc.VirtualSize = (DWORD)pLastSection->VirtualAddress + max - alignHeaderSize;
pFirstSection->PointerToRawData = pFirstSection->VirtualAddress; PIMAGE_SECTION_HEADER pSectionHeader = pFirstSection; for (int i = 0; i < pFile->NumberOfSections; i++) { pFirstSection->Characteristics |= pSectionHeader->Characteristics; pFirstSection = (PIMAGE_SECTION_HEADER)((DWORD)pFirstSection + 40); }
pFile->NumberOfSections = 1;
FILE *fp; errno_t err = fopen_s(&fp, OUTFILEPATH, "wb+");
fwrite(lpImageBuffer, pOption->SizeOfImage, 1, fp);
fclose(fp); return NULL;
}
int main() { LPVOID lpFileBuffer = createFileBuffer(FILEPATH);
if (!lpFileBuffer) { return 0; }
LPVOID lpImageBuffer = createImageBuffer(lpFileBuffer);
mergeSection(lpImageBuffer);
free(lpImageBuffer);
free(lpFileBuffer);
}
|
修改完成后
