How to run assembly code without creating a new process?

邮差的信 提交于 2019-12-06 01:52:33

on windows, this is code I wrote before. It works on Win7+VS2010 at least in my machine.

the base idea is that call VirtualAlloc to allocate memory with PAGE_EXECUTE_READWRITE flag. And call it in right way, that is, keep the stack balance.

#include "stdafx.h"
#include "windows.h"


int emitcode[] = 
{0x83ec8b55,0x565340ec,0x0c758b57,0x8b087d8b,
 0x348d104d,0xcf3c8dce,0x6f0fd9f7,0x6f0fce04,
 0x0f08ce4c,0x10ce546f,0xce5c6f0f,0x646f0f18,
 0x6f0f20ce,0x0f28ce6c,0x30ce746f,0xce7c6f0f,
 0x04e70f38,0x4ce70fcf,0xe70f08cf,0x0f10cf54,
 0x18cf5ce7,0xcf64e70f,0x6ce70f20,0xe70f28cf,
 0x0f30cf74,0x38cf7ce7,0x7508c183,0xf8ae0fad,
 0x5e5f770f,0x5de58b5b,0xccccccc3};

int _tmain(int argc, _TCHAR* argv[])
{
    int *src = new int[64];
    int *dst = new int[64];
    int *dst2 = new int[64];

    for (int i = 0; i < 64; ++i){
        src[i] = i;
    }

    //fastercopy(dst,src, 64/2);

    void* address = NULL;
    address= VirtualAlloc(NULL,
            sizeof(emitcode),
            MEM_COMMIT|MEM_RESERVE,
            PAGE_EXECUTE_READWRITE);

    memcpy(address,emitcode,sizeof(emitcode));

    //call emit code from assemble
    __asm {
      push        20h  
      mov         eax,dword ptr [src]  
      push        eax  
      mov         ecx,dword ptr [dst]  
      push        ecx
      mov         ecx, dword ptr [address]
      call        ecx
      add         esp,0Ch 
    }

    for (int i = 0; i < 64; ++i){
        printf("%d ",dst[i]);
    }

    //call emit code from function pointer
    typedef void (*FASTCALL)(void* dst, void* src, int len);
    FASTCALL fastcall;
    fastcall = (FASTCALL)address;
    fastcall(dst2,src,64/2);

    printf("\n");
    for (int i = 0; i < 64; ++i){
        printf("%d ",dst2[i]);
    }

    return 0;
}

You need to map a writable page, write your code to it, switch the page to executable, and then execute it.

Ignacio has described the general outline of how to do it.

Since you are on Windows, the function you need for this is VirtualAlloc instead of malloc, notably with the PAGE_EXECUTE_READWRITE flag to obtain permissions to write the memory, and execute it.

Then, according to the documentation you still need to explicitly set the execution flag using VirtualProtect after writing to the memory, and before executing it.

Finally, after using the memory you need to free it using VirtualFree instead of free.

std::size_t size = 20;
void* mem = VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
// Write assembly opcodes to mem

DWORD old_protect;
VirtualProtect(mem, size, PAGE_EXECUTE_READWRITE, &old_protect);
typedef (void)(*fptr)();
fptr f = *reinterpret_cast<fptr*>(&mem);

f();

// Later …
VirtualFree(mem, 0, MEM_RELEASE);

Note the added indirection in the reinterpret_cast. This is necessary to avoid undefined behaviour: C++ does not allow casting between an object pointer and a function pointer. However, the above code is implementation-defined and thus OK as far as C++ is concerned.

Furthermore, note that I omitted the error-checking code in the above to keep it simple. You must not do this in real code. Refer to the documentation for information about correct error handling.

On Linux the workflow is analogous, just using different names for the functions.

..and since you also asked about linux
here, you can use mmap.
~for example:

foo.cpp:

#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <assert.h>

void bar(int n) { printf("bar invoked: %d\n", n); }
typedef void(*fp_bar)(int);

typedef union
{
   unsigned char*   pb;
   void*            pv;
   void(*pf)();
} 
foocodes;

//some _unencrypted random foo code segment
const unsigned char ar_foos[]=
{
    0xbb,0x00,0x00,0x00,0x00,   //mov ebx addy of a function to invoke
    0xb8,0x0d,0x00,0x00,0x00,   //mov eax 13 ~int input arg 
    0x50,                       //push eax
    0xff,0xd3,                  //call absolute addy ebx
    0x5b,                       //pop
    0x90,                       //throw in a nop to make up 16 foos
    0xC3                        //return
};


int main()
{
    size_t foos_size=sizeof ar_foos;
    foocodes ufoos;
    fp_bar pbar=&bar;
    assert(4==sizeof pbar); //example requires a 32bit fn address

    ufoos.pv=mmap(
        NULL, 
        foos_size, 
        PROT_WRITE|PROT_EXEC, 
        MAP_PRIVATE|MAP_ANONYMOUS,
        -1, 
        0);

    memcpy(ufoos.pv, ar_foos, foos_size);    
    memcpy(ufoos.pb+1, &pbar, sizeof pbar); //poke in the bar fn address

    ufoos.pf(); //invoke foo codes

    return munmap(ufoos.pv, foos_size);    
}


& here's commandline stuff:

$ uname -a
Linux violet-313 3.0.0-19-generic #33-Ubuntu SMP Thu Apr 19 19:05:57 UTC 2012 i686 i686 i386 GNU/Linux

$ gcc --version
gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1
...

$ gcc -ofoo foo.cpp
$ ./foo
bar invoked: 13

(;ook, i also omitted error handling in the interests of clarity;)

I am not sure but are you looking for __asm keyword

More at: http://msdn.microsoft.com/en-us/library/aa297214(v=vs.60).aspx

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!