问题
The file contains the native assembly code, and I want to run it in the current process. But I don't want to create a real file (.com or .exe), so I tried:
...
using namespace std;
typedef void bitcode();
void testcode(){
cout<<"test";
};
int main()
{
bitcode *c=&testcode; // bitcode *c stands for the file containing the assembly code.
bitcode *d=reinterpret_cast<bitcode*> (malloc(20));
memcpy(d, c, 20);
d(); // it doesn't work
return 0;
};
However, it doesn't work when I invoke d();. I want to know what's the correct way to do this with C/C++.
(I'm on Windows, and I’d appreciate it very much if you could tell me how to make it on Linux)
Thanks a lot!
PS: I'm NOT asking "Running a executable in another process without creating a new process."
回答1:
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;
}
回答2:
You need to map a writable page, write your code to it, switch the page to executable, and then execute it.
回答3:
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.
回答4:
..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;)
回答5:
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
来源:https://stackoverflow.com/questions/10860093/how-to-run-assembly-code-without-creating-a-new-process