如何在不创建新进程的情况下运行汇编代码?

该文件包含本机程序集代码,我想在当前进程中运行它。 但我不想创建一个真实的文件(.com或.exe),所以我试过:

... 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 (malloc(20)); memcpy(d, c, 20); d(); // it doesn't work return 0; }; 

但是,当我调用d();它时它不起作用。 我想知道使用C / C ++执行此操作的正确方法是什么。

(我在Windows上,如果你能告诉我如何在Linux上制作它,我会非常感激)

非常感谢!

PS:我不是要求“在没有创建新进程的情况下在另一个进程中运行可执行文件”。

在Windows上,这是我之前写的代码。 它至少在我的机器上适用于Win7 + VS2010。

基本思想是调用VirtualAlloc来分配带有PAGE_EXECUTE_READWRITE标志的内存。 并以正确的方式调用它,即保持堆栈平衡。

 #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; } 

您需要映射可写页面,将代码写入其中,将页面切换为可执行文件,然后执行它。

伊格纳西奥已经描述了如何做到这一点。

由于您使用的是Windows,因此您需要的function是VirtualAlloc而不是malloc ,特别是使用PAGE_EXECUTE_READWRITE标志来获取写入内存的权限并执行它。

然后,根据文档,您需要在写入内存之后以及执行之前使用VirtualProtect显式设置执行标志。

最后,在使用内存后,您需要使用VirtualFree而不是freeVirtualFree它。

 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(&mem); f(); // Later … VirtualFree(mem, 0, MEM_RELEASE); 

请注意reinterpret_cast添加的间接。 这是避免未定义行为所必需的:C ++不允许在对象指针和函数指针之间进行转换。 但是,上面的代码是实现定义的,因此就C ++而言是可以的。

此外,请注意我省略了上面的错误检查代码以保持简单。 您不能在实际代码中执行此操作。 有关正确error handling的信息,请参阅文档。

在Linux上,工作流程类似,只是为函数使用不同的名称。

..而且你也问过linux
在这里,你可以使用mmap
〜例如:

foo.cpp

 #include  #include  #include  #include  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); } 

这是命令行的东西:

 $ 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 

(;为了清楚起见,我也省略了error handling;)

我不确定,但你在寻找__asm关键字

更多内容: http : //msdn.microsoft.com/en-us/library/aa297214(v = vs.60).aspx