1

Let's say I have a encrypted program, I open it with a decrypter, which loads the bytes into a array and decrypts it.

What I want to know is how it would be possible to execute those bytes without having to create another executable.

I read that it is possible using 'Forking', and that is the best way to do so. However I cannot successfully run my code, and it does not return any errors. Here's a sample of what I got :

    //<main>
    char* lpMemory;
    lpMemory = (char*)malloc (fileSize);
    memset(lpMemory,0,fileSize);
    memcpy (lpMemory, fileBuf, fileSize);
    RunFromMemory(lpMemory, /* What here? */);

    //</main>

void RunFromMemory(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;

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 /*&secAttrib*/, 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);
}
free(pMemory);
}

As you might have guessed, 'fileSize' is the size of the program and 'fileBuf' is the Byte array. I am sure that both of those values are correct.

Any links to resources that may help me is appreciated Thank you very much.

  • Cast the array pointer to a void pointer, and then to a function pointer, then call the function pointer? I'm nearly certain that it is undefined behavior, and I'm nearly sure that it is going to work on most computers :) – Sergey Kalinichenko Apr 30 '12 at 23:30
  • Also, you need to somehow get around the execute disable bit feature. http://en.wikipedia.org/wiki/NX_bit. – hookenz Apr 30 '12 at 23:31
  • 2
    You are **not** writing a virus, are you? – Sergey Kalinichenko Apr 30 '12 at 23:32
  • @dasblinkenlight Exactly what I was thinking. That or using it to encrypt/decrypt a program to keep people from getting around activation. – gcochard Apr 30 '12 at 23:34
  • There are legitimate uses for this besides writing a virus. – hookenz Apr 30 '12 at 23:36
  • It's interesting that dlopen requires that the file be represented on disk, but presumably it prevents an awful lot of memory leaks. http://stackoverflow.com/questions/5053664/dlopen-from-memory – Jeff Burdges May 01 '12 at 00:45
  • @dasblinkenlight Casting to a function pointer was UB in C++03, but now it's conditionally supported with implementation defined behavior. – bames53 May 01 '12 at 02:19

2 Answers2

1

Depending on what the bytes in the array actually represent, you might be able to just type-cast the array pointer into a function pointer and then call the "function" like any other. For that to work, the array would have to reside in executable memory (see VirtualProtect()) and contain just the byte representation of assembly instructions and nothing else.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • The thing is that I copied the entire content of the file, do you know a way to get only the code to be executed? –  May 01 '12 at 00:05
1

Yes it is possible: the easiest way to do it just to cast the pointer of your byte array to a function pointer and after call it. The second way is to use the inline assembler and perform a jmp to your byte array's address. Probably a heap or stack where your array is allocated will not be executable then you need to use the VirtualProtect and related api (for win32 ).

AlexTheo
  • 4,004
  • 1
  • 21
  • 35