1

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関数を使用する方法ですか???

ありがとうアレクサンドル

4

3 に答える 3

3

printf(括弧なし)は関数のアドレスに評価されるため、printf明らかに必要ですcode.push_back(printf);

編集: もちろん、code単純な vector` として定義したので、そのままでは機能しません。アドレスの個々のバイトを一度に 1 つずつプッシュ バックする必要があります。これは簡単なデモで、プッシュバックしてから結果を出力し、アドレスを 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 はポインター全体を一緒に表示しますが、これは一度に 1 バイトを表示します。Windows (リトル エンディアン ハードウェア) では、バイトが逆順になります。

于 2013-02-24T17:33:47.063 に答える
0

extern "C"Jerryが指摘しているように、関数の名前を使用するだけで関数のアドレスを取得できます。問題は、それをコードストリームに入れるだけでは役に立たないことです。つまり、実際の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);
}

また、「push MESSAGE」コードが間違っています。メッセージの最初の文字をプッシュしていますが、本当に必要なのは文字列のアドレスをプッシュすることです。

于 2013-02-24T19:15:25.867 に答える
0

私は質問を解決しました、私は 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;
}
于 2013-02-25T12:59:11.820 に答える