/**//**************************************************************************
* 文件名: Main.cpp
* 日 期: 2009年1月13日
* 作 者: rawdata
* 描 述: 增加3个节
空间都用new,所以新生成的PE文件在新的内存区域
***************************************************************************/
#include <windows.h>
#include <windowsx.h>
#include <winnt.h>
#include <iostream>
using namespace std;
#pragma warning(disable:4312)
#pragma warning(disable:4311)
#pragma warning(disable:4244)
int main(int argc,char**argv)
{
//------------------- 主要缓冲区定义 ----------------------
BYTE* pDos = NULL; //Dos头和Stub区
DWORD dwSizeDos = 0; //Dos头 大小
DWORD dwSizeStub = 0; //Dos Stub区大小
BYTE* pNT = NULL; //NT头
DWORD dwSizeNT = 0; //该区大小
BYTE* pSecH = NULL; //节表
DWORD dwSizeSecH = 0; //该区大小
WORD dwSizeAdd = 3; //增加的节的个数
BYTE* pDelta = NULL; //文件对齐填充数据
DWORD dwSizeDelta = 0; //该区大小
BYTE* pPrevSec = NULL; //节块
DWORD dwSizePrevSec = 0;//该区大小
BYTE* pAddSec = NULL; //新增的节块
DWORD dwSizeAddSec = 0; //该区大小
//---------------------- 其他临时定义 --------------------
const char* pszFilePath = NULL; //文件路径
HANDLE hFile = NULL; //文件句柄
PIMAGE_DOS_HEADER pIDH = NULL; //Dos头
PIMAGE_NT_HEADERS pINH = NULL; //NT 头
PIMAGE_SECTION_HEADER* ppISH = NULL; //节表
DWORD dwRealRead = 0; //实际每次文件读取的字节数
DWORD dwMiniPointer = 0; //第一个section的位置
BOOL bNeedModify = FALSE; //是否有必要需要修改节块的文件指针
DWORD dwRawDataSize = 10*1024; //增加区段的数据大小
DWORD dwTmp=0,dwTmp2=0,dwTmp3 = 0;
//Dos 头
//===============================================================================
//打开文件、读取Dos头
//===========================================================================
//
//typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header "MZ"
//WORD e_magic; // Magic number
//WORD e_cblp; // Bytes on last page of file
//WORD e_cp; // Pages in file
//WORD e_crlc; // Relocations
//WORD e_cparhdr; // Size of header in
// paragraphs
//WORD e_minalloc; // Minimum extra paragraphs
// needed
//WORD e_maxalloc; // Maximum extra paragraphs
// needed
//WORD e_ss; // Initial (relative) SS
// value
//WORD e_sp; // Initial SP value
//WORD e_csum; // Checksum
//WORD e_ip; // Initial IP value
//WORD e_cs; // Initial (relative) CS
// value
//WORD e_lfarlc; // File address of relocation
// table
//WORD e_ovno; // Overlay number
//WORD e_res[4]; // Reserved words
//WORD e_oemid; // OEM identifier
// (for e_oeminfo)
//WORD e_oeminfo; // OEM information;
// e_oemid specific
//WORD e_res2[10]; // Reserved words
//LONG e_lfanew; // File address of the new
// exe header
//} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
//===============================================================================
pszFilePath = argv[0];
pszFilePath = "BeingInjued.exe";//Test
cout<<"PE FileName:"<<pszFilePath<<endl;
if(0 == lstrcmp(pszFilePath,""))
{
cout<<"文件路径不能为空!"<<endl;
return -1;
}
hFile = CreateFile(pszFilePath,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,NULL);
if(INVALID_HANDLE_VALUE == hFile)
{
cout<<"打开文件失败!"<<endl;
hFile = NULL;
goto Error;
}
dwSizeDos = sizeof(IMAGE_DOS_HEADER);//dos头大小
pDos = new BYTE[dwSizeDos]; //Dos头和Stub区
memset(pDos,0,dwSizeDos); //initiate
if(!ReadFile(hFile,pDos,dwSizeDos,&dwRealRead,NULL))
{
cout<<"读取Dos头失败!"<<endl;
goto Error;
}
cout<<"Dos Header: "<<dwRealRead<<"bytes have read."<<endl;
//获得IMAGE_DOS_HEADER指针,效验
pIDH = (PIMAGE_DOS_HEADER)pDos; //dos_header pointer: pIDH和pDos区别:一个是结构体指针,指向新开辟的结构;一个是字符指针,指向未知的内存空间
//两个指针指向同一区域20090924
if(memcmp(&(pIDH->e_magic),"MZ",2)!=0) //check dos header validate
{
cout<<"不是有效的PE文件格式!"<<endl;
goto Error;
}
//DOS Stub
//================================================================================
dwSizeStub = pIDH->e_lfanew - dwSizeDos;
pDos = (BYTE*)realloc(pDos,dwSizeDos + dwSizeStub); //原先pDos指针指向的DOS头变成(DOS头+STUB)
memset(pDos+dwSizeDos,0,dwSizeStub); //initiate 0 of (dos+stub)
if(!ReadFile(hFile,pDos+dwSizeDos,dwSizeStub,&dwRealRead,NULL))
{
cout<<"读取DosStub失败!"<<endl;
goto Error;
}
cout<<"Dos Stub: "<<dwRealRead<<"bytes have read."<<endl;
//NT Header
//================================================================================
dwSizeNT = sizeof(IMAGE_NT_HEADERS); //nt header size
pNT = new BYTE[dwSizeNT]; //nt pointer
memset(pNT,0,dwSizeNT);
if(!ReadFile(hFile,pNT,dwSizeNT,&dwRealRead,NULL))
{
cout<<"读取NT Headers失败!"<<endl;
goto Error;
}
//获得NT指针
pINH = (PIMAGE_NT_HEADERS)pNT;
if(memcmp(&(pINH->Signature),"PE",2)!=0)
{
cout<<"错误的PE文件格式!"<<endl;
goto Error;
}
//up is the judgement of pe file
//============================================================================
//节表
//================================================================================
dwSizeSecH = (pINH->FileHeader.NumberOfSections + dwSizeAdd) * sizeof(IMAGE_SECTION_HEADER); //每个节大小固定,原先节的个数+新增加的节个数
pSecH = new BYTE[dwSizeSecH]; //指向节表的字符指针
memset(pSecH,0,pINH->FileHeader.NumberOfSections + dwSizeAdd);
ppISH = (PIMAGE_SECTION_HEADER*)new DWORD[pINH->FileHeader.NumberOfSections + dwSizeAdd]; //指向节表的结构指针数组
memset(ppISH,0,sizeof(DWORD)*(pINH->FileHeader.NumberOfSections + dwSizeAdd));
for(UINT i=0;i<pINH->FileHeader.NumberOfSections;i++) //读取原先旧的节内容
{
if(!ReadFile(hFile,pSecH+i*sizeof(IMAGE_SECTION_HEADER),
sizeof(IMAGE_SECTION_HEADER),&dwRealRead,NULL))
{
cout<<"读取Section Headers失败!"<<endl;
goto Error;
}
ppISH[i] = (PIMAGE_SECTION_HEADER)(pSecH+i*sizeof(IMAGE_SECTION_HEADER));
//ppISH[0]=pSecH
//ppISH[1]=pSecH+sizeof(IMAGE_SECTION_HEADER)
//ppISH[2]=pSecH+2*sizeof(IMAGE_SECTION_HEADER)
//ppISH[3]=pSecH+3*sizeof(IMAGE_SECTION_HEADER)
//发现程序中用到的指针都是指向头部,比如节表,ppISH, pSecH都是指向节表头部,不移动,
//读取内容时只是根据偏移地址来读取,这样的好处是下次用到这个指针的时候课可以很方便的找到:)
cout<<"Name: "<<ppISH[i]->Name<<endl;
cout<<"Size: "<<ppISH[i]->SizeOfRawData<<endl;
cout<<"Virtual Adress: "<<ppISH[i]->VirtualAddress<<endl;
cout<<"PointerToRawData: "<<ppISH[i]->PointerToRawData<<endl;
}
cout<<endl;
//节块
//================================================================================
pPrevSec = (BYTE*)malloc(0);
for(i=0;i<pINH->FileHeader.NumberOfSections;i++)
{
dwTmp = ppISH[i]->SizeOfRawData; //磁盘上,节根据FileAlignment对齐后的大小,必须是FileAlignment的倍数
//节的物理大小
pPrevSec = (BYTE*)realloc(pPrevSec,dwTmp2 + dwTmp); //指向内存中未知地方的一个节大小的指针
memset(pPrevSec+dwTmp2,0,dwTmp);
SetFilePointer(hFile,ppISH[i]->PointerToRawData,NULL,FILE_BEGIN); //pointerToRawData:从文件开头到对应节的偏移量
//hFile目前指向第一个节
cout<<i<<":PointerToRawData:"<<ppISH[i]->PointerToRawData<<endl;
cout<<"BlockSize:"<<ppISH[i]->SizeOfRawData<<endl;
cout<<"Virtual Address:"<<ppISH[i]->VirtualAddress<<endl; //当PE文件读入内存后,对应节的RVA
if(!ReadFile(hFile,pPrevSec+dwTmp2,dwTmp,&dwRealRead,NULL)){
cout<<"ReadFile Faield!"<<endl;
goto Error;
}
dwTmp2 += dwTmp;
}
dwSizePrevSec = dwTmp2; //原先节的总大小,此时hFile指向第一个节块的头部
//数据填补、修改部分
//================================================================================
//第一个节块的位置
for(i=0;i<pINH->FileHeader.NumberOfSections;i++)
{
if(ppISH[i])
{
if(0 == dwMiniPointer)
dwMiniPointer = (DWORD)ppISH[i]->PointerToRawData; //pointerToRawData:从文件开头到对应节的偏移量
if((ppISH[i]->PointerToRawData)<dwMiniPointer)
dwMiniPointer = (DWORD)ppISH[i]->PointerToRawData;
}
}
cout<<"Prev First Section Pos:"<<dwMiniPointer<<endl;
//ppISH[0]->PointerToRawData不应该是第一个结块的位置么???
//这里是最小的结块是第一个结块,难道说ppISH[0]--[n]不是按从小到大的顺序排的?
//空白填充区大小 ,先计算好
dwTmp = (dwSizeDos+dwSizeStub+dwSizeNT+dwSizeSecH); //前面头部总大小
if(dwMiniPointer >= dwTmp) //第一个结块在 前面那些头部的后面
dwSizeDelta = dwMiniPointer - dwTmp; //dosheader,ntheader,sectionheader,section之间有空白间隙
else //第一个结块在 前面那些头部的前面??可能么。。。
//说明pe文件只是按照pe文件那个结构,但是不是顺序的,可能节块在前面,而且最前面的结块不一定是第一个结块。
//它在内存中是东一块西一块的,不是一个整体。
{
dwSizeDelta = dwTmp % (pINH->OptionalHeader.FileAlignment); //文件对其粒度取余
if(dwSizeDelta != 0) //前面那些头部总大小和文件对其粒度不对其
dwSizeDelta = pINH->OptionalHeader.FileAlignment - dwSizeDelta; //对其粒度-总大小得到空白区域,包括dosheader--ntheader
//ntheader--sectionheader
//sectionheader
else dwSizeDelta = 0;
bNeedModify = TRUE;
}
cout<<"Delta:"<<dwSizeDelta<<endl;
pDelta = new BYTE[dwSizeDelta]; //空白区间
memset(pDelta,0,dwSizeDelta);
dwMiniPointer = dwTmp;
dwMiniPointer += dwSizeDelta; //前面头部总大小+空白区间=前面头部符合文件对其粒度的总大小,即内存中从dosheader---sectionheader最末端(包括空白)
//修改 NT 头,必须修改
pINH->FileHeader.NumberOfSections += dwSizeAdd;
//修改原来节表头的文件指针
cout<<endl;
if(bNeedModify) //节块可能在那些头部的前面
{
for(i=0;i<(UINT)(pINH->FileHeader.NumberOfSections - dwSizeAdd);i++) //还是在原先那些结块循环
{
if(0 != i)
ppISH[i]->PointerToRawData =
ppISH[i-1]->PointerToRawData +
ppISH[i-1]->SizeOfRawData;
else
ppISH[i]->PointerToRawData = dwMiniPointer; ////pointerToRawData:从文件开头到对应节的偏移量
cout<<"New Entry:"<<i<<": "<<ppISH[i]->PointerToRawData<<endl;
}
}
//使第一个结块在内存中在最前面,排序啦
//填充增加的节表头
cout<<endl;
char szName[8] = ".";
char szNum[7] = {0};
szName[5] = 0;
dwTmp = ppISH[0]->VirtualAddress; //第一个节表虚拟地址
dwTmp2 = pINH->OptionalHeader.SectionAlignment; //节粒度
dwTmp3 = pINH->OptionalHeader.FileAlignment; //文件粒度
int nCount = 1;
DWORD dwNewAllocSize = 0;
for(i=(pINH->FileHeader.NumberOfSections - dwSizeAdd);
i<pINH->FileHeader.NumberOfSections;i++) //新增加的那些节填充数据
{
ppISH[i] = (PIMAGE_SECTION_HEADER)(pSecH+i*sizeof(IMAGE_SECTION_HEADER)); //先创建节表
memset(ppISH[i],0,sizeof(IMAGE_SECTION_HEADER));
ppISH[i]->Characteristics = ppISH[0]->Characteristics;
sprintf(szNum,"%d",nCount);
memcpy(szName+1,szNum,7);
memcpy(ppISH[i]->Name,szName,8); //取节名
dwNewAllocSize = dwRawDataSize % dwTmp3; //文件尾添加10*1024空白数据,但是要对其
if(dwNewAllocSize != 0) //不对其
dwNewAllocSize = dwRawDataSize + (dwTmp3 - dwNewAllocSize); //文件不对其,多了dwNewAllocSize,所以dwRawDataSize- dwNewAllocSize
//但是多退少补,所以多加一个文件粒度
else dwNewAllocSize = dwRawDataSize;
ppISH[i]->SizeOfRawData = dwNewAllocSize; //第i个节的大小
//增加的文件区段
dwSizeAddSec += ppISH[i]->SizeOfRawData;
dwNewAllocSize = dwRawDataSize % dwTmp2; //还要节对其
if(dwNewAllocSize != 0)
dwNewAllocSize = dwRawDataSize + (dwTmp2 - dwNewAllocSize);
else dwNewAllocSize = dwRawDataSize;
ppISH[i]->Misc.VirtualSize = dwNewAllocSize;
//修改NT头,必须修改
pINH->OptionalHeader.SizeOfImage += dwNewAllocSize;
ppISH[i]->PointerToRawData = (ppISH[i-1]->PointerToRawData+ppISH[i-1]->SizeOfRawData);
ppISH[i]->VirtualAddress = ppISH[i]->PointerToRawData;
if(ppISH[i]->VirtualAddress>=(0x7FFFFFFF-dwNewAllocSize))
{
cout<<"Error!Virtual address overflow!"<<endl;
goto Error;
}
cout<<"New Entry:"<<i<<": "<<ppISH[i]->PointerToRawData<<endl;
nCount++;
}
//修改NT头,可选,不设置也能正常运行,但是为保证数据准确,还是写上
pINH->OptionalHeader.SizeOfHeaders = dwMiniPointer;
//新的Sections,必须满足文件对齐
pAddSec = new BYTE[dwSizeAddSec];
memset(pAddSec,0,dwSizeAddSec);
//重建文件: dumpOK.exe
//================================================================================
CloseHandle(hFile);
hFile = CreateFile("dumpOK.exe",GENERIC_READ|GENERIC_WRITE,NULL,NULL,CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,NULL);
//Dos Data
if(!WriteFile(hFile,pDos,dwSizeDos+dwSizeStub,&dwRealRead,NULL))
{
cout<<"WriteFile Faield!"<<endl;
goto Error;
}
cout<<"Dos Data:"<<dwRealRead<<" bytes write."<<endl;
//NT 头
if(!WriteFile(hFile,pNT,dwSizeNT,&dwRealRead,NULL))
{
cout<<"WriteFile Faield!"<<endl;
goto Error;
}
cout<<"NT Data:"<<dwRealRead<<" bytes write."<<endl;
//节表 (包括新加的)
if(!WriteFile(hFile,pSecH,dwSizeSecH,&dwRealRead,NULL))
{
cout<<"WriteFile Faield!"<<endl;
goto Error;
}
cout<<"Section Headers:"<<dwRealRead<<" bytes write."<<endl;
//填充空白数据
if(!WriteFile(hFile,pDelta,dwSizeDelta,&dwRealRead,NULL)){
cout<<"WriteFile Faield!"<<endl;
goto Error;
}
cout<<"Delta Data:"<<dwRealRead<<" bytes write."<<endl;
//原来的节块
if(!WriteFile(hFile,pPrevSec,dwSizePrevSec,&dwRealRead,NULL)){
cout<<"WriteFile Faield!"<<endl;
goto Error;
}
cout<<"Section Blocks:"<<dwRealRead<<" bytes write."<<endl;
//增加的节块
if(!WriteFile(hFile,pAddSec,dwSizeAddSec,&dwRealRead,NULL)){
cout<<"WriteFile Faield!"<<endl;
goto Error;
}
cout<<"Section Blocks:"<<dwRealRead<<" bytes write."<<endl;
cout<<"Requeried Works Success Completed."<<endl;
Error:
CloseHandle(hFile);
delete[]ppISH;
delete[]pDos;
delete[]pNT;
delete[]pSecH;
delete[]pDelta;
delete[]pPrevSec;
delete[]pAddSec;
return 0;
}