从字节数组中发出内联汇编

时间:2015-01-06 22:30:35

标签: c++ visual-c++

我在C ++函数中有这些参数:

unsigned char originalBytes[], int originalBytesLength

这个循环发出字节:

for (int i = 0; i < originalBytesLength; i++)
    __asm _emit originalBytes[i];

但是,我从最后一行收到错误"Improper operand type (C2415)"。有没有办法在没有硬编码的情况下发出字节?

我尝试做的是将一个字节数组传递给该函数,并让它使用内联汇编发出字节。因此,每次调用时字节可能不同。

2 个答案:

答案 0 :(得分:4)

这可能与您的想法无关。

首先,你不能在一个循环中使用__asm _emit,它不会&#34;意识到&#34;围绕它的代码。 如果你想要在循环中尝试使用#include,它只会被处理一次。

最重要的是_asm _emit不是你可以在运行时使用的东西,或者是变量,甚至不是constexpr。 它只是一种在编译时在应用程序中转储原始字节文字的方法,一次。 因此,确实没有一种干净的方法来做你正在尝试用__asm _emit做的事情。您必须在编译时逐字节地发出该缓冲区,或者使用更方便的内联ASM块。 所以不,没有硬编码就无法发出字节。

还要注意编译器没有尝试理解你刚刚在二进制文件中间转储的字节数。如果您正在修改寄存器或编写与位置相关的代码,这可能会与编译器的操作发生冲突并导致可怕的错误。

编辑:

  

我尝试做的是将一个字节数组传递给该函数,并让它使用内联汇编发出字节。因此,每次调用时字节可能不同。

你不能用__asm _emit做到这一点。 实际上,在运行时没有简单的方法可以做到这一点,因为每次发出一个字节时,都必须增加二进制文件。一旦二进制文件已经编译,那就真的很难。

如果您有重定位信息,并且您已准备好暂停所有线程,修复所有重定位,重写不适合的短跳,那么

可能 再作为长跳(并重新修复重定位,并在循环中重新组合jmps)。然后修复这些部分,必要时重新定位其他线程并继续。我已经听说过恶意软件(简化版),但是关于恶意软件。

那就是说,你可能想看看各种JIT库。我知道LLVM和GGC有一个。 你不会得到完全相同的结果,但JIT可能就是你想要的。 您将获得一个可以使用函数指针跳转到的字节数组,而不是在运行时在任意位置发出的代码。

答案 1 :(得分:3)

如果你真的想要执行字节,并且它们在运行时才知道,你可以将它们写入内存的读/执行区域,然后调用该区域的基础。确实这是你想要做的,并且非常确定这些字节的来源。在非常具体的情况下,我不建议这样做。以下是如何在Windows中执行此操作。

typedef __cdecl void (* voidf_t)(); // make sure the calling convention is correct
void execute(LPBYTE bytes, DWORD len_bytes) {
    // bytes on the stack are NX on most modern operating systems, get some executable memory
    LPBYTE exec_region = (LPBYTE) VirtualAlloc(NULL, len_bytes, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if(exec_region != NULL) {
        memcpy(exec_region, bytes, len_bytes);
        voidf_t fun = exec_region;
        fun(); // this will call the bytes
        VirtualFree(exec_region, 0, MEM_RELEASE);
        fun = exec_region = NULL;
    }
}

使用这样的技术时,需要考虑很多因素。你必须知道你执行的字节来自哪里。您正在执行的字节也必须是一个返回的函数,并且期望使用typedef中使用的约定进行调用。代码也必须完全独立于位置,因为没有执行重定位修复。通常情况下,这样的代码最终会成为应用程序漏洞和/或不稳定的根源,因此我建议您考虑是否有更好的解决方案来解决您的问题。