0

I was searching for awhile for how to read an exe into memory and execute it directly from memory. Then I've passed by this answer which was very useful CreateProcess from memory buffer.

Fortunately I've found some code implementing the mentioned idea. After some tweaking I got it to work.

#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>

void RunFromMemory(unsigned char* pImage,char* pPath)
{
    DWORD dwWritten = 0;
    DWORD dwHeader = 0; 
    DWORD dwImageSize = 0;
    DWORD dwSectionCount = 0;
    DWORD dwSectionSize = 0;
    DWORD firstSection = 0;
    DWORD previousProtection = 0;
    DWORD jmpSize = 0;

    IMAGE_NT_HEADERS INH;
    IMAGE_DOS_HEADER IDH;
    IMAGE_SECTION_HEADER Sections[1000];

    PROCESS_INFORMATION peProcessInformation;
    STARTUPINFO peStartUpInformation;
    CONTEXT pContext;
    SECURITY_ATTRIBUTES secAttrib;

    char* pMemory;
    char* pFile;
    memcpy(&IDH,pImage,sizeof(IDH));
    memcpy(&INH,(void*)((DWORD)pImage+IDH.e_lfanew),sizeof(INH));

    dwImageSize = INH.OptionalHeader.SizeOfImage;
    pMemory = (char*)malloc(dwImageSize);
    memset(pMemory,0,dwImageSize);
    pFile = pMemory;

    dwHeader = INH.OptionalHeader.SizeOfHeaders;
    firstSection = (DWORD)(((DWORD)pImage+IDH.e_lfanew) + sizeof(IMAGE_NT_HEADERS));
    memcpy(Sections,(char*)(firstSection),sizeof(IMAGE_SECTION_HEADER)*INH.FileHeader.NumberOfSections);

    memcpy(pFile,pImage,dwHeader);

    if((INH.OptionalHeader.SizeOfHeaders % INH.OptionalHeader.SectionAlignment)==0)
    {
        jmpSize = INH.OptionalHeader.SizeOfHeaders;
    }
    else
    {
        jmpSize = INH.OptionalHeader.SizeOfHeaders / INH.OptionalHeader.SectionAlignment;
        jmpSize += 1;
        jmpSize *= INH.OptionalHeader.SectionAlignment;
    }

    pFile = (char*)((DWORD)pFile + jmpSize);

    for(dwSectionCount = 0; dwSectionCount < INH.FileHeader.NumberOfSections; dwSectionCount++)
    {
        jmpSize = 0;
        dwSectionSize = Sections[dwSectionCount].SizeOfRawData;
        memcpy(pFile,(char*)(pImage + Sections[dwSectionCount].PointerToRawData),dwSectionSize);

        if((Sections[dwSectionCount].Misc.VirtualSize % INH.OptionalHeader.SectionAlignment)==0)
        {
            jmpSize = Sections[dwSectionCount].Misc.VirtualSize;
        }
        else
        {
            jmpSize = Sections[dwSectionCount].Misc.VirtualSize / INH.OptionalHeader.SectionAlignment;
            jmpSize += 1;
            jmpSize *= INH.OptionalHeader.SectionAlignment;
        }
        pFile = (char*)((DWORD)pFile + jmpSize);
    }


    memset(&peStartUpInformation,0,sizeof(STARTUPINFO));
    memset(&peProcessInformation,0,sizeof(PROCESS_INFORMATION));
    memset(&pContext,0,sizeof(CONTEXT));

    peStartUpInformation.cb = sizeof(peStartUpInformation);
    if(CreateProcess(NULL,pPath,NULL,NULL,false,CREATE_SUSPENDED, NULL,NULL,&peStartUpInformation,&peProcessInformation))
    {

        pContext.ContextFlags = CONTEXT_FULL;
        GetThreadContext(peProcessInformation.hThread,&pContext);
        VirtualProtectEx(peProcessInformation.hProcess,(void*)((DWORD)INH.OptionalHeader.ImageBase),dwImageSize,PAGE_EXECUTE_READWRITE,&previousProtection);
        WriteProcessMemory(peProcessInformation.hProcess,(void*)((DWORD)INH.OptionalHeader.ImageBase),pMemory,dwImageSize,&dwWritten);
        WriteProcessMemory(peProcessInformation.hProcess,(void*)((DWORD)pContext.Ebx + 8),&INH.OptionalHeader.ImageBase,4,&dwWritten);
        pContext.Eax = INH.OptionalHeader.ImageBase + INH.OptionalHeader.AddressOfEntryPoint;
        SetThreadContext(peProcessInformation.hThread,&pContext);
        VirtualProtectEx(peProcessInformation.hProcess,(void*)((DWORD)INH.OptionalHeader.ImageBase),dwImageSize,previousProtection,0);
        ResumeThread(peProcessInformation.hThread);

    }
    else{
        // for debugging
        DWORD er = GetLastError();
        DWORD x = er;
    }
    free(pMemory);
}

int main()
{
    //*********** open file to encrypt ************
    char exe_path[] = "C:\\prog.exe";
    FILE *inFile = fopen(exe_path, "rb");
    fseek(inFile , 0 , SEEK_END);
    unsigned long dwSize = ftell(inFile);
    rewind(inFile);
    unsigned char *lpMemory = (unsigned char*) malloc (sizeof(unsigned char)*dwSize);
    fread(lpMemory,1,dwSize,inFile);
    fclose (inFile);
    //**********************************************


    //********* execute ***********
    RunFromMemory(lpMemory,exe_path);


    return 0;
}

I put a sample program called prog.exe into my C drive and this code reads it into memory and executes it. This code works perfectly on Windows XP but I can't get it to work on Windows 7 as it launches this error message.

The application was unable to start correctly (0xc000000c). Click OK to close the application.

I don't get what the reason may be for it to work correctly on Windows XP but not on Windows 7. Did Windows 7 apply some changes to PE format or headers or something ??

Thanks in advance. And If anyone would like to test it, don't forget to put your sample exe as C:\prog.exe or change the path in the code as you like.

Community
  • 1
  • 1
Islam Hassan
  • 1,736
  • 4
  • 26
  • 42
  • 3
    This is an unsupported hack. Why would you be surprised if things changed between XP and Win7? You do realise that virus scanners will not like your program. – David Heffernan Feb 05 '14 at 22:58
  • For starters you might try not having the program stub reside in c:\. – 500 - Internal Server Error Feb 05 '14 at 23:21
  • There is only one legitimate use of this (packaging a 64bit version inside the 32bit resources) and it is used by various sysinternals utilities... but even they just unpack into the same folder. You really don't want to try to duplicate the functionality of the loader, it is quite complicated and knows more about the process and loading it than you do. – Mgetz Feb 05 '14 at 23:31

1 Answers1

0

This is a major hack, and you should really avoid doing it. If you want to start a new process then the only guaranteed way to make it work without issue is to launch an executable that resides in the filesystem. Anything else is a hack and you can't rely on it working in the future.

Sean
  • 60,939
  • 11
  • 97
  • 136