c语言编辑一个新文件,用C语言给PE文件添加一个新 section

#include #ifndef _IMAGEHLP_H

#include "imagehlp.h"

#pragma comment ( lib, "imagehlp.lib" )

#endif

#pragma warning(disable : 4996)

// 根据传入的dwAlign粒度调整内存中或文件中对齐后的大小

DWORD Align(DWORD dwNum, DWORD dwAlign){

if (dwNum % dwAlign == 0){

return dwNum;

}else{

return (dwNum / dwAlign + 1) * dwAlign;

}

}

int main(int argc, char* argv[]){

char szFilePath[MAX_PATH];// PE 路径

OPENFILENAME ofn;

HANDLE hFile;// 文件句柄

HANDLE hMapping;// 映射文件句柄

LPVOID ImageBase;// 映射基址

PIMAGE_DOS_HEADER pDH = NULL;// 指向 IMAGE_DOS 结构的指针

PIMAGE_NT_HEADERS pNtH = NULL;// 指向 IMAGE_NT 结构的指针

PIMAGE_FILE_HEADER pFH = NULL;// 指向 IMAGE_FILE 结构的指针

PIMAGE_OPTIONAL_HEADER pOH = NULL;// 指向 IMAGE_OPTIONALE 结构的指针

PIMAGE_SECTION_HEADER pSH1 = NULL;// 指向 IMAGE_SECTION_TABLE 结构的指针first

PIMAGE_SECTION_HEADER pSH2 = NULL;// 指向 IMAGE_SECTION_TABLE 结构的指针two

PIMAGE_SECTION_HEADER pSH3 = NULL;// 指向 IMAGE_SECTION_TABLE 结构的指针three

memset(szFilePath, 0, MAX_PATH);

memset(&ofn, 0, sizeof(ofn));

ofn.lStructSize = sizeof(ofn);

ofn.hwndOwner = NULL;

ofn.hInstance = GetModuleHandle(NULL);

ofn.nMaxFile = MAX_PATH;

ofn.lpstrInitialDir = ".";

ofn.lpstrFile = szFilePath;

ofn.lpstrTitle = "选择 PE 文件打开";

ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;

ofn.lpstrFilter = "*.exe\0*.exe\0";

if (!GetOpenFileName(&ofn)){

MessageBox(NULL, "打开文件错误", NULL, MB_OK);

return 0;

}

// 选择要分析的文件后,经过3步打开并映射 PE 到虚拟内存中_CreateFile_CreateFileMapping_MapViewOfFile

// 1.创建文件内核对象,其句柄保存于 hFile,将文件在物理存储器的位置通告给操作系统

hFile = CreateFile(szFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

if (!hFile){

MessageBox(NULL, "打开文件错误", NULL, MB_OK);

return 0;

}

// 2.创建文件映射内核对象(分配虚拟内存),句柄保存于 hFileMapping

hMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);

if (!hMapping){

CloseHandle(hFile);

return FALSE;

}

// 3.将文件数据映射到进程的地址空间,返回的映射基址保存在 ImageBase 中

ImageBase = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, 0);

if (!ImageBase){

CloseHandle(hMapping);

CloseHandle(hFile);

return FALSE;

}

pDH = (PIMAGE_DOS_HEADER)ImageBase;// IMAGE_DOS Header 结构指针

pNtH = (PIMAGE_NT_HEADERS)((DWORD)pDH + pDH->e_lfanew);// IMAGE_NT Header 结构指针

pFH = &pNtH->FileHeader;// IMAGE_File Header 结构指针

pOH = &pNtH->OptionalHeader;// IMAGE_Optional Header结构指针

pSH1 = IMAGE_FIRST_SECTION(pNtH);// IMAGE_FIRST_SECTION 宏

pSH2 = (PIMAGE_SECTION_HEADER)((DWORD)pNtH + sizeof(IMAGE_NT_HEADERS));

pSH3 = (PIMAGE_SECTION_HEADER)((DWORD)pDH + pOH->SizeOfHeaders);

if (pDH->e_magic != IMAGE_DOS_SIGNATURE || pNtH->Signature != IMAGE_NT_SIGNATURE){

printf("Not a valid PE file...");

return -1;

}

