#include <signal.h> void bad_instruction(int sig, siginfo_t *HowCome, void *ucontextv) { struct ucontext *uc=(struct ucontext *)ucontextv; struct sigcontext *r=(struct sigcontext *)(&uc->uc_mcontext); unsigned char c=*(unsigned char *)(r->rip); // read bad instruction std::cout<<"Fixing bad instruction byte "<<(int)c<<std::endl; r->rip++; // skip over bad instruction byte r->rax=1234; // change machine state } class static_init { public: static_init() { struct sigaction sa; sa.sa_sigaction = bad_instruction; sigemptyset( &sa.sa_mask ); sa.sa_flags = 0; sa.sa_flags |= SA_SIGINFO; /* we want a siginfo_t */ sa.sa_flags |= SA_RESTART; /* restart interrupted syscalls (no EINTR errors) */ if (sigaction (SIGILL, &sa, 0)) { perror("sigaction"); exit(1); } } }; extern "C" long run_code(void); __asm__ ( ".intel_syntax noprefix /* use good syntax */ \n\ .text /* make executable */ \n\ run_code:\n\ .byte 0x06, 0x07, 0x0E /* examples of bad code bytes */ \n\ ret\n\ \n\ .att_syntax prefix\n" ); long foo(void) { static static_init init; return run_code(); }
The 64-bit
disassembly of the "run_code" function is:
0000000000000000 <run_code>: 0: 06 (bad) 1: 07 (bad) 2: 0e (bad) 3: c3 ret
At runtime
this prints:
Fixing bad instruction byte 6 Fixing bad instruction byte 7 Fixing bad instruction byte 14 Program complete. Return 1234 (0x4D2)So it works!