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