A Simple PE Test

 摘自http://book.csdn.net/bookfiles/212/10021210203.shtml

  1. // Pe.h: 定义CPe类
  2. //
  3. #include <io.h>
  4. #include <fcntl.h>
  5. #include <sys/stat.h>
  6. typedef struct PE_HEADER_MAP
  7. {
  8.     DWORD signature;
  9.     IMAGE_FILE_HEADER _head;
  10.     IMAGE_OPTIONAL_HEADER opt_head;
  11.     IMAGE_SECTION_HEADER section_header[6];
  12. } peHeader;
  13. class CPe  
  14. {
  15. public:
  16.     CPe();
  17.     virtual ~CPe();
  18. public
  19.     void CalcAddress(const void *base);
  20.     void ModifyPe(CString strFileName,CString strMsg);
  21. //    void WriteFile(CString strFileName,CString strMsg);
  22.     void WriteFile(CString strFileName);
  23.     BOOL WriteNewEntry(int ret,long offset,DWORD dwAddress);
  24.     BOOL WriteMessageBox(int ret,long offset,CString strCap,CString strTxt);
  25.     CString StrOfDWord(DWORD dwAddress);
  26. public:
  27.     DWORD dwSpace;
  28.     DWORD dwEntryAddress;
  29.     DWORD dwEntryWrite;
  30.     DWORD dwProgRAV;
  31.     DWORD dwOldEntryAddress;
  32.     DWORD dwNewEntryAddress;
  33.     DWORD dwCodeOffset;
  34.     DWORD dwPeAddress;
  35.     DWORD dwFlagAddress;
  36.     DWORD dwVirtSize;
  37.     DWORD dwPhysAddress;
  38.     DWORD dwPhysSize;
  39.     DWORD dwMessageBoxAadaddress;
  40. };
  41. #endif

 

  1. // Pe.cpp: 实现 CPe类
  2. //
  3. #include "stdafx.h"
  4. #include "Pe.h"
  5. CPe::CPe()
  6. {
  7. }
  8. CPe::~CPe()
  9. {
  10. }
  11. void CPe::ModifyPe(CString strFileName,CString strMsg)
  12. {
  13.     CString strErrMsg;
  14.     HANDLE hFile, hMapping;
  15.     void *basepointer; 
  16.     // 打开要修改的文件
  17.     if ((hFile = CreateFile(strFileName, GENERIC_READ|GENERIC_WRITE, 
  18.         FILE_SHARE_READ|FILE_SHARE_WRITE, 0, 
  19.         OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE)
  20.     {
  21.         AfxMessageBox("Could not open file.");
  22.         return;
  23.     }
  24.     // 创建一个映射文件
  25.     if (!(hMapping = CreateFileMapping(hFile, 0, PAGE_READONLY | SEC_COMMIT, 0, 0, 0)))
  26.     {
  27.         AfxMessageBox("Mapping failed.");
  28.         CloseHandle(hFile);
  29.         return;
  30.     }
  31.     // 把文件头映象存入baseointer
  32.     if (!(basepointer = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0)))
  33.     {
  34.         AfxMessageBox("View failed.");
  35.         CloseHandle(hMapping);
  36.         CloseHandle(hFile);
  37.         return;
  38.     }
  39.     CloseHandle(hMapping);
  40.     CloseHandle(hFile);
  41.     CalcAddress(basepointer); // 得到相关地址
  42.     UnmapViewOfFile(basepointer);  
  43.     if(dwSpace<50)
  44.     {
  45.         AfxMessageBox("No room to write the data!");
  46.     }
  47.     else
  48.     {
  49.      //   WriteFile(strFileName,strMsg); // 写文件
  50.         WriteFile(strFileName);
  51.     }
  52.     
  53.     if ((hFile = CreateFile(strFileName, GENERIC_READ|GENERIC_WRITE, 
  54.         FILE_SHARE_READ|FILE_SHARE_WRITE,0, 
  55.         OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE)
  56.     {
  57.         AfxMessageBox("Could not open file.");
  58.         return;
  59.     } 
  60.     CloseHandle(hFile);
  61. }
  62. void CPe::CalcAddress(const void *base)
  63. {
  64.     IMAGE_DOS_HEADER * dos_head =(IMAGE_DOS_HEADER *)base;
  65.     if (dos_head->e_magic != IMAGE_DOS_SIGNATURE)
  66.     {
  67.         AfxMessageBox("Unknown type of file.");
  68.         return;
  69.     }    
  70.     peHeader * header;
  71.     // 得到PE文件头
  72.     header = (peHeader *)((char *)dos_head + dos_head->e_lfanew);
  73.     if(IsBadReadPtr(header, sizeof(*header)))
  74.     {
  75.         AfxMessageBox("No PE header, probably DOS executable.");
  76.         return;
  77.     }
  78.     DWORD mods;
  79.     char tmpstr[4]={0};
  80.     if(strstr((const char *)header->section_header[0].Name,".text")!= NULL)
  81.     {
  82.         // 此段的真实长度
  83.         dwVirtSize=header->section_header[0].Misc.VirtualSize;
  84.         // 此段的物理偏移
  85.         dwPhysAddress=header->section_header[0].PointerToRawData;
  86.         // 此段的物理长度
  87.         dwPhysSize=header->section_header[0].SizeOfRawData;       
  88.         // 得到PE文件头的开始偏移
  89.         dwPeAddress=dos_head->e_lfanew;        
  90.         // 得到代码段的可用空间,用以判断可不可以写入我们的代码
  91.         // 用此段的物理长度减去此段的真实长度就可以得到
  92.         dwSpace=dwPhysSize-dwVirtSize;
  93.         // 得到程序的装载地址,一般为0x400000
  94.         dwProgRAV=header->opt_head.ImageBase; 
  95.         // 得到代码偏移,用代码段起始RVA减去此段的物理偏移
  96.         // 应为程序的入口计算公式是一个相对的偏移地址,计算公式为:
  97.         // 代码的写入地址+dwCodeOffset
  98.         dwCodeOffset=header->opt_head.BaseOfCode-dwPhysAddress;        
  99.         // 代码写入的物理偏移
  100.         dwEntryWrite=header->section_header[0].PointerToRawData+header->
  101.             section_header[0].Misc.VirtualSize;
  102.         //对齐边界
  103.         mods=dwEntryWrite%16;
  104.         if(mods!=0)
  105.         {
  106.             dwEntryWrite+=(16-mods);
  107.         }
  108.         // 保存旧的程序入口地址
  109.         dwOldEntryAddress=header->opt_head.AddressOfEntryPoint;
  110.         // 计算新的程序入口地址        
  111.         dwNewEntryAddress=dwEntryWrite+dwCodeOffset;
  112.         return;
  113.     }
  114. }  
  115. CString CPe::StrOfDWord(DWORD dwAddress)
  116. {
  117.     unsigned char waddress[4]={0};  
  118.     waddress[3]=(char)(dwAddress>>24)&0xFF;
  119.     waddress[2]=(char)(dwAddress>>16)&0xFF;
  120.     waddress[1]=(char)(dwAddress>>8)&0xFF;
  121.     waddress[0]=(char)(dwAddress)&0xFF;
  122.     return waddress;
  123. }
  124. BOOL CPe::WriteNewEntry(int ret,long offset, DWORD dwAddress)
  125. {
  126.     CString strErrMsg;
  127.     long retf;
  128.     unsigned char waddress[4]={0};
  129.     retf=_lseek(ret,offset,SEEK_SET);
  130.     if(retf==-1)
  131.     {
  132.         AfxMessageBox("Error seek.");
  133.         return FALSE;
  134.     }
  135.     memcpy(waddress,StrOfDWord(dwAddress),4);
  136.     retf=_write(ret,waddress,4);
  137.     if(retf==-1)
  138.     {
  139.         strErrMsg.Format("Error write: %d",GetLastError());
  140.         AfxMessageBox(strErrMsg);
  141.         return FALSE;
  142.     }
  143.     return TRUE;
  144. }
  145. BOOL CPe::WriteMessageBox(int ret,long offset,CString strCap,CString strTxt)
  146. {
  147.     CString strAddress1,strAddress2;
  148.     unsigned char waddress[4]={0};
  149.     DWORD dwAddress;
  150.     // 获取MessageBox在内存中的地址
  151.     HINSTANCE gLibMsg=LoadLibrary("user32.dll"); 
  152.     dwMessageBoxAadaddress=(DWORD)GetProcAddress(gLibMsg,"MessageBoxA");
  153.     // 计算校验位
  154.     int nLenCap1 =strCap.GetLength()+1;   // 加上字符串后面的结束位
  155.     int nLenTxt1 =strTxt.GetLength()+1;   // 加上字符串后面的结束位
  156.     int nTotLen=nLenCap1+nLenTxt1+24;
  157.     // 重新计算MessageBox函数的地址
  158.     dwAddress=dwMessageBoxAadaddress-(dwProgRAV+dwNewEntryAddress+nTotLen-5);
  159.     strAddress1=StrOfDWord(dwAddress);
  160.     // 计算返回地址
  161.     dwAddress=0-(dwNewEntryAddress-dwOldEntryAddress+nTotLen);
  162.     strAddress2=StrOfDWord(dwAddress);
  163.     // 对话框头代码(固定)
  164.     unsigned char cHeader[2]={0x6a,0x40};
  165.     // 标题定义
  166.     unsigned char cDesCap[5]={0xe8,nLenCap1,0x00,0x00,0x00}; 
  167.     // 内容定义
  168.     unsigned char cDesTxt[5]={0xe8,nLenTxt1,0x00,0x00,0x00};  
  169.     // 对话框后部分的代码段
  170.     unsigned char cFix[12]
  171.         ={0x6a,0x00,0xe8,0x00,0x00,0x00,0x00,0xe9,0x00,0x00,0x00,0x00};  
  172.     // 修改对话框后部分的代码段
  173.     for(int i=0;i<4;i++)
  174.         cFix[3+i]=strAddress1.GetAt(i);
  175.     for(i=0;i<4;i++)
  176.         cFix[8+i]=strAddress2.GetAt(i);
  177.     char* cMessageBox=new char[nTotLen];
  178.     char* cMsg; 
  179.     // 生成对话框命令字符串
  180.     memcpy((cMsg  = cMessageBox),(char*)cHeader,2);
  181.     memcpy((cMsg += 2),cDesCap,5);
  182.     memcpy((cMsg += 5),strCap,nLenCap1);
  183.     memcpy((cMsg += nLenCap1),cDesTxt,5);
  184.     memcpy((cMsg += 5),strTxt,nLenTxt1);
  185.     memcpy((cMsg += nLenTxt1),cFix,12);
  186.     // 向应用程序写入对话框代码
  187.     CString strErrMsg;
  188.     long retf;
  189.     retf=_lseek(ret,(long)dwEntryWrite,SEEK_SET);
  190.     if(retf==-1)
  191.     {
  192.         delete[] cMessageBox;
  193.         AfxMessageBox("Error seek.");
  194.         return FALSE;
  195.     }
  196.     retf=_write(ret,cMessageBox,nTotLen);
  197.     if(retf==-1)
  198.     {
  199.         delete[] cMessageBox;
  200.         strErrMsg.Format("Error write: %d",GetLastError());
  201.         AfxMessageBox(strErrMsg);
  202.         return FALSE;
  203.     }
  204.     delete[] cMessageBox;
  205.     return TRUE;
  206. }
  207. void CPe::WriteFile(CString strFileName)
  208. {
  209.     CString strAddress1,strAddress2;
  210.     int ret;
  211.     unsigned char waddress[4]={0};  
  212.     ret=_open(strFileName,_O_RDWR | _O_CREAT | _O_BINARY,_S_IREAD | _S_IWRITE);
  213.     if(!ret)
  214.     {
  215.         AfxMessageBox("Error open");
  216.         return;
  217.     }
  218.     // 把新的入口地址写入文件,程序的入口地址在偏移PE文件头开始第40位
  219.     if(!WriteNewEntry(ret,(long)(dwPeAddress+40),dwNewEntryAddress)) 
  220.         return;
  221.     // 把对话框代码写入到应用程序中
  222.     if(!WriteMessageBox(ret,(long)dwEntryWrite,"Test","We are the world!")) 
  223.         return;
  224.      _close(ret);
  225. }

你可能感兴趣的:(A Simple PE Test)