www.pudn.com > ch02_codes.rar > Pe.cpp


// Pe.cpp: 实现 CPe类.
//
#include "stdafx.h"
#include "Pe.h"

CPe::CPe()
{
}

CPe::~CPe()
{
}

void CPe::ModifyPe(CString strFileName,CString strMsg)
{
CString strErrMsg;

HANDLE hFile, hMapping;
void *basepointer;

// 打开要修改的文件.
if ((hFile = CreateFile(strFileName, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, 0,
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE)
{
AfxMessageBox("Could not open file.");
return;
}

// 创建一个映射文件.
if (!(hMapping = CreateFileMapping(hFile, 0, PAGE_READONLY | SEC_COMMIT, 0, 0, 0)))
{
AfxMessageBox("Mapping failed.");
CloseHandle(hFile);
return;
}

// 把文件头映象存入baseointer.
if (!(basepointer = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0)))
{
AfxMessageBox("View failed.");
CloseHandle(hMapping);
CloseHandle(hFile);
return;
}

CloseHandle(hMapping);
CloseHandle(hFile);

CalcAddress(basepointer); // 得到相关地址.
UnmapViewOfFile(basepointer);

if(dwSpace<50)
{
AfxMessageBox("No room to write the data!");
}
else
{
WriteFile(strFileName,strMsg); // 写文件.
}

if ((hFile = CreateFile(strFileName, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, 0,
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE)
{
AfxMessageBox("Could not open file.");
return;
}

CloseHandle(hFile);
}

void CPe::CalcAddress(const void *base)
{
IMAGE_DOS_HEADER * dos_head =(IMAGE_DOS_HEADER *)base;

if (dos_head->e_magic != IMAGE_DOS_SIGNATURE)
{
AfxMessageBox("Unknown type of file.");
return;
}

peHeader * header;

// 得到PE文件头.
header = (peHeader *)((char *)dos_head + dos_head->e_lfanew);

if(IsBadReadPtr(header, sizeof(*header)))
{
AfxMessageBox("No PE header, probably DOS executable.");
return;
}

DWORD mods;
char tmpstr[4]={0};
if(strstr((const char *)header->section_header[0].Name,".text")!=NULL)
{
// 此段的真实长度.
dwVirtSize=header->section_header[0].Misc.VirtualSize;

// 此段的物理偏移.
dwPhysAddress=header->section_header[0].PointerToRawData;

// 此段的物理长度.
dwPhysSize=header->section_header[0].SizeOfRawData;

// 得到PE文件头的开始偏移.
dwPeAddress=dos_head->e_lfanew;

// 得到代码段的可用空间,用以判断可不可以写入我们的代码
// 用此段的物理长度减去此段的真实长度就可以得到.
dwSpace=dwPhysSize-dwVirtSize;

// 得到程序的装载地址,一般为0x400000.
dwProgRAV=header->opt_head.ImageBase;

// 得到代码偏移,用代码段起始RVA减去此段的物理偏移
// 应为程序的入口计算公式是一个相对的偏移地址,计算公式为:
// 代码的写入地址+dwCodeOffset.
dwCodeOffset=header->opt_head.BaseOfCode-dwPhysAddress;

// 代码写入的物理偏移.
dwEntryWrite=header->section_header[0].PointerToRawData+header->
section_header[0].Misc.VirtualSize;

//对齐边界.
mods=dwEntryWrite>16;

if(mods!=0)
{
dwEntryWrite+=(16-mods);
}

// 保存旧的程序入口地址.
dwOldEntryAddress=header->opt_head.AddressOfEntryPoint;

// 计算新的程序入口地址.
dwNewEntryAddress=dwEntryWrite+dwCodeOffset;
return;
}
}

CString CPe::StrOfDWord(DWORD dwAddress)
{
unsigned char waddress[4]={0};

waddress[3]=(char)(dwAddress>>24)&amt;0xFF;
waddress[2]=(char)(dwAddress>>16)&amt;0xFF;
waddress[1]=(char)(dwAddress>>8 )&amt;0xFF;
waddress[0]=(char)(dwAddress )&amt;0xFF;

return waddress;
}

BOOL CPe::WriteNewEntry(int ret,long offset, DWORD dwAddress)
{
CString strErrMsg;
long retf;
unsigned char waddress[4]={0};

retf=_lseek(ret,offset,SEEK_SET);
if(retf==-1)
{
AfxMessageBox("Error seek.");
return FALSE;
}

memcpy(waddress,StrOfDWord(dwAddress),4);
retf=_write(ret,waddress,4);

if(retf==-1)
{
strErrMsg.Format("error write: >d",GetLastError());
AfxMessageBox(strErrMsg);
return FALSE;
}

return TRUE;
}

BOOL CPe::WriteMessageBox(int ret,long offset,CString strCap,CString strTxt)
{
CString strAddress1,strAddress2;
unsigned char waddress[4]={0};
DWORD dwAddress;

// 获取MessageBox在内存中的地址.
HINSTANCE gLibMsg=LoadLibrary("user32.dll");
dwMessageBoxAadaddress=(DWORD)GetProcAddress(gLibMsg,"MessageBoxA");

// 计算校验位.
int nLenCap1 =strCap.GetLength()+1; // 加上字符串后面的结束位.
int nLenTxt1 =strTxt.GetLength()+1; // 加上字符串后面的结束位.
int nTotLen=nLenCap1+nLenTxt1+24;

// 重新计算MessageBox函数的地址.
dwAddress=dwMessageBoxAadaddress-(dwProgRAV+dwNewEntryAddress+nTotLen-5);
strAddress1=StrOfDWord(dwAddress);

// 计算返回地址.
dwAddress=0-(dwNewEntryAddress-dwOldEntryAddress+nTotLen);
strAddress2=StrOfDWord(dwAddress);

// 对话框头代码(固定).
unsigned char cHeader[2]={0x6a,0x40};

// 标题定义.
unsigned char cDesCap[5]={0xe8,nLenCap1,0x00,0x00,0x00};

// 内容定义.
unsigned char cDesTxt[5]={0xe8,nLenTxt1,0x00,0x00,0x00};

// 对话框后部分的代码段.
unsigned char cFix[12]
={0x6a,0x00,0xe8,0x00,0x00,0x00,0x00,0xe9,0x00,0x00,0x00,0x00};

// 修改对话框后部分的代码段.
for(int i=0;i<4;i++)
cFix[3+i]=strAddress1.GetAt(i);

for(i=0;i<4;i++)
cFix[8+i]=strAddress2.GetAt(i);

char* cMessageBox=new char[nTotLen];
char* cMsg;

// 生成对话框命令字符串.
memcpy((cMsg = cMessageBox),(char*)cHeader,2);
memcpy((cMsg += 2),cDesCap,5);
memcpy((cMsg += 5),strCap,nLenCap1);
memcpy((cMsg += nLenCap1),cDesTxt,5);
memcpy((cMsg += 5),strTxt,nLenTxt1);
memcpy((cMsg += nLenTxt1),cFix,12);

// 向应用程序写入对话框代码.
CString strErrMsg;
long retf;
retf=_lseek(ret,(long)dwEntryWrite,SEEK_SET);
if(retf==-1)
{
delete[] cMessageBox;
AfxMessageBox("Error seek.");
return FALSE;
}

retf=_write(ret,cMessageBox,nTotLen);
if(retf==-1)
{
delete[] cMessageBox;
strErrMsg.Format("error write: >d",GetLastError());
AfxMessageBox(strErrMsg);
return FALSE;
}
delete[] cMessageBox;

return TRUE;
}

void CPe::WriteFile(CString strFileName,CString strMsg)
{
CString strAddress1,strAddress2;
int ret;
unsigned char waddress[4]={0};

ret=_open(strFileName,_O_RDWR | _O_CREAT | _O_BINARY,_S_IREAD | _S_IWRITE);
if(!ret)
{
AfxMessageBox("Error open.");
return;
}

// 把新的入口地址写入文件,程序的入口地址在偏移PE文件头开始第40位.
if(!WriteNewEntry(ret,(long)(dwPeAddress+40),dwNewEntryAddress)) return;

// 把对话框代码写入到应用程序中.
if(!WriteMessageBox(ret,(long)dwEntryWrite,"Test",strMsg)) return;

_close(ret);
}