Reputation: 2025
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
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
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
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