使用NASM汇编程序时出现问题

时间:2012-10-21 18:16:11

标签: c++ assembly nasm

我有以下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 个答案:

答案 0 :(得分:1)

内存可以有不同的保护,它可以是可读,可写或可执行的。默认情况下,由您定义的数据成员不可执行,以避免代码注入或利用代码中的攻击。这里有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个字节的内存,所以这将改变内存其他部分的内存保护,从而导致安全漏洞。

答案 1 :(得分:0)

旁注(我无法添加评论..)

__asm{
    lea eax, hexData
    call eax
}

您不需要内联汇编程序来调用hexData。也许它适用于MSVC x32,但注意MSVC x64没有内联汇编程序。

您可以使用following approach来调用二进制数组中的代码:

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