【问题标题】:Problems when using NASM assembler使用 NASM 汇编器时的问题
【发布时间】:2012-10-11 15:06:33
【问题描述】:

我有以下 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)总是会导致访问冲突异常。 :( 我不知道这里到底发生了什么。你能告诉我问题是什么吗?

【问题讨论】:

  • 在 Main 之前尝试 SECTION .text:
  • NASM会产生相对地址跳转吗?可能只是跳转到某个固定地址,在嵌入式代码案例中是无效的
  • @Lol4t0:我认为生成的所有跳转都是相对的。

标签: c++ assembly nasm


【解决方案1】:

内存可以有不同的保护,它可以是可读的、可写的或可执行的。默认情况下,您定义的数据成员不可执行,以避免代码注入或利用代码中的攻击。你有两个选择:

// 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 字节的内存,这将改变内存其他部分的内存保护,从而导致安全漏洞。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 使用内联汇编器是我最喜欢执行此类二进制代码的方式。 :) 不管怎么说,还是要谢谢你! :)
    • 我也更喜欢使用内联汇编程序,但不幸的是它并非在任何地方都可用(例如在 MSVC x64 中)。
    猜你喜欢
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-07
    • 1970-01-01
    相关资源
    最近更新 更多