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)&0xff; 
	waddress[2]=(char)(dwAddress>>16)&0xff; 
	waddress[1]=(char)(dwAddress>>8)&0xff; 
	waddress[0]=(char)(dwAddress)&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); 
}