Как запустить машинный код как функцию в C ++ - PullRequest
1 голос
/ 14 апреля 2019

система: Windows 10 компилятор: 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 и завершает работу. В моем компьютере я получаю ошибку «Ошибка сегментации». Кто-нибудь может мне помочь?

Ответы [ 2 ]

2 голосов
/ 14 апреля 2019

Строковый литерал, такой как "\xB8\x0C\x00\x00\x00\xC3", является объектом статической длительности хранения [lex.string] / 15 . Компилятор обычно помещает такие строковые литеральные объекты в секцию .rdata вашего двоичного файла, то есть в неисполняемую память только для чтения. Как следствие, попытка выполнить байты строкового литерала приведет к нарушению доступа. Если вы хотите выполнить байты машинного кода, содержащиеся в объекте глобального массива, вы должны убедиться, что ваш объект размещен в исполняемом разделе. Например (для Windows с Visual C ++):

#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 или HeapAlloc из кучи с установленным флагом исполняемого файла . Вам также понадобится знать о FlushInstructionCache API & hellip;

0 голосов
/ 14 апреля 2019

Я нашел метод:

#include <windows.h>
#include <iostream>

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));
cout << "argument:\n";

int result = (( int(*)(void) )mem_map)();
cout << result;
cout << '\n';

return 0;

}

...