Alexandre
Alexandre

Reputation: 2025

jit assembler in C++, using C functions

I'm developing a simple JIT Assembly system in C++, but, I whant to call C functions in this jit system, so, what I have thinked... I need the pointer of the command... but, I don't know how I can get this...

That is my code

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

So, my problem is, how I can get the offset of printf command to use in JIT, or, how I can use the C function using the JIT ???

Thanks Alexandre

Upvotes: 1

Views: 651

Answers (3)

Alexandre
Alexandre

Reputation: 2025

I have solved the questio, I passed to use the reinterpret_cast

here my solution:

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

Upvotes: 0

Chris Dodd
Chris Dodd

Reputation: 126546

As Jerry notes, you can get the address of an extern "C" function by just using the name of the function. The problem is, just putting that in your code stream does you no good -- you need to generate an actual CALL instruction. To make matters worse, the normal CALL instruction on x86 (0xe8) uses PC-relative addressing, which you can't readily use, as you don't know what address your code will end up at (the value the eventual call to VirtualAlloc will return). You can get around that by not using a PC-relative addressing mode:

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

Also, your "push MESSAGE" code is wrong -- you're pushing the first character of the message, but what you really want is to push the address of the string.

Upvotes: 0

Jerry Coffin
Jerry Coffin

Reputation: 490808

printf (without parens) will evaluate to the address of the function printf, so you'd apparently want code.push_back(printf);

Edit: Of course, since you've defined code as a simple vector`, that won't work as-is. You'll need to push back the individual bytes of the address one at a time. Here's a quick demo, showing pushing it back, then printing out the results and showing that it's pretty much the same as you get by passing the address to printf and converting with %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;
}

As you can see, %p shows the entire pointer together, whereas this shows one byte at a time. On Windows (little-endian hardware) this will result in the byte being in reverse order.

Upvotes: 3

Related Questions