// 创建PSection指针指向原程序中的第一个Section,并创建一个新的Section结构体 secToAdd

PIMAGE_SECTION_HEADER pSection = NULL;

IMAGE_SECTION_HEADER secToAdd = { 0 };// 节区名 Name

// 属性 Characteristics

// 实际被使用的区块大小 Misc.VirtualSize

// 节区在磁盘文件中的大小 SizeOfRawData

// 节区在内存中的RVA VirtualAddress

// 节区在磁盘中的偏移 PointerToRawData

pSection = (PIMAGE_SECTION_HEADER)((BYTE*)pOH + pFH->SizeOfOptionalHeader);// 定位到节区表

DWORD dwSectionNum = pFH->NumberOfSections;

DWORD dwSectionAlign = pOH->SectionAlignment;

DWORD dwFileAlign = pOH->FileAlignment;

DWORD dwOEP = pOH->AddressOfEntryPoint;// 程序执行入口地址VA

dwOEP = (DWORD)(pOH->ImageBase + dwOEP);// 映射起始地址+执行入口地址

pSection = pSection + dwSectionNum - 1;// 将PSection指向原程序节区表中最后一个Section表,这是关键一步,因为新节区所有属性和原来最后一个节区是相同的

strcpy((char *)secToAdd.Name, ".newSec");// 设置新添加的section的名字

secToAdd.Characteristics = pSection->Characteristics;// 设置新添加的section的属性值,与最后一个section取值相同

DWORD vsize = 0x2A01;// 新section大小设置

secToAdd.Misc.VirtualSize = vsize;

secToAdd.SizeOfRawData = Align(secToAdd.Misc.VirtualSize, dwFileAlign);// 根据之前定义的Align函数调用,得到经过处理后的section尺寸大小,经调整后实际大小为0x234,对齐后大小为0x400

secToAdd.VirtualAddress = pSection->VirtualAddress +

Align(pSection->Misc.VirtualSize, dwSectionAlign);// 调用Align函数,得到经过内存对齐处理后的尺寸,新Section的RVA等于原程序最后一个Section的RVA加上该节在内存中的映射尺寸

secToAdd.PointerToRawData = pSection->PointerToRawData + pSection->SizeOfRawData;// 新Section的FA地址等于最后一个Section的FA加上该节的文件对齐尺寸

pSection++;// pSection指向原程序中最后一个节表的下一个,写入新的节表结构

secToAdd.Characteristics = 0xE00000E0;// pSection->Characteristics = 0xE00000E0;

memcpy(pSection, &secToAdd, sizeof(IMAGE_SECTION_HEADER));// 将最后一个节区拷贝到新建的节区

// 打印新节区信息

printf("\n节表添加成功,新节表的信息为:\n");

printf("\nName = %s", secToAdd.Name);

printf("\nVirtualSize = %08lX", secToAdd.Misc.VirtualSize);

printf("\nVirtualAddress = %08lX", secToAdd.VirtualAddress);

printf("\nSizeOfRawData = %08lX", secToAdd.SizeOfRawData);

printf("\nPointerToRawData = %08lX", secToAdd.PointerToRawData);

printf("\n");

// 添加完信息之后要进行三个修改:①修改节区数量NumberOfSections

//②映像大小

//③扩充原PE文件的大小,将Section真正写入到尾部

pNtH->FileHeader.NumberOfSections += 0x1;// 更改PE文件中节表的数量

pOH->SizeOfImage = pOH->SizeOfImage + Align(secToAdd.Misc.VirtualSize, dwSectionAlign);// 修改程序的映像大小,比如VirtualSize=200,SectionAlign=200,那么最后就是400

BYTE bNum = '\x0';// 修改文件大小

DWORD dwWritten = 0;

::SetFilePointer(hFile, 0, 0, FILE_END);

::WriteFile(hFile, &bNum, secToAdd.SizeOfRawData, &dwWritten, NULL);

::UnmapViewOfFile(ImageBase);

::CloseHandle(hMapping);

::CloseHandle(hFile);

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值