该文件包含本机程序集代码,我想在当前进程中运行它。 但我不想创建一个真实的文件(.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<bitcode*> (malloc(20));
memcpy(d, c, 20);
d(); // it doesn't work
return 0;
};
但是,当我调用d();时它不起作用。我想知道使用C / C ++执行此操作的正确方法是什么。
(我在Windows上,如果你能告诉我如何在Linux上制作它,我会非常感激)
非常感谢!
PS:我不询问“在另一个进程中运行可执行文件而不创建新进程。”
答案 0 :(得分:4)
您需要映射可写页面,将代码写入其中,将页面切换为可执行文件,然后执行它。
答案 1 :(得分:4)
伊格纳西奥已经描述了如何做到这一点。
由于您使用的是Windows,因此您需要的功能是VirtualAlloc
而不是malloc
,特别是使用PAGE_EXECUTE_READWRITE
标志来获取写入内存的权限并执行它。
然后,根据文档,仍需要在写入内存之后,执行之前使用VirtualProtect
显式设置执行标志。
最后,在使用内存后,您需要使用VirtualFree
而不是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);
请注意reinterpret_cast
中添加的间接。这是避免未定义行为的必要条件:C ++不允许在对象指针和函数指针之间进行转换。但是,上面的代码是实现定义的,因此就C ++而言是可以的。
此外,请注意我省略了上面的错误检查代码以保持简单。您不得在实际代码中执行此操作。有关正确错误处理的信息,请参阅文档。
在Linux上,工作流程类似,只是为函数使用不同的名称。
答案 2 :(得分:1)
..既然你也问过linux
在这里,您可以使用mmap
。
〜例如:
<强> 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);
}
&安培;这是命令行的东西:
$ 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
(;为了清楚起见,我也省略了错误处理;)
答案 3 :(得分:1)
基本思想是调用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;
}
答案 4 :(得分:0)
我不确定,但您是否正在寻找__asm关键字
更多信息: http://msdn.microsoft.com/en-us/library/aa297214(v=vs.60).aspx