Skip to content

Instantly share code, notes, and snippets.

@caiorss
Created November 16, 2020 14:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save caiorss/4baf7dab5728d0e8f5a475967c0846b5 to your computer and use it in GitHub Desktop.
Save caiorss/4baf7dab5728d0e8f5a475967c0846b5 to your computer and use it in GitHub Desktop.
Loading machine code with mmap at runtime
// =======>>> Load and execute machine code at runtime with mmap <<<======
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <sys/mman.h>
using byte = uint8_t;
/** Load machine code into process virtual memory */
void* load_machine_code(byte* buffer, std::size_t size);
void* load_machine_code(std::vector<byte> const& data);
std::vector<byte>
hexstr_to_bytes(std::string const& hexcode);
template<typename T>
inline T load_mcode(std::vector<byte> const& data)
{
return reinterpret_cast<T>( load_machine_code(data) );
}
int main(int argc, char** argv)
{
std::puts("\n ====== Load add_numbers from machine code ================");
// 'extern' means that the variable will be resolved by the Linker
extern std::string add_numbers_str;
// Type alias for function pointer
using add_numbers_t = int (*) (int, int);
auto add_numbers_code = hexstr_to_bytes(add_numbers_str);
// Load machine code for function add_numbers() at runtime.
auto add_numbers = load_mcode<add_numbers_t>(add_numbers_code);
std::cout << " [RESULT] add_numbers(20, 100) = " << add_numbers(20, 100) << '\n';
std::cout << " [RESULT] add_numbers(206, 782) = " << add_numbers(206, 782) << '\n';
std::puts("\n ======== Load factorial() from machine code =============");
extern std::vector<byte> factorial_code;
// Function pointer alias
using factorial_t = int (*) (int);
auto factorial_func = load_mcode<factorial_t>(factorial_code);
std::cout << " [RESULT] factorial(5) = " << factorial_func(5) << '\n';
std::cout << " [RESULT] factorial(6) = " << factorial_func(6) << '\n';
std::cout << " [RESULT] factorial(7) = " << factorial_func(7) << '\n';
std::fprintf(stdout, " [TRACE] Process terminated gracefully Ok. \n");
return 0;
}
//===========================================================//
// I P L E M E N T A T I O N S //
//===========================================================//
void* load_machine_code(const byte* buffer, std::size_t size)
{
// Create anonymous mapping (not backed by file), a memory that will
// be later marked as executable.
void* pmap = ::mmap( nullptr
, size
, PROT_READ | PROT_WRITE
, MAP_PRIVATE | MAP_ANONYMOUS
, -1, 0 );
if(pmap == MAP_FAILED){ throw std::runtime_error("Failed create memory map"); }
// Copy machine code to memory map
std::memcpy( pmap, buffer, size);
// Mark memory as executable, but not writable.
if( mprotect(pmap, size, PROT_READ | PROT_EXEC ) == -1 )
throw std::runtime_error("Faile to change memory protection flags");
return pmap;
}
std::vector<byte>
hexstr_to_bytes(std::string const& hexcode)
{
std::vector<byte> bytes;
bytes.reserve(hexcode.size());
char* token = strtok((char*) hexcode.data(), "\\x");
while( token != nullptr ){
char byte = (char) strtol(token, nullptr, 16);
// ss << byte;
bytes.push_back(byte);
token = strtok(nullptr, "\\x");
}
return bytes;
}
void* load_machine_code(std::vector<byte> const& data)
{
return load_machine_code(&data[0], data.size());
}
// int add_numners(int x, int y)
//---------------------------------------------------
// 0000000000401152 <add_numbers>:
// 401152: 55 push %rbp
// 401153: 48 89 e5 mov %rsp,%rbp
// 401156: 48 89 f8 mov %rdi,%rax
// 401159: 48 01 f0 add %rsi,%rax
// 40115c: 5d pop %rbp
// 40115d: c3 retq
//
// Machine encoded as ASCII string
std::string add_numbers_str = "\\x55\\x48\\x89\\xe5\\x48\\x89\\xf8\\x48\\x01\\xf0\\x5d\\xc3";
std::vector<byte> factorial_code = {
0x55 // push rbp
, 0x48, 0x89, 0xe5 // mov rbp,rsp
, 0x89, 0x7d, 0xec // mov DWORD PTR [rbp-0x14],edi
, 0xc7, 0x45, 0xfc, 0x01, 0x00, 0x00, 0x00 // mov DWORD PTR [rbp-0x4],0x1
, 0xc7, 0x45, 0xf8, 0x01, 0x00, 0x00, 0x00 // mov DWORD PTR [rbp-0x8],0x1
, 0xeb, 0x0e // jmp 40115b <factorial+0x25>
, 0x8b, 0x45, 0xfc // mov eax,DWORD PTR [rbp-0x4]
, 0x0f, 0xaf, 0x45, 0xf8 // imul eax,DWORD PTR [rbp-0x8]
, 0x89, 0x45, 0xfc // mov DWORD PTR [rbp-0x4],eax
, 0x83, 0x45, 0xf8, 0x01 // add DWORD PTR [rbp-0x8],0x1
, 0x8b, 0x45, 0xf8 // mov eax,DWORD PTR [rbp-0x8]
, 0x3b, 0x45, 0xec // cmp eax,DWORD PTR [rbp-0x14]
, 0x7c, 0xea // jl 40114d <factorial+0x17>
, 0x8b, 0x45, 0xfc // mov eax,DWORD PTR [rbp-0x4]
, 0x5d // pop rbp
, 0xc3 // ret
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment