如何在 C++ 中将 运行 机器代码作为函数
How to run machine code as a function in c++
系统:Windows10
编译器:MinGW
错误:分段错误
我正在尝试 运行 机器代码作为 c++ 中的函数。这是我的代码:
#include <iostream>
int main()
{
int(*fun_ptr)(void) = ((int(*)())("\xB8\x0C\x00\x00\x00\xC3"));
std::cout << fun_ptr();
return 0;
}
在 ideone.com 等在线编译器中,程序成功打印 12 并退出。我的电脑收到 "Segmentation fault" 错误。谁能帮帮我?
像"\xB8\x0C\x00\x00\x00\xC3"
这样的字符串文字是一个静态存储持续时间[lex.string]/15的对象。编译器通常会将此类字符串文字对象放入二进制文件的 .rdata
部分,即放入只读、不可执行的内存中。因此,尝试执行字符串文字的字节将导致访问冲突。如果要执行包含在全局数组对象中的机器代码字节,则必须确保将对象分配在可执行的部分中。例如(使用 Visual C++ 定位 Windows):
#include <iostream>
#pragma section("runstuff", read, execute)
__declspec(allocate("runstuff"))
const unsigned char code[] = {
0xB8, 0x0C, 0x0, 0x0, 0x0, 0xC3
};
int main()
{
auto fun_ptr = reinterpret_cast<int(*)()>(&code[0]);
std::cout << fun_ptr();
return 0;
}
请注意,像这样的东西本质上是不可移植的,并且充其量具有实现定义的行为。如果您在构建时知道您想要什么机器代码 运行,请考虑使用汇编程序并将生成的目标文件链接到您的可执行文件。如果你想在 Windows 上动态生成机器代码,你将不得不分配可执行内存。为此,要么在可执行(以及可写)内存中创建一个足够大的数组(例如,类似于我上面的示例),您可以在其中放置代码,要么动态分配可执行内存,例如使用 VirtualAlloc
or using HeapAlloc
from a Heap with the executable flag set. You will also want to be aware of the FlushInstructionCache
API…
我找到了一个方法:
#include <iostream>
#include <windows.h>
using namespace std;
int main() {
unsigned char bytes[] = "\xB8\x0C\x00\x00\x00\xC3";
HANDLE mem_handle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, sizeof(bytes), NULL);
void *mem_map = MapViewOfFile(mem_handle, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0x0, 0x0, sizeof(bytes));
memcpy(mem_map, bytes, sizeof(bytes));
int result = ((int (*)(void))mem_map)();
cout << "argument:\n" << result << '\n';
return 0;
}
您可以使用内联汇编器来做到这一点:
#include <iostream>
int code() {
__asm (
".byte 0xB8, 0x0C, 0x00, 0x00, 0x00"
);
}
int main() {
std::cout << code() << std::endl;
return 0;
}
系统:Windows10 编译器:MinGW 错误:分段错误
我正在尝试 运行 机器代码作为 c++ 中的函数。这是我的代码:
#include <iostream>
int main()
{
int(*fun_ptr)(void) = ((int(*)())("\xB8\x0C\x00\x00\x00\xC3"));
std::cout << fun_ptr();
return 0;
}
在 ideone.com 等在线编译器中,程序成功打印 12 并退出。我的电脑收到 "Segmentation fault" 错误。谁能帮帮我?
像"\xB8\x0C\x00\x00\x00\xC3"
这样的字符串文字是一个静态存储持续时间[lex.string]/15的对象。编译器通常会将此类字符串文字对象放入二进制文件的 .rdata
部分,即放入只读、不可执行的内存中。因此,尝试执行字符串文字的字节将导致访问冲突。如果要执行包含在全局数组对象中的机器代码字节,则必须确保将对象分配在可执行的部分中。例如(使用 Visual C++ 定位 Windows):
#include <iostream>
#pragma section("runstuff", read, execute)
__declspec(allocate("runstuff"))
const unsigned char code[] = {
0xB8, 0x0C, 0x0, 0x0, 0x0, 0xC3
};
int main()
{
auto fun_ptr = reinterpret_cast<int(*)()>(&code[0]);
std::cout << fun_ptr();
return 0;
}
请注意,像这样的东西本质上是不可移植的,并且充其量具有实现定义的行为。如果您在构建时知道您想要什么机器代码 运行,请考虑使用汇编程序并将生成的目标文件链接到您的可执行文件。如果你想在 Windows 上动态生成机器代码,你将不得不分配可执行内存。为此,要么在可执行(以及可写)内存中创建一个足够大的数组(例如,类似于我上面的示例),您可以在其中放置代码,要么动态分配可执行内存,例如使用 VirtualAlloc
or using HeapAlloc
from a Heap with the executable flag set. You will also want to be aware of the FlushInstructionCache
API…
我找到了一个方法:
#include <iostream>
#include <windows.h>
using namespace std;
int main() {
unsigned char bytes[] = "\xB8\x0C\x00\x00\x00\xC3";
HANDLE mem_handle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, sizeof(bytes), NULL);
void *mem_map = MapViewOfFile(mem_handle, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0x0, 0x0, sizeof(bytes));
memcpy(mem_map, bytes, sizeof(bytes));
int result = ((int (*)(void))mem_map)();
cout << "argument:\n" << result << '\n';
return 0;
}
您可以使用内联汇编器来做到这一点:
#include <iostream>
int code() {
__asm (
".byte 0xB8, 0x0C, 0x00, 0x00, 0x00"
);
}
int main() {
std::cout << code() << std::endl;
return 0;
}