#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!