/* * How to dereference a null pointer and get away with it. * * G. Back, CS 3214 */ #define _GNU_SOURCE 1 #include #include #include #include static void install_signal_handler(int signal, void (*handler)(int, siginfo_t *, void *)) { struct sigaction act; act.sa_sigaction = handler; act.sa_flags = SA_SIGINFO; sigemptyset (&act.sa_mask); int status = sigaction (signal, &act, NULL); if (status) { perror ("sigaction"); exit (1); } } static void catch_segfault(int signo, siginfo_t *info, void * _ctxt) { ucontext_t * ctxt = _ctxt; printf("Catching Segfault at sig=%d fault addr is %p eip was at %x\n", signo, info->si_addr, ctxt->uc_mcontext.gregs[REG_RIP]); /* The assembly code for main (below) is: 400690: b8 00 00 00 00 mov $0x0,%eax ----> This is where it faults, eip has value 400695 on fault 400695: 8b 30 mov (%rax),%esi ----> If it hadn't faulted, result would be in %esi 400697: bf ee 07 40 00 mov $0x4007ee,%edi */ ctxt->uc_mcontext.gregs[REG_RSI] = 42; // put '42' in rsi ctxt->uc_mcontext.gregs[REG_RIP] += 2; // skip to next instruction // upon return, OS will read *ctxt and restore CPU's registers from it } int main() { install_signal_handler(SIGSEGV, catch_segfault); printf("Dereferencing NULL -> %d ...\n", *(int *)NULL); return 0; }