Skip to content

Instantly share code, notes, and snippets.

@paxbun
Last active May 14, 2021 14:16
Show Gist options
  • Select an option

  • Save paxbun/a25f75a9fc5b8c3a262a86f09965bab2 to your computer and use it in GitHub Desktop.

Select an option

Save paxbun/a25f75a9fc5b8c3a262a86f09965bab2 to your computer and use it in GitHub Desktop.
Run dynamically generated machine code on runtime
#ifdef _WIN32
# include <Windows.h>
#else
# include <sys/mman.h>
# include <unistd.h>
#endif
#include <array>
#include <cstddef>
#include <cstring>
#include <iostream>
#include <stdexcept>
#include <vector>
template <typename From, typename To>
To transmute(From from)
{
union
{
From from;
To to;
} u;
u.from = from;
return u.to;
}
void print(uint32_t n)
{
for (uint32_t i = 0; i < n; ++i) std::cout << i << ": Hello, world!" << std::endl;
}
struct Program
{
private:
void (*ptr)();
size_t offset;
public:
Program(void (*callback)(uint32_t), uint32_t input);
~Program();
inline void operator()()
{
if (ptr)
ptr();
}
};
int main()
{
uint32_t input;
std::cout << "Number of times to repeat: ";
std::cin >> input;
try
{
Program program { print, input };
program();
}
catch (const std::runtime_error&)
{
std::perror("Changing protection attribute failed");
return 1;
}
}
Program::Program(void (*callback)(uint32_t), uint32_t input) : ptr { nullptr }, offset { 0 }
{
auto param = transmute<uint32_t, std::array<uint8_t, 4>>(input);
auto func = transmute<void (*)(uint32_t), std::array<uint8_t, 8>>(callback);
uint8_t source[] = {
0x55, // push rbp
0x48, 0x89, 0xe5, // mov rbp, rsp
0x48, 0x83, 0xec, 0x10, // sub rsp, 0x10
#ifdef _WIN32
0xb9, param[0], param[1], param[2], param[3], // mov ecx, input
#else
0xbf, param[0], param[1], param[2], param[3], // mov edi, input
#endif
0x48, 0xb8, func[0], func[1], func[2],
func[3], func[4], func[5], func[6], func[7], // movabs rax, print
0xff, 0xd0, // call rax
0xc9, // leave
0xc3, // ret
};
constexpr size_t program_size = sizeof source;
#ifdef _WIN32
uint8_t* program = new uint8_t[program_size];
memcpy(program, source, program_size);
DWORD before;
if (!VirtualProtect(program, program_size, PAGE_EXECUTE_READWRITE, &before))
{
delete[] program;
throw std::runtime_error { "" };
}
ptr = (void (*)())program;
offset = 0;
#else
size_t page_size = getpagesize();
uint8_t* program = new uint8_t[page_size + program_size];
offset = page_size - ((size_t)program) % page_size;
program += offset;
memcpy(program, source, program_size);
if (mprotect(program, program_size, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
{
delete[](program - offset);
throw std::runtime_error { "" };
}
ptr = (void (*)())program;
#endif
}
Program::~Program()
{
delete[]((uint8_t*)ptr - offset);
ptr = nullptr;
offset = 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment