Process Forking - Running Process From Memory

On martes, 7 de septiembre de 2010 0 comentarios

by Vrillon

I've noticed some custom made anti-cheats like to start a process from memory pointer rather than a
file for extra protection.

I wrote a little code a while back to do the same, for those who would like to know how to do so.

Código:
//--------------------------------------------------------
// Dynamic Process Forking of Portable Executable
// Author : Vrillon / Venus
// Date   : 07/14/2008
//--------------------------------------------------------
/*********************************************************/
/* With this header, you can create and run a process    */
/* from memory and not from a file.                      */
/*********************************************************/

#ifdef WIN32
    #include 
#else
    #error Process Forking Requires a Windows Operating System
#endif

#include 

/////////////////////////////////////////////////////////////
// NtUnmapViewOfSection (ZwUnmapViewOfSection)
// Used to unmap a section from a process.
typedef long int (__stdcall* NtUnmapViewOfSectionF)(HANDLE,PVOID);
NtUnmapViewOfSectionF NtUnmapViewOfSection = (NtUnmapViewOfSectionF)GetProcAddress(LoadLibrary("ntdll.dll"),"NtUnmapViewOfSection");

/////////////////////////////////////////////////////////////
// Fork Process
// Dynamically create a process based on the parameter 'lpImage'. The parameter should have the entire
// image of a portable executable file from address 0 to the end.
bool ForkProcess(LPVOID lpImage)
{
    // Variables for Process Forking
    long int                lWritten;
    long int                lHeaderSize;
    long int                lImageSize;
    long int                lSectionCount;
    long int                lSectionSize;
    long int                lFirstSection;
    long int                lPreviousProtection;
    long int                lJumpSize;

    bool                    bReturnValue;

    LPVOID                    lpImageMemory;
    LPVOID                    lpImageMemoryDummy;

    IMAGE_DOS_HEADER        dsDosHeader;
    IMAGE_NT_HEADERS        ntNtHeader;
    IMAGE_SECTION_HEADER    shSections[512 * 2];

    PROCESS_INFORMATION        piProcessInformation;
    STARTUPINFO                suStartUpInformation;

    CONTEXT                    cContext;

    // Variables for Local Process
    FILE*                    fFile;
    char*                    pProcessName;
    
    long int                lFileSize;
    long int                lLocalImageBase;
    long int                lLocalImageSize;

    LPVOID                    lpLocalFile;

    IMAGE_DOS_HEADER        dsLocalDosHeader;
    IMAGE_NT_HEADERS        ntLocalNtHeader;

    /////////////////////////////////////////////////////////////////
    // End Variable Definition

    bReturnValue = false;

    pProcessName = new char[MAX_PATH];
    ZeroMemory(pProcessName,MAX_PATH);

    // Get the file name for the dummy process
    if(GetModuleFileName(NULL,pProcessName,MAX_PATH) == 0)
    {
        delete [] pProcessName;
        return bReturnValue;
    }

    // Open the dummy process in binary mode
    fFile = fopen(pProcessName,"rb");
    if(!fFile)
    {
        delete [] pProcessName;
        return bReturnValue;
    }

    fseek(fFile,0,SEEK_END);

    // Get file size
    lFileSize = ftell(fFile);

    rewind(fFile);

    // Allocate memory for dummy file
    lpLocalFile = new LPVOID[lFileSize];
    ZeroMemory(lpLocalFile,lFileSize);

    // Read memory of file
    fread(lpLocalFile,lFileSize,1,fFile);

    // Close file
    fclose(fFile);

    // Grab the DOS Headers
    memcpy(&dsLocalDosHeader,lpLocalFile,sizeof(dsLocalDosHeader));

    if(dsLocalDosHeader.e_magic != IMAGE_DOS_SIGNATURE)
    {
        delete [] pProcessName;
        delete [] lpLocalFile;
        return bReturnValue;
    }

    // Grab NT Headers
    memcpy(&ntLocalNtHeader,(LPVOID)((long int)lpLocalFile+dsLocalDosHeader.e_lfanew),sizeof(dsLocalDosHeader));

    if(ntLocalNtHeader.Signature != IMAGE_NT_SIGNATURE)
    {
        delete [] pProcessName;
        delete [] lpLocalFile;
        return bReturnValue;
    }

    // Get Size and Image Base
    lLocalImageBase = ntLocalNtHeader.OptionalHeader.ImageBase;
    lLocalImageSize = ntLocalNtHeader.OptionalHeader.SizeOfImage;

    // Deallocate
    delete [] lpLocalFile;

    // Grab DOS Header for Forking Process
    memcpy(&dsDosHeader,lpImage,sizeof(dsDosHeader));

    if(dsDosHeader.e_magic != IMAGE_DOS_SIGNATURE)
    {
        delete [] pProcessName;
        return bReturnValue;
    }

    // Grab NT Header for Forking Process
    memcpy(&ntNtHeader,(LPVOID)((long int)lpImage+dsDosHeader.e_lfanew),sizeof(ntNtHeader));

    if(ntNtHeader.Signature != IMAGE_NT_SIGNATURE)
    {
        delete [] pProcessName;
        return bReturnValue;
    }

    // Get proper sizes
    lImageSize = ntNtHeader.OptionalHeader.SizeOfImage;
    lHeaderSize = ntNtHeader.OptionalHeader.SizeOfHeaders;

    // Allocate memory for image
    lpImageMemory = new LPVOID[lImageSize];
    ZeroMemory(lpImageMemory,lImageSize);

    lpImageMemoryDummy = lpImageMemory;

    lFirstSection = (long int)(((long int)lpImage+dsDosHeader.e_lfanew) + sizeof(IMAGE_NT_HEADERS));
    
    memcpy(shSections,(LPVOID)(lFirstSection),sizeof(IMAGE_SECTION_HEADER)*ntNtHeader.FileHeader.NumberOfSections);
    memcpy(lpImageMemoryDummy,lpImage,lHeaderSize);

    // Get Section Alignment
    if((ntNtHeader.OptionalHeader.SizeOfHeaders % ntNtHeader.OptionalHeader.SectionAlignment) == 0)
    {
        lJumpSize = ntNtHeader.OptionalHeader.SizeOfHeaders;
    }
    else
    {
        lJumpSize  = (ntNtHeader.OptionalHeader.SizeOfHeaders/ntNtHeader.OptionalHeader.SectionAlignment);
        lJumpSize += 1;
        lJumpSize *= (ntNtHeader.OptionalHeader.SectionAlignment);
    }

    lpImageMemoryDummy = (LPVOID)((long int)lpImageMemoryDummy + lJumpSize);

    // Copy Sections To Buffer
    for(lSectionCount = 0; lSectionCount < ntNtHeader.FileHeader.NumberOfSections; lSectionCount++)
    {
        lJumpSize = 0;
        lSectionSize = shSections[lSectionCount].SizeOfRawData;
        
        memcpy(lpImageMemoryDummy,(LPVOID)((long int)lpImage + shSections[lSectionCount].PointerToRawData),lSectionSize);

        if((shSections[lSectionCount].Misc.VirtualSize % ntNtHeader.OptionalHeader.SectionAlignment)==0)
        {
            lJumpSize = shSections[lSectionCount].Misc.VirtualSize;
        }
        else
        {
            lJumpSize  = (shSections[lSectionCount].Misc.VirtualSize/ntNtHeader.OptionalHeader.SectionAlignment);
            lJumpSize += 1;
            lJumpSize *= (ntNtHeader.OptionalHeader.SectionAlignment);
        }

        lpImageMemoryDummy = (LPVOID)((long int)lpImageMemoryDummy + lJumpSize);
    }

    ZeroMemory(&suStartUpInformation,sizeof(STARTUPINFO));
    ZeroMemory(&piProcessInformation,sizeof(PROCESS_INFORMATION));
    ZeroMemory(&cContext,sizeof(CONTEXT));

    suStartUpInformation.cb = sizeof(suStartUpInformation);

    // Create Process
    if(CreateProcess(NULL,pProcessName,NULL,NULL,false,CREATE_SUSPENDED,NULL,NULL,&suStartUpInformation,&piProcessInformation))
    {
        cContext.ContextFlags = CONTEXT_FULL;
        GetThreadContext(piProcessInformation.hThread,&cContext);

        // Check image base and image size
        if(lLocalImageBase == (long int)ntNtHeader.OptionalHeader.ImageBase && lImageSize <= lLocalImageSize)
        {
            VirtualProtectEx(piProcessInformation.hProcess,(LPVOID)((long int)ntNtHeader.OptionalHeader.ImageBase),lImageSize,PAGE_EXECUTE_READWRITE,(unsigned long*)&lPreviousProtection);
        }
        else
        {
            if(!NtUnmapViewOfSection(piProcessInformation.hProcess,(LPVOID)((DWORD)lLocalImageBase)))
                VirtualAllocEx(piProcessInformation.hProcess,(LPVOID)((long int)ntNtHeader.OptionalHeader.ImageBase),lImageSize,MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
        }

        // Write Image to Process
        if(WriteProcessMemory(piProcessInformation.hProcess,(LPVOID)((long int)ntNtHeader.OptionalHeader.ImageBase),lpImageMemory,lImageSize,(unsigned long*)&lWritten))
        {
            bReturnValue = true;
        }

        // Set Image Base
        if(WriteProcessMemory(piProcessInformation.hProcess,(LPVOID)((long int)cContext.Ebx + 8),&ntNtHeader.OptionalHeader.ImageBase,4,(unsigned long*)&lWritten))
        {
            if(bReturnValue == true)
                bReturnValue = true;
        }

        if(bReturnValue == false)
        {
            delete [] pProcessName;
            delete [] lpImageMemory;
            return bReturnValue;
        }

        // Set the new entry point
        cContext.Eax = ntNtHeader.OptionalHeader.ImageBase + ntNtHeader.OptionalHeader.AddressOfEntryPoint;
        
        SetThreadContext(piProcessInformation.hThread,&cContext);

        if(lLocalImageBase == (long int)ntNtHeader.OptionalHeader.ImageBase && lImageSize <= lLocalImageSize)
            VirtualProtectEx(piProcessInformation.hProcess,(LPVOID)((long int)ntNtHeader.OptionalHeader.ImageBase),lImageSize,lPreviousProtection,0);

        // Resume the process
        ResumeThread(piProcessInformation.hThread);
    }

    delete [] pProcessName;
    delete [] lpImageMemory;

    return bReturnValue;    
}

/////////////////////////////////////////////////////////////
// Fork Process From Resource
// Dynamically create a process from a resource file.
bool ForkProcessFromResource(int iResource,char* pResourceSection)
{
    HGLOBAL        hResData;
    HRSRC        hResInfo;

    LPVOID        lpRes;
    LPVOID        lpMemory;
    long int    lSize;

    HMODULE        hModule;

    bool bReturn;

    hModule = GetModuleHandle(0);
    bReturn = false;

    if(!hModule)
        return bReturn;

    hResInfo = FindResource(hModule, MAKEINTRESOURCE(iResource), pResourceSection);
    if(!hResInfo)
    {
        return bReturn;
    }

    hResData = LoadResource(hModule, hResInfo);
    if(!hResData)
    {
        return bReturn;
    }

    lpRes = LockResource(hResData);
    if(!lpRes)
    {
        FreeResource(hResData);
        return bReturn;
    }


    lSize = SizeofResource(hModule, hResInfo);

    lpMemory = new LPVOID[lSize];
    ZeroMemory(lpMemory,lSize);

    memcpy (lpMemory, lpRes, lSize);
        
    bReturn = ForkProcess(lpMemory);
    
    FreeResource(hResData);
    delete [] lpMemory;

    return bReturn;
}












































































































































































































































 
Can be used like this:
Código:
ForkProcess(pointer to executable memory);

or

ForkProcessFromResource(IDE_FILE1,"EXE"); (If you wanna load it from a resource)

0 comentarios:

Publicar un comentario