jit汇编程序,使用C函数

jit assembler in C++, using C functions

本文关键字:函数 使用 汇编程序 jit      更新时间:2023-10-16

我正在用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;
}

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

谢谢Alexandre

printf(没有parens(将计算为函数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("%pn", 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(小端序硬件(上,这将导致字节的顺序相反。

正如Jerry所指出的,只需使用函数的名称就可以获得extern "C"函数的地址。问题是,仅仅把它放在代码流中是没有好处的——你需要生成一个实际的CALL指令。更糟糕的是,x86(0xe8(上的普通CALL指令使用PC相对寻址,这是你不容易使用的,因为你不知道你的代码最终会到达什么地址(最终调用VirtualAlloc会返回的值(。你可以通过不使用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);
}

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

我已经解决了这个问题,我通过了使用interpret_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 = "HIn";
    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 = %dn", exec);
    return 0;
}
相关文章: