【问题标题】:jit assembler in C++, using C functionsC++ 中的 jit 汇编器,使用 C 函数
【发布时间】:2013-02-09 20:33:31
【问题描述】:

我正在用 C++ 开发一个简单的 JIT 汇编系统,但是,我想在这个 jit 系统中调用 C 函数,所以,我的想法……我需要命令的指针……但是,我不知道我怎么能得到这个......

这是我的代码

#include <cstdio>
#include <vector>
#include <windows.h>

int Execute(std::vector<unsigned char> code)
{
    int eaxRegister;

    unsigned char* func = (unsigned char*)VirtualAlloc( 0, code.size() + 1, 0x1000, 0x40 );

    memcpy( func, code.data(), code.size() );
    func[code.size()] = 0xC3; // add the ret to the final of code final

    CallWindowProc( (WNDPROC)func, 0, 0, 0, 0 );

    _asm mov eaxRegister, eax;

    VirtualFree( func, code.size() + 1, 0x4000 );

    return eaxRegister;
}

int main()
{
    std::vector<unsigned char> code;

    //mov eax, 10
    code.push_back( 0xc7 );
    code.push_back( 0xc0 );
    code.push_back( 0xa );
    code.push_back( 0x0 );
    code.push_back( 0x0 );
    code.push_back( 0x0 );

    //mov ecx, 10
    code.push_back( 0xc7 );
    code.push_back( 0xc1 );
    code.push_back( 0xa );
    code.push_back( 0x0 );
    code.push_back( 0x0 );
    code.push_back( 0x0 );

    //add eax, ecx
    code.push_back( 0x3 );
    code.push_back( 0xc1 );

    // push MESSAGE
    const char* ohi = "HI";
    code.push_back( 0x69 );
    code.push_back( *ohi );

    // call prinf ?????
    code.push_back( 0xe8 );
    code.push_back( 0xfff/* offset of printf */ ) ;

    // add esp, 4
    code.push_back( 0x83 );
    code.push_back( 0xc4 );
    code.push_back( 0x04 );
    code.push_back( 0x0 );
    code.push_back( 0x0 );
    code.push_back( 0x0 );

    int exec = Execute( code );
    printf("SUM = %d", exec);

    return 0;
}

所以,我的问题是,如何获取 printf 命令的偏移量以在 JIT 中使用,或者,如何通过 JIT 使用 C 函数???

谢谢 亚历山大

【问题讨论】:

  • 你写了一个JIT,但不知道LoadLibrary和朋友? #困惑

标签: c++ c assembly jit


【解决方案1】:

printf(不带括号)将评估为函数printf 的地址,因此您显然想要code.push_back(printf);

编辑:当然,既然您已将code 定义为一个简单的向量`,那将无法按原样工作。您需要一次推回地址的单个字节。这是一个快速演示,显示将其推回,然后打印出结果并显示它与将地址传递给 printf 并使用 %p 转换得到的结果几乎相同:

#include <vector>
#include <stdio.h>
#include <iostream>

int main() {
    std::vector<unsigned char> code;

    auto a = printf;
    char *p = (char *) &a;

    printf("%p\n", printf);

    for (int i=0; i<sizeof(a); i++)
        code.push_back(*p++);

    for (int i=0; i<code.size(); i++)
        std::cout << std::hex << (unsigned int)code[i] << " ";
    return 0;
}

如您所见,%p 将整个指针显示在一起,而这一次显示一个字节。在 Windows(小端硬件)上,这将导致字节顺序相反。

【讨论】:

  • 很有趣 :) ...但是,不行...哈哈 :( ...我不知道为什么 :(
  • 我已经删除了 ohi 的 *,以获得真正的偏移量,并且 printf 命令不起作用 :(
  • 好吧,显然你需要调用code.push_back 四次,printf 的每个字节调用一次(假设是 32 位环境)。 ohi 也是如此。现在可以用了吗?
  • 好的,但是我的消息有一个大问题,我无法获得消息的真实偏移量:( ...并且,打印消息;x
【解决方案2】:

正如 Jerry 所说,您只需使用函数名称即可获取 extern "C" 函数的地址。问题是,仅仅把它放在你的代码流中对你没有好处——你需要生成一个实际的 CALL 指令。更糟糕的是,x86 (0xe8) 上的普通 CALL 指令使用 PC 相对寻址,你不能轻易使用它,因为你不知道你的代码最终会到达哪个地址(最终调用 @ 987654322@ 将返回)。您可以通过不使用 PC 相对寻址模式来解决这个问题:

void gen_call(std::vector<unsigned char> &code, void *address) {
    // mov eax,address
    code.push_back(0xb8);
    code.push_back((uint32_t)address & 0xff);
    code.push_back(((uint32_t)address >> 8) & 0xff);
    code.push_back(((uint32_t)address >> 16) & 0xff);
    code.push_back(((uint32_t)address >> 24) & 0xff);
    // call eax
    code.push_back(0xff);
    code.push_back(0xd0);
}

另外,您的“推送消息”代码是错误的 - 您正在推送消息的第一个字符,但您真正想要的是推送字符串的地址。

【讨论】:

  • 推送消息的正确形式是使用不带指针 (*) 的变量? const char* ohi = "你好"; code.push_back(0x69); code.push_back(ohi);
【解决方案3】:

我已经解决了问题,我通过使用 reinterpret_cast

这是我的解决方案:

#include <cstdio>
#include <vector>
#include <windows.h>

using namespace std;

class Buffer: public vector<unsigned char>
{
public:
    void push_dword(DWORD dw)
    {
        push_back(dw);
        push_back(dw >> 8);
        push_back(dw >> 16);
        push_back(dw >> 24);
    }

    void push_ptr(const void *p)
    {
        push_dword(reinterpret_cast<DWORD>(p));
    }

    int Execute()
    {
        char *func = reinterpret_cast<char *>(VirtualAlloc(
            0, size() + 1, MEM_COMMIT, PAGE_EXECUTE_READWRITE ));

        memcpy( func, data(), size() );
        func[size()] = 0xC3; // add the ret to the final of code final

        int ret = (*reinterpret_cast<int(*)()>(func))();

        VirtualFree( func, 0, MEM_RELEASE );

        return ret;
    }
};

int main()
{
    Buffer code;

    // push MESSAGE
    const char* ohi = "HI\n";
    code.push_back( 0x68 );
    code.push_ptr( ohi );

    // mov eax, printf
    code.push_back( 0xb8 );
    code.push_ptr( reinterpret_cast<void *>(&printf) );

    // call eax
    code.push_back( 0xff );
    code.push_back( 0xd0 );

    // add esp, 4
    code.push_back( 0x83 );
    code.push_back( 0xc4 );
    code.push_back( 0x04 );

    int exec = code.Execute();
    printf("SUM = %d\n", exec);

    return 0;
}

【讨论】:

    猜你喜欢
    • 2011-09-04
    • 2010-12-21
    • 1970-01-01
    • 1970-01-01
    • 2018-10-13
    • 2011-09-03
    • 2021-11-11
    • 2021-04-23
    • 2012-12-03
    相关资源
    最近更新 更多