public
Created

A simple runtime assembler written in C++

  • Download Gist
Assembler.cpp
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
#include "Assembler.hpp"
 
Assembler::Assembler()
{
}
 
int Assembler::Run()
{
if ( code.size() == 0 ) return -1;
 
int reg_eax;
 
unsigned char* func = (unsigned char*)VirtualAlloc( 0, code.size() + 1, 0x1000, 0x40 );
 
memcpy( func, code.data(), code.size() );
func[code.size()] = 0xC3;
 
CallWindowProc( (WNDPROC)func, 0, 0, 0, 0 );
 
_asm mov reg_eax, eax;
 
VirtualFree( func, code.size() + 1, 0x4000 );
 
return reg_eax;
}
 
void Assembler::Clear()
{
code.clear();
}
 
void Assembler::INop()
{
code.push_back( 0x90 );
}
 
void Assembler::IMov32( Register dst, int value )
{
code.push_back( 0xC7 );
code.push_back( 0xC0 | dst );
PushInt32( value );
}
 
void Assembler::IMov32( Register dst, Register src )
{
code.push_back( 0x8B );
code.push_back( 0xC0 | ( dst << 3 ) | src );
}
 
void Assembler::IInc32( Register reg )
{
code.push_back( 0xFF );
code.push_back( 0xC0 | reg );
}
 
void Assembler::IAdd32( Register dst, Register src )
{
code.push_back( 0x03 );
code.push_back( 0xC0 | ( dst << 3 ) | src );
}
 
void Assembler::IPush32( int value )
{
code.push_back( 0x68 );
PushInt32( value );
}
 
void Assembler::IPop32( Register reg )
{
code.push_back( 0x8F );
code.push_back( 0xC0 | reg );
}
 
void Assembler::PushInt32( int i )
{
char b[4];
memcpy( b, &i, 4 );
code.push_back( b[0] );
code.push_back( b[1] );
code.push_back( b[2] );
code.push_back( b[3] );
}
Assembler.hpp
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
#include <Windows.h>
#include <vector>
 
// TODO:
// Preserve registers besides EAX (with naked function call?)
// Allow addressing beyond just registers (e.g. addresses in registers)
 
// Available registers for addressing
enum Register {
REG_EAX = 0,
REG_ECX = 1
};
 
// Class that allows programs to conveniently construct machine code at runtime
class Assembler
{
public:
Assembler();
 
int Run();
void Clear();
 
// Instructions
void INop();
void IMov32( Register dst, int value );
void IMov32( Register dst, Register src );
void IInc32( Register reg );
void IAdd32( Register dst, Register src );
void IPush32( int value );
void IPop32( Register reg );
 
private:
std::vector<unsigned char> code;
 
void PushInt32( const int i );
};
main.cpp
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#include <cstdio>
#include "Assembler.hpp"
 
int main()
{
Assembler as;
as.IMov32( REG_EAX, 2 );
as.IMov32( REG_ECX, 4 );
as.IAdd32( REG_EAX, REG_ECX );
int eax = as.Run();
 
printf( "EAX contains %d\n", eax );
 
return 0;
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.