【问题标题】:Expression cannot be used as a function, c++ machine code function表达式不能作为函数,c++机器码函数
【发布时间】:2019-02-13 14:30:32
【问题描述】:

我正在为缓冲区溢出执行生成机器代码,并且想要一种快速简便的方法将字节码插入程序并查看它如何在我的主机上运行。

我寻找在 C++ 中动态生成函数的方法,并在very interesting answer 中遇到了这个问题。它得到了相当多的支持,似乎没有人质疑他们所说的话。

但是,当尝试实现他们在我自己的程序中编写的内容时,我收到错误“表达式不能用作函数”。

这是我的代码:

int main()
{
    uint8_t machinecode[] = {0x90, 0x0F, 0x01};

    *reinterpret_cast<void**>(&machinecode)();

    return 0;
}

【问题讨论】:

  • 操作系统不允许你执行任意一块内存。为此,您需要mmap(或等效的,取决于您的操作系统)才能创建可执行的内存块。还有reinterpret_castvoid**?不,您需要重新解释为函数指针。您可能想阅读以下内容:eli.thegreenplace.net/2013/11/05/how-to-jit-an-introduction
  • 对于初学者来说,() 的优先级高于*,在这种情况下。所以这是错误的,马上。其次,void * 不是可调用函数,它是无类型指针,不能作为函数调用。指向返回 void 的函数的指针是 void (*)()
  • @EdwardSeverinsen 最后一个问题:你到底想做什么?编写自己的 jit 是一项困难、容易出错且极其耗时的任务。你确定你不想使用一些现有的工具,例如LLVM?
  • 您链接的答案获得了 32 次赞成,这仅表明人们会赞成他们不理解的事情,只要它看起来足够聪明并且已经有一些赞成。
  • 字节码。你一直用那个词。 I don't think it means what you think it means.

标签: c++ c++11 bytecode


【解决方案1】:

就编译的代码有效性而言,希望我能正确理解您的问题,您需要转换为可调用对象,在本例中为 void(*)(),而不仅仅是 void*,您还需要一个额外的一组括号:

(*reinterpret_cast<void(*)()>(bytecode))();

请参阅 here live,但我不确定这是您真正想要运行的任何内容,即使在您提供的上下文中也是如此。

【讨论】:

  • &amp; [0] 是多余的。使用* 取消引用函数指针也是多余的,因为生成的函数会立即衰减回指针(由() 调用)。代码可以缩短为reinterpret_cast&lt;void(*)()&gt;(bytecode)()
  • @melpomene 复制了一些尝试时打错了字。谢谢。对不起
  • 对不起,又犯傻了。用 C++ 编程已经有几年了,但有时我会忘记最基本的语法。 :P
  • @EdwardSeverinsen 不会称其为愚蠢,这绝对不是最基本的语法。很高兴能帮上忙。
【解决方案2】:

怀疑经验主义者的回答是正确的,并且解决了编译问题,所以我将其标记为正确。

但是,我必须做的是创建一个函数来使用VirtualAlloc 分配可执行内存:

uint8_t* alloc_executable(uint32_t alloc_size)
{
    if(!alloc_size)
        return nullptr;

    return reinterpret_cast<uint8_t*>(VirtualAlloc(NULL, alloc_size, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE));
}

我的main 功能:

int main()
{
    /*
    * nop - 0x90
    * ret - 0xC3
    */
    uint8_t machinecode[] = {0x90, 0xC3};
    uint32_t machinecode_size = ARRAYSIZE(machinecode);

    uint8_t* exec_mem = alloc_executable(machinecode_size);

    memcpy(exec_mem, bytecode, machinecode_size);

    FlushInstructionCache(GetCurrentProcess(), exec_mem, machinecode_size);

    auto func = reinterpret_cast<void(*)()>(exec_mem);

    func();

    return 0;
}

进程返回0,没有错误。

另外:显然这是特定于 Windows 的。我的目标平台是 x64 Windows 10。

【讨论】:

    猜你喜欢
    • 2022-11-12
    • 2019-06-22
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 2020-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多