/* * Helper to invoke int80 with controlled regs and capture the final regs.
*/ staticvoid do_full_int80(struct syscall_args32 *args)
{ #ifdef __x86_64__ registerunsignedlong bp asm("bp") = args->arg5; asmvolatile ("int $0x80"
: "+a" (args->nr), "+b" (args->arg0), "+c" (args->arg1), "+d" (args->arg2), "+S" (args->arg3), "+D" (args->arg4), "+r" (bp)
: : "r8", "r9", "r10", "r11");
args->arg5 = bp; #else
sys32_helper(args, int80_and_ret); #endif
}
#ifdef __i386__ staticvoid (*vsyscall32)(void);
/* * Nasty helper to invoke AT_SYSINFO (i.e. __kernel_vsyscall) with * controlled regs and capture the final regs. This is so nasty that it * crashes my copy of gdb :)
*/ staticvoid do_full_vsyscall32(struct syscall_args32 *args)
{
sys32_helper(args, vsyscall32);
} #endif
static siginfo_t wait_trap(pid_t chld)
{
siginfo_t si; if (waitid(P_PID, chld, &si, WEXITED|WSTOPPED) != 0)
err(1, "waitid"); if (si.si_pid != chld)
errx(1, "got unexpected pid in event\n"); if (si.si_code != CLD_TRAPPED)
errx(1, "got unexpected event type %d\n", si.si_code); return si;
}
printf("[RUN]\tRestart the syscall (ip = 0x%lx)\n",
(unsignedlong)regs.user_ip);
/* * This does exactly what it appears to do if syscall is int80 or * SYSCALL64. For SYSCALL32 or SYSENTER, though, this is highly * magical. It needs to work so that ptrace and syscall restart * work as expected.
*/
regs.user_ax = regs.user_syscall_nr;
regs.user_ip -= 2; if (ptrace(PTRACE_SETREGS, chld, 0, ®s) != 0)
err(1, "PTRACE_SETREGS");
if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0)
err(1, "PTRACE_SYSEMU");
wait_trap(chld);
if (ptrace(PTRACE_GETREGS, chld, 0, ®s) != 0)
err(1, "PTRACE_GETREGS");
if (regs.user_syscall_nr != SYS_gettid ||
regs.user_arg0 != 10 || regs.user_arg1 != 11 ||
regs.user_arg2 != 12 || regs.user_arg3 != 13 ||
regs.user_arg4 != 14 || regs.user_arg5 != 15) {
printf("[FAIL]\tRestart nr or args are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n", (unsignedlong)regs.user_syscall_nr, (unsignedlong)regs.user_arg0, (unsignedlong)regs.user_arg1, (unsignedlong)regs.user_arg2, (unsignedlong)regs.user_arg3, (unsignedlong)regs.user_arg4, (unsignedlong)regs.user_arg5);
nerrs++;
} else {
printf("[OK]\tRestarted nr and args are correct\n");
}
printf("[RUN]\tChange nr and args and restart the syscall (ip = 0x%lx)\n",
(unsignedlong)regs.user_ip);
/* Advance. We should be stopped at exit. */
printf("[RUN]\tSYSCALL\n"); if (ptrace(PTRACE_SYSCALL, chld, 0, 0) != 0)
err(1, "PTRACE_SYSCALL");
wait_trap(chld);
if (ptrace(PTRACE_GETREGS, chld, 0, ®s) != 0)
err(1, "PTRACE_GETREGS");
/* Poke the regs back in. This must not break anything. */ if (ptrace(PTRACE_SETREGS, chld, 0, ®s) != 0)
err(1, "PTRACE_SETREGS");
/* Catch the (ignored) SIGUSR1. */ if (ptrace(PTRACE_CONT, chld, 0, 0) != 0)
err(1, "PTRACE_CONT"); if (waitpid(chld, &status, 0) != chld)
err(1, "waitpid"); if (!WIFSTOPPED(status)) {
printf("[FAIL]\tChild was stopped for SIGUSR1 (status = 0x%x)\n", status);
nerrs++;
} else {
printf("[OK]\tChild got SIGUSR1\n");
}
/* The next event should be pause(2) again. */
printf("[RUN]\tStep again\n"); if (ptrace(PTRACE_SYSCALL, chld, 0, 0) != 0)
err(1, "PTRACE_SYSCALL");
wait_trap(chld);
/* We should be stopped at pause(2) entry. */
if (ptrace(PTRACE_GETREGS, chld, 0, ®s) != 0)
err(1, "PTRACE_GETREGS");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.