在内存中运行可执行程序

本文介绍了一种从内存中加载并执行PE文件的方法,包括内存分配、PE文件对齐、外壳进程创建与替换等步骤,并提供了一个完整的C++实现示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 在内存中运行可执行程序,好处是可以给程序加壳,加密源程序,静态反汇编无法获得PE输入节,但是因为运行后仍然是独立的进程,所以没办法防止远程线程注入,挂接API钩子。

  1 typedef IMAGE_SECTION_HEADER ( * PIMAGE_SECTION_HEADERS)[ 1 ];      2      3  //  计算对齐后的大小       4  unsigned  long  GetAlignedSize(unsigned  long  Origin, unsigned  long  Alignment)      5   {      6      return  (Origin  +  Alignment  -   1 )  /  Alignment  *  Alignment;      7 }       8      9  //  计算加载pe并对齐需要占用多少内存     10  //  未直接使用OptionalHeader.SizeOfImage作为结果是因为据说有的编译器生成的exe这个值会填0      11  unsigned  long  CalcTotalImageSize(PIMAGE_DOS_HEADER MzH     12                                  , unsigned  long  FileLen     13                                  , PIMAGE_NT_HEADERS peH     14                                  , PIMAGE_SECTION_HEADERS peSecH)     15   {     16     unsigned  long  res;     17      //  计算pe头的大小      18      res  =  GetAlignedSize( peH -> OptionalHeader.SizeOfHeaders , peH -> OptionalHeader.SectionAlignment);     19     20      //  计算所有节的大小      21       for (  int  i  =   0 ; i  <  peH -> FileHeader.NumberOfSections;  ++ i)     22       {     23          //  超出文件范围      24           if (peSecH[i] -> PointerToRawData  +  peSecH[i] -> SizeOfRawData  >  FileLen)    25           {  26              return   0 ;     27         }   28          else   if (peSecH[i] -> VirtualAddress) // 计算对齐后某节的大小      29             {     30              if (peSecH[i] -> Misc.VirtualSize)     31               {     32                 res  =  GetAlignedSize( peSecH[i] -> VirtualAddress  +  peSecH[i] -> Misc.VirtualSize     33                     , peH -> OptionalHeader.SectionAlignment);     34             }      35              else     36               {     37                 res  =  GetAlignedSize( peSecH[i] -> VirtualAddress  +  peSecH[i] -> SizeOfRawData     38                     , peH -> OptionalHeader.SectionAlignment);     39             }      40         }      41          else   if ( peSecH[i] -> Misc.VirtualSize  <  peSecH[i] -> SizeOfRawData )     42           {     43             res  +=  GetAlignedSize( peSecH[i] -> SizeOfRawData     44                 , peH -> OptionalHeader.SectionAlignment);     45         }      46          else     47           {     48             res  +=  GetAlignedSize( peSecH[i] -> Misc.VirtualSize     49                 , peH -> OptionalHeader.SectionAlignment);     50         } //  if_else      51      } //  for      52           53      return  res;     54 }      55     56     57     58     59  //  加载pe到内存并对齐所有节      60  BOOL AlignPEToMem(  void   * Buf     61                   ,  long  Len     62                   , PIMAGE_NT_HEADERS  & peH     63                   , PIMAGE_SECTION_HEADERS  & peSecH     64                   ,  void   *& Mem     65                   , unsigned  long   & ImageSize)     66   {     67     PIMAGE_DOS_HEADER SrcMz; //  DOS头      68      PIMAGE_NT_HEADERS SrcPeH; //  PE头      69      PIMAGE_SECTION_HEADERS SrcPeSecH; //  节表      70           71     SrcMz  =  (PIMAGE_DOS_HEADER)Buf;     72     73      if ( Len  <   sizeof (IMAGE_DOS_HEADER) )      74          return  FALSE;     75          76      if ( SrcMz -> e_magic  !=  IMAGE_DOS_SIGNATURE )     77          return  FALSE;     78          79      if ( Len  <  SrcMz -> e_lfanew  +  ( long ) sizeof (IMAGE_NT_HEADERS) )     80          return  FALSE;     81     82     SrcPeH  =  (PIMAGE_NT_HEADERS)(( int )SrcMz  +  SrcMz -> e_lfanew);     83      if ( SrcPeH -> Signature  !=  IMAGE_NT_SIGNATURE )     84          return  FALSE;     85     86      if ( (SrcPeH -> FileHeader.Characteristics  &  IMAGE_FILE_DLL)  ||      87         (SrcPeH -> FileHeader.Characteristics  &  IMAGE_FILE_EXECUTABLE_IMAGE  ==   0 )  ||      88         (SrcPeH -> FileHeader.SizeOfOptionalHeader  !=   sizeof (IMAGE_OPTIONAL_HEADER)) )     89       {     90          return  FALSE;     91     }      92     93     94     SrcPeSecH  =  (PIMAGE_SECTION_HEADERS)(( int )SrcPeH  +   sizeof (IMAGE_NT_HEADERS));     95     ImageSize  =  CalcTotalImageSize( SrcMz, Len, SrcPeH, SrcPeSecH);     96     97      if ( ImageSize  ==   0  )     98          return  FALSE;     99         100     Mem  =  VirtualAlloc( NULL, ImageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);  //  分配内存     101       if ( Mem  !=  NULL )    102       {    103          //  计算需要复制的PE头字节数     104          unsigned  long  l  =  SrcPeH -> OptionalHeader.SizeOfHeaders;    105          for (  int  i  =   0 ; i  <  SrcPeH -> FileHeader.NumberOfSections;  ++ i)    106           {    107              if ( (SrcPeSecH[i] -> PointerToRawData)  &&     108                 (SrcPeSecH[i] -> PointerToRawData  <  l) )    109               {    110                 l  =  SrcPeSecH[i] -> PointerToRawData;    111             }     112         }     113         memmove( Mem, SrcMz, l);    114         peH  =  (PIMAGE_NT_HEADERS)(( int )Mem  +  ((PIMAGE_DOS_HEADER)Mem) -> e_lfanew);    115         peSecH  =  (PIMAGE_SECTION_HEADERS)(( int )peH  +   sizeof (IMAGE_NT_HEADERS));    116    117          void   * Pt  =  ( void   * )((unsigned  long )Mem     118              +  GetAlignedSize( peH -> OptionalHeader.SizeOfHeaders    119             , peH -> OptionalHeader.SectionAlignment)    120             );    121    122          for ( i  =   0 ; i  <  peH -> FileHeader.NumberOfSections;  ++ i)    123           {    124              //  定位该节在内存中的位置     125               if (peSecH[i] -> VirtualAddress)    126                 Pt  =  ( void   * )((unsigned  long )Mem  +  peSecH[i] -> VirtualAddress);    127    128              if (peSecH[i] -> SizeOfRawData)    129               {    130                  //  复制数据到内存     131                  memmove(Pt, ( const   void   * )((unsigned  long )(SrcMz)  +  peSecH[i] -> PointerToRawData), peSecH[i] -> SizeOfRawData);    132                  if (peSecH[i] -> Misc.VirtualSize  <  peSecH[i] -> SizeOfRawData)    133                     Pt  =  ( void   * )((unsigned  long )Pt  +  GetAlignedSize(peSecH[i] -> SizeOfRawData, peH -> OptionalHeader.SectionAlignment));    134                  else   //  pt 定位到下一节开始位置     135                      Pt  =  ( void   * )((unsigned  long )Pt  +  GetAlignedSize(peSecH[i] -> Misc.VirtualSize, peH -> OptionalHeader.SectionAlignment));    136             }     137              else    138               {    139                 Pt  =  ( void   * )((unsigned  long )Pt  +  GetAlignedSize(peSecH[i] -> Misc.VirtualSize, peH -> OptionalHeader.SectionAlignment));    140             }     141         }     142     }     143      return  TRUE;    144 }     145    146    147    148 typedef  void   * (__stdcall  * pfVirtualAllocEx)(unsigned  long ,  void   * , unsigned  long , unsigned  long , unsigned  long );    149 pfVirtualAllocEx MyVirtualAllocEx  =  NULL;    150    151 BOOL IsNT()    152   {    153      return  MyVirtualAllocEx != NULL;    154 }     155    156  //  生成外壳程序命令行     157  char   * PrepareShellExe( char   * CmdParam, unsigned  long  BaseAddr, unsigned  long  ImageSize)    158   {    159      if (IsNT())    160       {    161          char   * Buf  =   new   char [ 256 ];    162         memset(Buf,  0 ,  256 );    163         GetModuleFileName( 0 , Buf,  256 );    164         strcat(Buf, CmdParam);    165          return  Buf;  //  请记得释放内存;-)     166      }     167      else    168       {    169          //  Win98 170 171           return  NULL;    172     }     173 }     174    175  //  是否包含可重定向列表     176  BOOL HasRelocationTable(PIMAGE_NT_HEADERS peH)    177   {    178      return  (peH -> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)    179          &&  (peH -> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);    180 }     181    182    183    184    185 #pragma pack(push,  1 )    186 typedef  struct  {    187     unsigned  long  VirtualAddress;    188     unsigned  long  SizeOfBlock;    189 }   * PImageBaseRelocation;    190 #pragma pack(pop)    191    192  //  重定向PE用到的地址     193  void  DoRelocation(PIMAGE_NT_HEADERS peH,  void   * OldBase,  void   * NewBase)    194   {    195     unsigned  long  Delta  =  (unsigned  long )NewBase  -  peH -> OptionalHeader.ImageBase;    196     PImageBaseRelocation p  =  (PImageBaseRelocation)((unsigned  long )OldBase     197          +  peH -> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);    198      while (p -> VirtualAddress  +  p -> SizeOfBlock)    199       {    200         unsigned  short   * pw  =  (unsigned  short   * )(( int )p  +   sizeof ( * p));    201          for (unsigned  int  i = 1 ; i  <=  (p -> SizeOfBlock  -   sizeof ( * p))  /   2 ;  ++ i)    202           {    203              if (( * pw)  &   0xF000   ==   0x3000 )  {    204                 unsigned  long   * t  =  (unsigned  long   * )((unsigned  long )(OldBase)  +  p -> VirtualAddress  +  (( * pw)  &   0x0FFF ));    205                  * t  +=  Delta;    206             }     207              ++ pw;    208         }     209         p  =  (PImageBaseRelocation)pw;    210     }     211 }     212    213  //  卸载原外壳占用内存     214  BOOL UnloadShell(HANDLE ProcHnd, unsigned  long  BaseAddr)    215   {    216     typedef unsigned  long  (__stdcall  * pfZwUnmapViewOfSection)(unsigned  long , unsigned  long );    217     pfZwUnmapViewOfSection ZwUnmapViewOfSection  =  NULL;    218     BOOL res  =  FALSE;    219     HMODULE m  =  LoadLibrary( " ntdll.dll " );    220      if (m)  {    221         ZwUnmapViewOfSection  =  (pfZwUnmapViewOfSection)GetProcAddress(m,  " ZwUnmapViewOfSection " );    222          if (ZwUnmapViewOfSection)    223             res  =  (ZwUnmapViewOfSection((unsigned  long )ProcHnd, BaseAddr)  ==   0 );    224         FreeLibrary(m);    225     }     226      return  res;    227 }     228    229  //  创建外壳进程并获取其基址、大小和当前运行状态     230  BOOL CreateChild( char   * Cmd, CONTEXT  & Ctx, HANDLE  & ProcHnd, HANDLE  & ThrdHnd,     231                  unsigned  long   & ProcId, unsigned  long   & BaseAddr, unsigned  long   & ImageSize)    232   {    233     STARTUPINFOA si;    234     PROCESS_INFORMATION pi;    235     unsigned  long  old;    236     MEMORY_BASIC_INFORMATION MemInfo;    237     memset( & si,  0 ,  sizeof (si));    238     memset( & pi,  0 ,  sizeof (pi));    239     si.cb  =   sizeof (si);    240         241     BOOL res  =  CreateProcess(NULL, Cmd, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL,  & si,  & pi);  //  以挂起方式运行进程;     242        if (res)  {    243         ProcHnd  =  pi.hProcess;    244         ThrdHnd  =  pi.hThread;    245         ProcId  =  pi.dwProcessId;    246          //  获取外壳进程运行状态,[ctx.Ebx+8]内存处存的是外壳进程的加载基址,ctx.Eax存放有外壳进程的入口地址     247          Ctx.ContextFlags  =  CONTEXT_FULL;    248         GetThreadContext(ThrdHnd,  & Ctx);    249         ReadProcessMemory(ProcHnd, ( void   * )(Ctx.Ebx + 8 ),  & BaseAddr,  sizeof (unsigned  long ),  & old);  //  读取加载基址     250           void   * p  =  ( void   * )BaseAddr;    251          //  计算外壳进程占有的内存     252           while (VirtualQueryEx(ProcHnd, p,  & MemInfo,  sizeof (MemInfo)))    253           {    254              if (MemInfo.State  =  MEM_FREE)  break ;    255             p  =  ( void   * )((unsigned  long )p  +  MemInfo.RegionSize);    256         }     257         ImageSize  =  (unsigned  long )p  -  (unsigned  long )BaseAddr;    258     }     259      return  res;    260 }     261    262  //  创建外壳进程并用目标进程替换它然后执行     263  HANDLE AttachPE( char   * CmdParam, PIMAGE_NT_HEADERS peH, PIMAGE_SECTION_HEADERS peSecH,     264                  void   * Ptr, unsigned  long  ImageSize, unsigned  long   & ProcId)    265   {    266     HANDLE res  =  INVALID_HANDLE_VALUE;    267     CONTEXT Ctx;    268     HANDLE Thrd;    269     unsigned  long  Addr, Size;    270      char   * s  =  PrepareShellExe(CmdParam, peH -> OptionalHeader.ImageBase, ImageSize);    271      if (s == NULL)  return  res;    272      if (CreateChild(s, Ctx, res, Thrd, ProcId, Addr, Size))  {    273          void   * p  =  NULL;    274         unsigned  long  old;    275          if ((peH -> OptionalHeader.ImageBase  ==  Addr)  &&  (Size  >=  ImageSize))  { //  外壳进程可以容纳目标进程并且加载地址一致     276              p  =  ( void   * )Addr;    277             VirtualProtectEx(res, p, Size, PAGE_EXECUTE_READWRITE,  & old);    278         }     279          else   if (IsNT())  {    280              if (UnloadShell(res, Addr))  { //  卸载外壳进程占有内存     281                  p  =  MyVirtualAllocEx((unsigned  long )res, ( void   * )peH -> OptionalHeader.ImageBase, ImageSize, MEM_RESERVE  |  MEM_COMMIT, PAGE_EXECUTE_READWRITE);    282             }     283              if ((p  ==  NULL)  &&  HasRelocationTable(peH))  { //  分配内存失败并且目标进程支持重定向     284                  p  =  MyVirtualAllocEx((unsigned  long )res, NULL, ImageSize, MEM_RESERVE  |  MEM_COMMIT, PAGE_EXECUTE_READWRITE);    285                  if (p) DoRelocation(peH, Ptr, p);  //  重定向     286              }     287         }     288          if (p)  {    289             WriteProcessMemory(res, ( void   * )(Ctx.Ebx + 8 ),  & p,  sizeof (DWORD),  & old);  //  重置目标进程运行环境中的基址     290              peH -> OptionalHeader.ImageBase  =  (unsigned  long )p;    291              if (WriteProcessMemory(res, p, Ptr, ImageSize,  & old))  { //  复制PE数据到目标进程     292                  Ctx.ContextFlags  =  CONTEXT_FULL;    293                  if ((unsigned  long )p  ==  Addr)    294                     Ctx.Eax  =  peH -> OptionalHeader.ImageBase  +  peH -> OptionalHeader.AddressOfEntryPoint;  //  重置运行环境中的入口地址     295                   else    296                     Ctx.Eax  =  (unsigned  long )p  +  peH -> OptionalHeader.AddressOfEntryPoint;    297                 SetThreadContext(Thrd,  & Ctx); //  更新运行环境     298                  ResumeThread(Thrd); //  执行     299                  CloseHandle(Thrd);    300             }     301              else  { //  加载失败,杀掉外壳进程     302                  TerminateProcess(res,  0 );    303                 CloseHandle(Thrd);    304                 CloseHandle(res);    305                 res  =  INVALID_HANDLE_VALUE;    306             }     307         }     308          else  { //  加载失败,杀掉外壳进程     309              TerminateProcess(res,  0 );    310             CloseHandle(Thrd);    311             CloseHandle(res);    312             res  =  INVALID_HANDLE_VALUE;    313         }     314     }     315     delete[] s;    316      return  res;    317 }     318    319    320    321    322   /**/ /**/ /**/ /* ******************************************************/   323 { ******************************************************* }   324 { *                 从内存中加载并运行exe               * }   325 { ******************************************************* }   326 { * 参数:                                                }   327 { * Buffer: 内存中的exe地址                               }   328 { * Len: 内存中exe占用长度                                }   329 { * CmdParam: 命令行参数(不包含exe文件名的剩余命令行参数)}   330 { * ProcessId: 返回的进程Id                               }   331 { * 返回值: 如果成功则返回进程的Handle(ProcessHandle),   }   332 {            如果失败则返回INVALID_HANDLE_VALUE           }   333 { ******************************************************* }   334  /****************************************************** */    335 HANDLE MemExecute( void   * ABuffer,  long  Len,  char   * CmdParam, unsigned  long   * ProcessId)    336   {    337     HANDLE res  =  INVALID_HANDLE_VALUE;    338     PIMAGE_NT_HEADERS peH;    339     PIMAGE_SECTION_HEADERS peSecH;    340      void   * Ptr;    341     unsigned  long  peSz;    342      if (AlignPEToMem(ABuffer, Len, peH, peSecH, Ptr, peSz))    343       {    344         res  =  AttachPE(CmdParam, peH, peSecH, Ptr, peSz,  * ProcessId);    345         VirtualFree(Ptr, peSz, MEM_DECOMMIT);    346     }     347      return  res;    348 }     349    350  //  初始化     351  class  CInit    352   {    353  public :    354     CInit()    355       {    356         MyVirtualAllocEx  =  (pfVirtualAllocEx)GetProcAddress(GetModuleHandle( " Kernel32.dll " ),  " VirtualAllocEx " );    357     }     358 } Init;    359    360    361    362    363  364  365  366  int  main( int  argc,  char *  argv[]) 367   { 368     FILE *  fp; 369     fp  =  fopen( " E://CProject//DBGVIEW.EXE " , " rb " ); 370  371      if  ( fp ) 372       { 373  374         fseek(fp, 0l ,SEEK_END); 375          int  file_size = ftell(fp); /**/ /* 获取文件长度 */  376          fseek(fp, 0l ,SEEK_SET); /**/ /* 回到文件头部 */     377          378          379         LPBYTE pBuf  =   new  BYTE[file_size];    380         memset( pBuf,  0 , file_size);    381  382         fread(pBuf,file_size, 1 ,fp); 383  384         DWORD id  =  GetCurrentProcessId(); 385         unsigned  long  ulProcessId  =   0 ;    386         MemExecute( pBuf, file_size,  "" ,  & ulProcessId);    387         delete[] pBuf;    388          389     }    390      391      return   0 ; 392 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值