原理
新增节的原理是在最后一个节表后面新增一个节表,然后在ImageBuffer后面新增一块内存;要注意新增节表后必须留有一个节表空间(40字节)的0,否则会出错。有些程序如notepad,最后一个节表后面是一些数据,删除后程序无法运行,对于这种情况必须特殊处理,比如扩大节后再新增节,或者把NT头往上挪,覆盖掉dos stub垃圾数据,当然,方法是多样的。
除了上述工作,还需要修改PE头中节的数量(加1),修改SizeOfImage的大小,增加的值应该是要新增的节的大小内存对齐后的结果。另外,不要忘记设置新增节的属性。
测试了几个32位程序,有的能正常工作,有的不行。出错的程序有个共同点是他们最后一个节表后面并不是0,而是绑定导入表,以32位notepad为例,最后一个节表后面的数据是这样的:
为了解决这个问题,我添加了移动NT头的代码,也就是刚才说的,把NT头移动到DOS STUB中的方式。
移动NT头+新增节的代码
// 移动NT头和节表到DOS STUB,该函数在新增节时节表空间不足的情况下调用;返回地址减小值
DWORD MoveNTHeaderAndSectionHeadersToDosStub(LPVOID pFileBuffer)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));
PIMAGE_SECTION_HEADER pSectionHeader = \
(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
LPVOID pDst = (LPVOID)((DWORD)pDosHeader + sizeof(IMAGE_DOS_HEADER)); // NT头插入点
DWORD dwRet = (DWORD)pNTHeader - (DWORD)pDst; // 返回地址减小的值
DWORD dwSize = 4 + sizeof(IMAGE_FILE_HEADER) + pPEHeader->SizeOfOptionalHeader +\
sizeof(IMAGE_SECTION_HEADER) * pPEHeader->NumberOfSections; // 移动的字节数
LPVOID pSrc = malloc(dwSize);
if (pSrc == NULL)
{
printf("分配内存失败\n"