memory execute exe

Delphi版牛人Idle_(阿呆)的作品,小弟只是转换成了VC版本,详情请参见源文:)  
  http://community.csdn.net/Expert/topic/4416/4416252.xml?temp=.950268  
   
  引源文一段话:  
  windows似乎只提供了一种启动进程的方法:即必须从一个可执行文件中加载并启动。  
  而下面这段代码就是提供一种可以直接从内存中启动一个exe的变通办法。  
  用途嘛,   也许可以用来保护你的exe,你可以对要保护的   exe   进行任意切分、加密、存储,只要运行时能将exe的内容正确拼接到一块内存中,就可以直接从内存中启动,而不必不安全地去生成一个临时文件再从临时文件启动进程。另外这段代码也提供了一种自己写exe外壳的简单途径,如果能配合其它各种外壳技术就更好地保护你的exe文件。  
   
  原理很简单:就是“借尸还魂”,启动一个僵尸进程(NT下可以是自身程序启动的另一个进程),然后在它运行前将其整个替换成内存中的exe内容,待正式运行后执行的就是你的目标代码了。  
   
  不过代码中还有一些不尽人意的地方,比如在98下运行会留一个僵尸程序的壳在硬盘上(其实那个僵尸程序本身就是一个完整的可执行程序,直接运行的话只显示一条错误信息然后就退出了)。另外由于客观条件限制,代码没有经过充分测试,只在XP下进行了一些初步测试:普通exe都能正常运行,upx压缩过的exe绝大多数情况下都能运行,只有在不能卸载僵尸外壳时才有问题(upx压缩过的exe没有重定向表,无法加载到其它地址运行)。    
   
  如果有bug望告之,如果有更好的方法特别是能解决98下的遗留尾巴的话希望不吝赐教。  
  ---------------------------------------------------------------------------------------  
   
  小弟没有翻译Win98下处理的方法,请大家参考原文:)  
   
  //   MemPE.cpp   :   Defines   the   entry   point   for   the   DLL   application.  
  //  
   
  #include   "stdafx.h"  
   
  typedef   IMAGE_SECTION_HEADER   (*PIMAGE_SECTION_HEADERS)[1];  
   
  //   计算对齐后的大小  
  unsigned   long   GetAlignedSize(unsigned   long   Origin,   unsigned   long   Alignment)  
  {  
  return   (Origin   +   Alignment   -   1)   /   Alignment   *   Alignment;  
  }  
   
  //   计算加载pe并对齐需要占用多少内存  
  //   未直接使用OptionalHeader.SizeOfImage作为结果是因为据说有的编译器生成的exe这个值会填0  
  unsigned   long   CalcTotalImageSize(PIMAGE_DOS_HEADER   MzH,   unsigned   long   FileLen,    
    PIMAGE_NT_HEADERS   peH,   PIMAGE_SECTION_HEADERS   peSecH)  
  {  
  unsigned   long   res;  
  //   计算pe头的大小  
  res   =   GetAlignedSize(peH->OptionalHeader.SizeOfHeaders,   peH->OptionalHeader.SectionAlignment);  
  //   计算所有节的大小  
  for(int   i=0;   i   <   peH->FileHeader.NumberOfSections;   ++i)  
  {  
  if(peSecH[i]->PointerToRawData   +   peSecH[i]->SizeOfRawData>FileLen){//   超出文件范围  
  return   0;  
  }  
  else   if(peSecH[i]->VirtualAddress){//计算对齐后某节的大小  
  if(peSecH[i]->Misc.VirtualSize){  
  res   =   GetAlignedSize(peSecH[i]->VirtualAddress   +   peSecH[i]->Misc.VirtualSize,    
  peH->OptionalHeader.SectionAlignment);  
  }  
  else{  
  res   =   GetAlignedSize(peSecH[i]->VirtualAddress   +   peSecH[i]->SizeOfRawData,    
  peH->OptionalHeader.SectionAlignment);  
  }  
  }  
  else   if(peSecH[i]->Misc.VirtualSize   <   peSecH[i]->SizeOfRawData){  
  res   +=   GetAlignedSize(peSecH[i]->SizeOfRawData,   peH->OptionalHeader.SectionAlignment);  
  }  
  else{  
  res   +=   GetAlignedSize(peSecH[i]->Misc.VirtualSize,   peH->OptionalHeader.SectionAlignment);  
  }  
  }  
  return   res;  
  }  

 

