www.pudn.com > MessageAdder.rar > Pe.cpp
// Pe.cpp: implementation of the CPe class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "MessageAdder.h"
#include "Pe.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CPe::CPe()
{
}
CPe::~CPe()
{
}
//对一个PE文件进行MessageBoxA代码的注入
void CPe::ModifyPe(CString strFileName, CString strTitle, CString strMsg)
{
CString strErrMsg;
HANDLE hFile,hMapping;
void *basepointer;
//create fiel Object;
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("不能打开文件");
return ;
}
//create a name file mapping object
if (!(hMapping=CreateFileMapping(hFile,0,PAGE_READONLY|SEC_COMMIT,0,0,0))) {
AfxMessageBox("映射文件失败");
CloseHandle(hFile);
return ;
}
//map view of file into base pointer
if (!(basepointer = MapViewOfFile(hMapping,FILE_MAP_READ,0,0,0))) {
AfxMessageBox("视图无效");
CloseHandle(hMapping);
CloseHandle(hFile);
return;
}
CloseHandle(hMapping);
CloseHandle(hFile);
CalcAddress(basepointer);//计算得到相关地址
UnmapViewOfFile(basepointer);
if (dwSpace<50) {
AfxMessageBox("没有足够的空隙空间供写入数据");
}
else{
WriteFile(strFileName,strTitle,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("不能打开文件");
return ;
}
CloseHandle(hFile);
}
//计算PE header的开始偏移,保存旧的程序入口地址,计算新的入口地址和计算PE文件的空隙空间
void CPe::CalcAddress(const void *base)
{
IMAGE_DOS_HEADER *dos_head = (IMAGE_DOS_HEADER*)base;
if (dos_head->e_magic !=IMAGE_DOS_SIGNATURE) {
AfxMessageBox("未知类型文件!");
return;
}
peHeader *header;
//得到PE文件头
header = (peHeader *)((char*)dos_head+dos_head->e_lfanew);
if (IsBadReadPtr(header,sizeof(*header))) {
AfxMessageBox("不正确的PE文件头,可能是DOS下可执行文件");
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
dwProvRAV = 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;
}
}
//把一个DWORD变量值转换成一个字符串,同时颠倒顺序,按照Little-endian方式
CString CPe::StrOfWord(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;
}
//把新的入口地址写入PE程序原来的入口地址处,使PE加载器载入程序时先跳到MessageBoxA处
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("查找错误!");
return FALSE;
}
memcpy(waddress,StrOfWord(dwAddress),4);
retf = _write(ret,waddress,4);
if (retf==-1) {
strErrMsg.Format("Error Write : >d",GetLastError());
AfxMessageBox(strErrMsg);
return FALSE;
}
return TRUE;
}
//把MessageBoxA的机器代码写入到PE文件中。这个函数现实的对话框的标题和现实内容长度不固定。
//先计算MessageBoxA函数的地址和函数的返回值,把新生成的的代码写入PE程序
BOOL CPe::WriteMessageBox(int ret, long offset, CString strCap, CString strTxt)
{
CString strAddress1,strAddress2;
unsigned char waddress[4]={0};
DWORD dwAddress;
//获得MessageBox在内存中的地址
HINSTANCE dLibMsg = LoadLibrary("user32.dll");
// HINSTANCE dLibMsg = LoadLibrary("NTDLL.dll");
dwMessageBoxAadaddress = (DWORD)GetProcAddress(dLibMsg,"MessageBoxA");
//计算校验位
int nLenCap1 = strCap.GetLength()+1;
int nLenTxt1 = strTxt.GetLength()+1;
int nTotLen = nLenCap1+nLenTxt1+24;
//重新计算MessageBox函数的地址
dwAddress = dwMessageBoxAadaddress-(dwProvRAV+dwNewEntryAddress+nTotLen-5);//????
strAddress1 = StrOfWord(dwAddress);
//计算返回地址
dwAddress = 0-(dwNewEntryAddress-dwOldEntryAddress+nTotLen);
strAddress2 = StrOfWord(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[i];
}
for (i=0;i<4;i++) {
cFix[8+i]=strAddress2[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("查找错误!");
return FALSE;
}
retf = _write(ret,cMessageBox,nTotLen);//写入
if (retf==-1) {
delete [] cMessageBox;
strErrMsg.Format("Error Write : >d",GetLastError());
AfxMessageBox(strErrMsg);
return FALSE;
}
return TRUE;
}
void CPe::WriteFile(CString strFileName, CString strTitle, 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("文件打开错误 !");
return;
}
//把新的入口地址写入文件,程序的入口地址在偏移PE文件头开始的第40位
if (!WriteNewEntry(ret,(long)(dwPeAddress+40),dwNewEntryAddress)) {
return;
}
//把对话框代码写入到应用程序中
if (!WriteMessageBox(ret,(long)dwEntryWrite,strTitle,strMsg)) {
return;
}
_close(ret);
}