目录
通常扩大最后一个节比较方便,假设扩大第一个节则后续所有节对应的数据都需要更改.
扩大节对PE文件中哪些值会有影响?
- 最后节IMAGE_SECTION_HEADER结构成员中SizeOfRawData和VirtualSize.
- IMAGE_OPTIONAL_HEADER → SizeOfImage(扩大节后在内存中的大小需要修正).
扩大节步骤:
- 将最后一个节文件中的大小修改为当前文件大小加新增大小(文件对齐后的大小),节内存中的大小修改为当前内存大小加新增大小.
- 修复IMAGE_OPTIONAL_HEADER → SizeOfImage.
- 重新分配新增后对应大小的文件缓存.
- 拷贝先前数据.
手动扩大节
通过WinHex工具查看PE文件默认属性
1).修改最后一个节文件与内存大小
方便测试这里扩大1000h(下述代码示例会自动检测对齐).
2).修复IMAGE_OPTIONAL_HEADER → SizeOfImage
这个值必须是内存对齐后的大小,默认值为0x00033000,扩大节大小为0x1000,内存对齐为1000h.
3.在文件中新增对应节数据
移至文件尾部选中最后一个字节,WinHex选中菜单栏中编辑,选中菜单项粘贴0数据
扩大节大小为1000h,对应十进制为4096.
新增数据后另存为文件,通过PE工具查看其数据
程序是否可以正常运行就知道扩大节成功与否.
代码扩大节
读取文件代码
PVOID FileToMem(IN PCHAR szFilePath, OUT LPDWORD dwFileSize)
{
//打开文件
FILE* pFile = fopen(szFilePath, "rb");
if (!pFile)
{
printf("FileToMem fopen Fail \r\n");
return NULL;
}
//获取文件长度
fseek(pFile, 0, SEEK_END); //SEEK_END文件结尾
DWORD Size = ftell(pFile);
fseek(pFile, 0, SEEK_SET); //SEEK_SET文件开头
//申请存储文件数据缓冲区
PCHAR pFileBuffer = (PCHAR)malloc(Size);
if (!pFileBuffer)
{
printf("FileToMem malloc Fail \r\n");
fclose(pFile);
return NULL;
}
//读取文件数据
fread(pFileBuffer, Size, 1, pFile);
//判断是否为可执行文件
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;
}
输出文件代码
VOID MemToFile(IN PCHAR szFilePath, IN PVOID pFileBuffer, IN DWORD dwFileSize)
{
//打开文件
FILE* pFile = fopen(szFilePath, "wb");
if (!pFile)
{
printf("MemToFile fopen Fail \r\n");
return;
}
//输出文件
fwrite(pFileBuffer, dwFileSize, 1, pFile);
fclose(pFile);
}
扩大节代码
PVOID ExpandSection(PCHAR pBuffer, DWORD dwSectionSize, LPDWORD pNewFileSize)
{
//定位结构
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);
//默认文件大小
DWORD dwOldSize = pSec[pFil->NumberOfSections - 1].SizeOfRawData + pSec[pFil->NumberOfSections - 1].PointerToRawData;
//修改最后一个节的属性
pSec[pFil->NumberOfSections - 1].Misc.VirtualSize += dwSectionSize;//内存中对齐前的大小
pSec[pFil->NumberOfSections - 1].SizeOfRawData += Align(pOpo->FileAlignment, dwSectionSize);//文件中对齐后的大小
//修复内存镜像大小
pOpo->SizeOfImage += Align(pOpo->SectionAlignment, dwSectionSize);
//当前文件大小
DWORD dwNewSize = pSec[pFil->NumberOfSections - 1].SizeOfRawData + pSec[pFil->NumberOfSections - 1].PointerToRawData;
if (pNewFileSize)
{
*pNewFileSize = dwNewSize;
}
//重新分配缓冲区
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;
}
测试代码
int main()
{
//读取文件二进制数据
DWORD dwFileSize = 0;
PCHAR pFileBuffer = FileToMem(FILE_PATH_IN, &dwFileSize);
if (!pFileBuffer)
{
return;
}
//扩大节
pFileBuffer = ExpandSection(pFileBuffer, 0x2222, &dwFileSize);
//将二进制数据输出到文件
MemToFile(FILE_PATH_OUT, pFileBuffer, dwFileSize);
return
;
}