//   加载pe到内存并对齐所有节  
  BOOL   AlignPEToMem(void   *Buf,   long   Len,   PIMAGE_NT_HEADERS   &peH,   PIMAGE_SECTION_HEADERS   &peSecH,    
      void   *&Mem,   unsigned   long   &ImageSize)  
  {  
  PIMAGE_DOS_HEADER   SrcMz; //   DOS头  
  PIMAGE_NT_HEADERS   SrcPeH; //   PE头  
  PIMAGE_SECTION_HEADERS   SrcPeSecH; //   节表  
   
  SrcMz   =   (PIMAGE_DOS_HEADER)Buf;  
  if(Len   <   sizeof(IMAGE_DOS_HEADER))   return   FALSE;  
  if(SrcMz->e_magic   !=   IMAGE_DOS_SIGNATURE)   return   FALSE;  
  if(Len   <   SrcMz->e_lfanew   +   (long)sizeof(IMAGE_NT_HEADERS))   return   FALSE;  
  SrcPeH   =   (PIMAGE_NT_HEADERS)((int)SrcMz   +   SrcMz->e_lfanew);  
  if(SrcPeH->Signature   !=   IMAGE_NT_SIGNATURE)   return   FALSE;  
  if((SrcPeH->FileHeader.Characteristics   &   IMAGE_FILE_DLL)  
  ||   (SrcPeH->FileHeader.Characteristics   &   IMAGE_FILE_EXECUTABLE_IMAGE   ==   0)  
  ||   (SrcPeH->FileHeader.SizeOfOptionalHeader   !=   sizeof(IMAGE_OPTIONAL_HEADER)))   return   FALSE;  
  SrcPeSecH   =   (PIMAGE_SECTION_HEADERS)((int)SrcPeH   +   sizeof(IMAGE_NT_HEADERS));  
  ImageSize   =   CalcTotalImageSize(SrcMz,   Len,   SrcPeH,   SrcPeSecH);  
  if(ImageSize   ==   0)   return   FALSE;  
  Mem   =   VirtualAlloc(NULL,   ImageSize,   MEM_COMMIT,   PAGE_EXECUTE_READWRITE);   //   分配内存  
  if(Mem){  
  //   计算需要复制的PE头字节数  
  unsigned   long   l   =   SrcPeH->OptionalHeader.SizeOfHeaders;  
  for(int   i=0;   i   <   SrcPeH->FileHeader.NumberOfSections;   ++i)  
  if((SrcPeSecH[i]->PointerToRawData)   &&   (SrcPeSecH[i]->PointerToRawData   <   l))  
  l   =   SrcPeSecH[i]->PointerToRawData;  
  memmove(Mem,   SrcMz,   l);  
  peH   =   (PIMAGE_NT_HEADERS)((int)Mem   +   ((PIMAGE_DOS_HEADER)Mem)->e_lfanew);  
  peSecH   =   (PIMAGE_SECTION_HEADERS)((int)peH   +   sizeof(IMAGE_NT_HEADERS));  
  void   *Pt   =   (void   *)((unsigned   long)Mem   +   GetAlignedSize(peH->OptionalHeader.SizeOfHeaders,   peH->OptionalHeader.SectionAlignment));  
  for(i=0;   i   <   peH->FileHeader.NumberOfSections;   ++i)  
  {  
  //   定位该节在内存中的位置  
  if(peSecH[i]->VirtualAddress)  
  Pt   =   (void   *)((unsigned   long)Mem   +   peSecH[i]->VirtualAddress);  
  if(peSecH[i]->SizeOfRawData){  
  //   复制数据到内存  
  memmove(Pt,   (const   void   *)((unsigned   long)(SrcMz)   +   peSecH[i]->PointerToRawData),   peSecH[i]->SizeOfRawData);  
  if(peSecH[i]->Misc.VirtualSize   <   peSecH[i]->SizeOfRawData)  
  Pt   =   (void   *)((unsigned   long)Pt   +   GetAlignedSize(peSecH[i]->SizeOfRawData,   peH->OptionalHeader.SectionAlignment));  
  else   //   pt   定位到下一节开始位置  
  Pt   =   (void   *)((unsigned   long)Pt   +   GetAlignedSize(peSecH[i]->Misc.VirtualSize,   peH->OptionalHeader.SectionAlignment));  
  }  
  else{  
  Pt   =   (void   *)((unsigned   long)Pt   +   GetAlignedSize(peSecH[i]->Misc.VirtualSize,   peH->OptionalHeader.SectionAlignment));  
  }  
  }  
  }  
  return   TRUE;  
  }  
   
  typedef   void   *(__stdcall   *pfVirtualAllocEx)(unsigned   long,   void   *,   unsigned   long,   unsigned   long,   unsigned   long);  
  pfVirtualAllocEx   MyVirtualAllocEx   =   NULL;  
   
  BOOL   IsNT()  
  {  
  return   MyVirtualAllocEx!=NULL;  
  }  
   
  //   生成外壳程序命令行  
  char   *PrepareShellExe(char   *CmdParam,   unsigned   long   BaseAddr,   unsigned   long   ImageSize)  
  {  
  if(IsNT()){  
  char   *Buf   =   new   char[256];  
  memset(Buf,   0,   256);  
  GetModuleFileName(0,   Buf,   256);  
  strcat(Buf,   CmdParam);  
  return   Buf;   //   请记得释放内存;-)  
  }  
  else{  
  //   Win98下的处理请参考原文;-)  
  //   http://community.csdn.net/Expert/topic/4416/4416252.xml?temp=8.709133E-03  
  return   NULL;  
  }  
  }  
   
  //   是否包含可重定向列表  
  BOOL   HasRelocationTable(PIMAGE_NT_HEADERS   peH)  
  {  
  return   (peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)  
  &&   (peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);  
  }  

