步骤
扩大节区会修改原本的节表属性,新增节不会,通常大部分加壳软件都会新增节来移动或者备份各种目录项数据
新增一个0x1000字节大小的节区
- 判断头中是否有空间存下一个节表,为了便于验证默认空间不足。最后一个节表后面必须跟40个字节0,所以必须有大于80个字节的空间
- 抹除DOS Stub,将PE标识开始移动到DOS Stub处
- 修改IMAGE_DOS_HEADER.e_lfanew 为0x40(DOS Stub开始处)
- 在最后一个节表的结尾处填充刚才删除的字节数(IMAGE_NT_HEADERS.Signature的地址 - 0x40 = 填充字节数),一定要在节表的末尾处填充,只能移动头部,节区是不能移动的。
- 在最后一个节表后添加一个新的节表,将其VirtualSize和SizeOfRawData修改为0x1000,将其PointerToRawData修改为上一个节的SizeOfRawData + PointerToRawData(结果也就是PE文件结尾处)。
将其VirtualAddress修改为上一个节的VirtualAddress + VirtualSize,结果按照内存对齐
- 修改IMAGE_FILE_HEADER.NumberOfSections
- 修改IMAGE_OPTIONAL_HEADER.SizeOfImage
- 修改节区包含代码段和可执行属性,修改IMAGE_SECTION_HEADER.Characteristics,将节的IMAGE_SCN_CNT_CODE和IMAGE_SCN_MEM_EXECUTE标志位置1。
新增节不需要拉伸,直接通过最后一个节区就可以计算出新节地址
实现
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 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
| #include<Windows.h> #include<stdio.h> #include<stdlib.h> #define OUTFILEPATH TEXT("D:\\absolution\\temporary\\output.dll") #define DLLPATH TEXT("D:\\absolution\\temporary\\myDll.dll") #include<PETool.h> #pragma comment(lib,"PETool.lib")
BOOL deleteDOSStub(LPVOID lpFileBuffer) { PIMAGE_DOS_HEADER pDOS = (PIMAGE_DOS_HEADER)lpFileBuffer; PIMAGE_NT_HEADERS pNT = (PIMAGE_NT_HEADERS)((DWORD)pDOS + pDOS->e_lfanew); PIMAGE_FILE_HEADER pFile = (PIMAGE_FILE_HEADER)((DWORD)pNT + 4); PIMAGE_OPTIONAL_HEADER pOptional = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFile + 20); PIMAGE_SECTION_HEADER pSections = (PIMAGE_SECTION_HEADER)((DWORD)pOptional + pFile->SizeOfOptionalHeader); PIMAGE_SECTION_HEADER pLastSection = (PIMAGE_SECTION_HEADER)((DWORD)pSections + (pFile->NumberOfSections - 1) * 40);
DWORD dwSpace = ((DWORD)pDOS + pOptional->SizeOfHeaders) - ((DWORD)pLastSection + 40);
DWORD dwMoveSize = ((DWORD)pSections + (pFile->NumberOfSections) * 40) - (DWORD)pNT; LPVOID lpTemp = malloc(dwMoveSize); memset(lpTemp, 0, dwMoveSize);
memcpy(lpTemp, pNT, dwMoveSize);
memset(pNT, 0, dwMoveSize);
memcpy((LPVOID)(DWORD(pDOS) + 64), lpTemp, dwMoveSize);
pDOS->e_lfanew = 0x40;
free(lpTemp);
return TRUE;
}
LPVOID addNewSection(LPVOID lpFileBuffer, DWORD size) {
deleteDOSStub(lpFileBuffer);
PIMAGE_DOS_HEADER pDOS = (PIMAGE_DOS_HEADER)lpFileBuffer; PIMAGE_NT_HEADERS pNT = (PIMAGE_NT_HEADERS)((DWORD)pDOS + pDOS->e_lfanew); PIMAGE_FILE_HEADER pFile = (PIMAGE_FILE_HEADER)((DWORD)pNT + 4); PIMAGE_OPTIONAL_HEADER pOptional = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFile + 20); PIMAGE_SECTION_HEADER pSections = (PIMAGE_SECTION_HEADER)((DWORD)pOptional + pFile->SizeOfOptionalHeader); PIMAGE_SECTION_HEADER pLastSection = (PIMAGE_SECTION_HEADER)((DWORD)pSections + (pFile->NumberOfSections - 1) * 40);
PIMAGE_SECTION_HEADER pNewSection = PIMAGE_SECTION_HEADER((DWORD)pLastSection + 40);
memcpy(pNewSection, pLastSection, 40);
pFile->NumberOfSections = pFile->NumberOfSections + 1;
pNewSection->SizeOfRawData = PEAlign(size, pOptional->FileAlignment); pNewSection->Misc.VirtualSize = PEAlign(size, pOptional->SectionAlignment);
pNewSection->PointerToRawData = PEAlign((pLastSection->PointerToRawData + pLastSection->SizeOfRawData), pOptional->FileAlignment); pNewSection->VirtualAddress = PEAlign((pLastSection->VirtualAddress + pLastSection->Misc.VirtualSize), pOptional->SectionAlignment);
pNewSection->Characteristics = (pNewSection->Characteristics | IMAGE_SCN_CNT_CODE) | IMAGE_SCN_MEM_EXECUTE;
pOptional->SizeOfImage = PEAlign((pOptional->SizeOfImage + pNewSection->Misc.VirtualSize), pOptional->SectionAlignment);
LPVOID lpTemp = malloc(pNewSection->PointerToRawData + pNewSection->SizeOfRawData); memset(lpTemp, 0, pNewSection->PointerToRawData + pNewSection->SizeOfRawData); memcpy(lpTemp, lpFileBuffer, pNewSection->PointerToRawData);
return lpTemp; }
int main() { LPVOID lpFileBuffer = NULL; lpFileBuffer = createFileBuffer(DLLPATH); PIMAGE_SECTION_HEADER lpNewSection = NULL;
LPVOID lpModifyBuffer = (PIMAGE_SECTION_HEADER)addNewSection(lpFileBuffer, 0x1000);
PIMAGE_DOS_HEADER pDOS = (PIMAGE_DOS_HEADER)lpModifyBuffer; PIMAGE_NT_HEADERS pNT = (PIMAGE_NT_HEADERS)((DWORD)pDOS + pDOS->e_lfanew); PIMAGE_FILE_HEADER pFile = (PIMAGE_FILE_HEADER)((DWORD)pNT + 4); PIMAGE_OPTIONAL_HEADER pOptional = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFile + 20); PIMAGE_SECTION_HEADER pSections = (PIMAGE_SECTION_HEADER)((DWORD)pOptional + pFile->SizeOfOptionalHeader); PIMAGE_SECTION_HEADER pNewSection = (PIMAGE_SECTION_HEADER)((DWORD)pSections + (pFile->NumberOfSections - 1) * 40);
FILE *fp; fopen_s(&fp, OUTFILEPATH, "wb+"); if (!fp) { printf("fopen error\n"); getchar(); return 0; } fseek(fp, 0, SEEK_SET);
DWORD count=fwrite(lpModifyBuffer, pNewSection->PointerToRawData+pNewSection->SizeOfRawData,1, fp); if (count) { printf("写入成功!!\n"); getchar(); }
fclose(fp);
free(lpFileBuffer); free(lpModifyBuffer);
}
|
节表的两个偏移和大小要按照拓展PE头对齐,否则是无法正常执行的。