У меня есть следующий код ASM:
USE32
Start:
jmp Main
struc st
.stLong resd 1
.stWord resw 1
.stBuffer resb 32
endstruc
mystruc:
istruc st
at st.stLong, dd 1
at st.stWord, dw 1
iend
Main:
mov eax, 1
mov [mystruc+st.stLong], eax
Я скомпилировал его с помощью NASM и попытался (шаг за шагом) выполнить двоичный файл, сгенерированный в режиме отладки Visual C ++, с помощью приведенного ниже кода:
unsigned char hexData[50] = {
0xEB, 0x00, 0xB8, 0x01, 0x00, 0x00, 0x00, 0xA3,
0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00
};__asm{
lea eax, hexData
call eax
}
Проблема в том, что выполнение первой инструкции (jmp Main) всегда приводит к исключению нарушения прав доступа. 🙁 Я не знаю, что на самом деле здесь происходит. Скажите, пожалуйста, в чем проблема?
Память может иметь различную защиту, она может быть читаемой, записываемой или исполняемой. По умолчанию определенные вами члены данных не являются исполняемыми, чтобы избежать внедрения кода или использования атаки в вашем коде. У вас есть 2 варианта здесь:
// Remember this function at least allocate a page that is usually 4096 byte
// Use GetSystemInfo to get page size.
void* pvExecutableMem = VirtualAlloc(NULL, 50, MEM_RESERVE | MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
// Resulting page is executable
memcpy( pvExecutableMem, hexData, 50 );
// Now you can execute this page
__asm {
mov eax, pvExecutableMem
call eax
}
Другой подход заключается в изменении типа защиты hexData
:
DWORD dwOldProt;
VirtualProtect( hexData, sizeof(hexData), PAGE_EXECUTE_READWRITE, &dwOldProt );
Но потому что VirtualXXX
Функции работают на страницах и не могут обрабатывать только 50 байтов памяти, это изменит защиту памяти других частей вашей памяти, что может привести к уязвимостям безопасности.
Примечание (я не могу добавить комментарий ..)
__asm{
lea eax, hexData
call eax
}
Вам не нужен встроенный ассемблер для вызова hexData. Может быть, это нормально для MSVC x32, но обратите внимание, что MSVC x64 не имеет встроенного ассемблера.
Вы можете использовать следующий подход вызвать код в двоичном массиве:
#include <iostream>
#include <ostream>
using namespace std;
namespace Namespace
{
namespace Aux
{
extern "C" unsigned char hexData[]={0xC3};
}
extern "C" void hexData();
}
int main()
{
Namespace::hexData();
cout << "alive!" << endl;
return 0;
}
Чтобы исправить нарушение доступа — следуйте советам BigBoss. Например, следующий код работает нормально в MSVC x64:
#include <iostream>
#include <windows.h>
using namespace std;
namespace Namespace
{
namespace Aux
{
extern "C" unsigned char hexData[]={0xC3};
}
extern "C" void hexData();
}
int main()
{
DWORD dwOldProt;
VirtualProtect( Namespace::Aux::hexData, sizeof(Namespace::Aux::hexData), PAGE_EXECUTE_READWRITE, &dwOldProt );
Namespace::hexData();
cout << "alive!" << endl;
return 0;
}