#pragma   pack(push,   1)  
  typedef   struct{  
  unsigned   long   VirtualAddress;  
  unsigned   long   SizeOfBlock;  
  }   *PImageBaseRelocation;  
  #pragma   pack(pop)  
   
  //   重定向PE用到的地址  
  void   DoRelocation(PIMAGE_NT_HEADERS   peH,   void   *OldBase,   void   *NewBase)  
  {  
  unsigned   long   Delta   =   (unsigned   long)NewBase   -   peH->OptionalHeader.ImageBase;  
  PImageBaseRelocation   p   =   (PImageBaseRelocation)((unsigned   long)OldBase    
  +   peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);  
  while(p->VirtualAddress   +   p->SizeOfBlock)  
  {  
  unsigned   short   *pw   =   (unsigned   short   *)((int)p   +   sizeof(*p));  
  for(unsigned   int   i=1;   i   <=   (p->SizeOfBlock   -   sizeof(*p))   /   2;   ++i)  
  {  
  if((*pw)   &   0xF000   ==   0x3000){  
  unsigned   long   *t   =   (unsigned   long   *)((unsigned   long)(OldBase)   +   p->VirtualAddress   +   ((*pw)   &   0x0FFF));  
  *t   +=   Delta;  
  }  
  ++pw;  
  }  
  p   =   (PImageBaseRelocation)pw;  
  }  
  }  
   
  //   卸载原外壳占用内存  
  BOOL   UnloadShell(HANDLE   ProcHnd,   unsigned   long   BaseAddr)  
  {  
  typedef   unsigned   long   (__stdcall   *pfZwUnmapViewOfSection)(unsigned   long,   unsigned   long);  
  pfZwUnmapViewOfSection   ZwUnmapViewOfSection   =   NULL;  
  BOOL   res   =   FALSE;  
  HMODULE   m   =   LoadLibrary("ntdll.dll");  
  if(m){  
  ZwUnmapViewOfSection   =   (pfZwUnmapViewOfSection)GetProcAddress(m,   "ZwUnmapViewOfSection");  
  if(ZwUnmapViewOfSection)  
  res   =   (ZwUnmapViewOfSection((unsigned   long)ProcHnd,   BaseAddr)   ==   0);  
  FreeLibrary(m);  
  }  
  return   res;  
  }  
   
  //   创建外壳进程并获取其基址、大小和当前运行状态  
  BOOL   CreateChild(char   *Cmd,   CONTEXT   &Ctx,   HANDLE   &ProcHnd,   HANDLE   &ThrdHnd,    
    unsigned   long   &ProcId,   unsigned   long   &BaseAddr,   unsigned   long   &ImageSize)  
  {  
  STARTUPINFOA   si;  
  PROCESS_INFORMATION   pi;  
  unsigned   long   old;  
  MEMORY_BASIC_INFORMATION   MemInfo;  
  memset(&si,   0,   sizeof(si));  
  memset(&pi,   0,   sizeof(pi));  
  si.cb   =   sizeof(si);  
   
  BOOL   res   =   CreateProcess(NULL,   Cmd,   NULL,   NULL,   FALSE,   CREATE_SUSPENDED,   NULL,   NULL,   &si,   &pi);   //   以挂起方式运行进程;  
  if(res){  
  ProcHnd   =   pi.hProcess;  
  ThrdHnd   =   pi.hThread;  
  ProcId   =   pi.dwProcessId;  
  //   获取外壳进程运行状态,[ctx.Ebx+8]内存处存的是外壳进程的加载基址,ctx.Eax存放有外壳进程的入口地址  
  Ctx.ContextFlags   =   CONTEXT_FULL;  
  GetThreadContext(ThrdHnd,   &Ctx);  
  ReadProcessMemory(ProcHnd,   (void   *)(Ctx.Ebx+8),   &BaseAddr,   sizeof(unsigned   long),   &old);   //   读取加载基址  
  void   *p   =   (void   *)BaseAddr;  
  //   计算外壳进程占有的内存  
  while(VirtualQueryEx(ProcHnd,   p,   &MemInfo,   sizeof(MemInfo)))  
  {  
  if(MemInfo.State   =   MEM_FREE)   break;  
  p   =   (void   *)((unsigned   long)p   +   MemInfo.RegionSize);  
  }  
  ImageSize   =   (unsigned   long)p   -   (unsigned   long)BaseAddr;  
  }  
  return   res;  
  }  
   
  //   创建外壳进程并用目标进程替换它然后执行  
  HANDLE   AttachPE(char   *CmdParam,   PIMAGE_NT_HEADERS   peH,   PIMAGE_SECTION_HEADERS   peSecH,    
        void   *Ptr,   unsigned   long   ImageSize,   unsigned   long   &ProcId)  
  {  
  HANDLE   res   =   INVALID_HANDLE_VALUE;  
  CONTEXT   Ctx;  
  HANDLE   Thrd;  
  unsigned   long   Addr,   Size;  
  char   *s   =   PrepareShellExe(CmdParam,   peH->OptionalHeader.ImageBase,   ImageSize);  
  if(s==NULL)   return   res;  
  if(CreateChild(s,   Ctx,   res,   Thrd,   ProcId,   Addr,   Size)){  
  void   *p   =   NULL;  
  unsigned   long   old;  
  if((peH->OptionalHeader.ImageBase   ==   Addr)   &&   (Size   >=   ImageSize)){//   外壳进程可以容纳目标进程并且加载地址一致  
  p   =   (void   *)Addr;  
  VirtualProtectEx(res,   p,   Size,   PAGE_EXECUTE_READWRITE,   &old);  
  }  
  else   if(IsNT()){  
  if(UnloadShell(res,   Addr)){//   卸载外壳进程占有内存  
  p   =   MyVirtualAllocEx((unsigned   long)res,   (void   *)peH->OptionalHeader.ImageBase,   ImageSize,   MEM_RESERVE   |   MEM_COMMIT,   PAGE_EXECUTE_READWRITE);  
  }  
  if((p   ==   NULL)   &&   HasRelocationTable(peH)){//   分配内存失败并且目标进程支持重定向  
  p   =   MyVirtualAllocEx((unsigned   long)res,   NULL,   ImageSize,   MEM_RESERVE   |   MEM_COMMIT,   PAGE_EXECUTE_READWRITE);  
  if(p)   DoRelocation(peH,   Ptr,   p);   //   重定向  
  }  
  }  
  if(p){  
  WriteProcessMemory(res,   (void   *)(Ctx.Ebx+8),   &p,   sizeof(DWORD),   &old);   //   重置目标进程运行环境中的基址  
  peH->OptionalHeader.ImageBase   =   (unsigned   long)p;  
  if(WriteProcessMemory(res,   p,   Ptr,   ImageSize,   &old)){//   复制PE数据到目标进程  
  Ctx.ContextFlags   =   CONTEXT_FULL;  
  if((unsigned   long)p   ==   Addr)  
  Ctx.Eax   =   peH->OptionalHeader.ImageBase   +   peH->OptionalHeader.AddressOfEntryPoint;   //   重置运行环境中的入口地址  
  else  
  Ctx.Eax   =   (unsigned   long)p   +   peH->OptionalHeader.AddressOfEntryPoint;  
  SetThreadContext(Thrd,   &Ctx); //   更新运行环境  
  ResumeThread(Thrd); //   执行  
  CloseHandle(Thrd);  
  }  
  else{//   加载失败,杀掉外壳进程  
  TerminateProcess(res,   0);  
  CloseHandle(Thrd);  
  CloseHandle(res);  
  res   =   INVALID_HANDLE_VALUE;  
  }  
  }  
  else{//   加载失败,杀掉外壳进程  
  TerminateProcess(res,   0);  
  CloseHandle(Thrd);  
  CloseHandle(res);  
  res   =   INVALID_HANDLE_VALUE;  
  }  
  }  
  delete[]   s;  
  return   res;  
  }  
   
    /*******************************************************/  
  {   *******************************************************   }  
  {   *                                   从内存中加载并运行exe                               *   }  
  {   *******************************************************   }  
  {   *   参数:                                                                                                 }  
  {   *   Buffer:   内存中的exe地址                                                               }  
  {   *   Len:   内存中exe占用长度                                                                 }  
  {   *   CmdParam:   命令行参数(不包含exe文件名的剩余命令行参数)}  
  {   *   ProcessId:   返回的进程Id                                                               }  
  {   *   返回值:   如果成功则返回进程的Handle(ProcessHandle),       }  
  {                         如果失败则返回INVALID_HANDLE_VALUE                       }  
  {   *******************************************************   }  
    /*******************************************************/  
  HANDLE   MemExecute(void   *ABuffer,   long   Len,   char   *CmdParam,   unsigned   long   *ProcessId)  
  {  
  HANDLE   res   =   INVALID_HANDLE_VALUE;  
  PIMAGE_NT_HEADERS   peH;  
  PIMAGE_SECTION_HEADERS   peSecH;  
  void   *Ptr;  
  unsigned   long   peSz;  
  if(AlignPEToMem(ABuffer,   Len,   peH,   peSecH,   Ptr,   peSz)){  
  res   =   AttachPE(CmdParam,   peH,   peSecH,   Ptr,   peSz,   *ProcessId);  
  VirtualFree(Ptr,   peSz,   MEM_DECOMMIT);  
  }  
  return   res;  
  }  
   
  //   初始化  
  class   CInit  
  {  
  public:  
  CInit(){  
  MyVirtualAllocEx   =   (pfVirtualAllocEx)GetProcAddress(GetModuleHandle("Kernel32.dll"),   "VirtualAllocEx");  
  }  
  }Init;  
  Top


    
  CFile   f;  
  if(f.Open("target.exe",   CFile::modeRead)){  
  void   *lpBuf   =   new   char[f.GetLength()];  
  f.Read(lpBuf,   f.GetLength());  
  unsigned   long   ProcessId;  
  HANDLE   MemExecute(void   *,   long,   char   *,   unsigned   long   *);  
  MemExecute(lpBuf,   f.GetLength(),   "",   &ProcessId);  
  f.Close();  
  delete[]   lpBuf;  
  }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值