Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
273 lines (214 sloc) 6.12 KB
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <errno.h>
#include <wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#define DR_OFFSET(num) ((void *) (& ((struct user *) 0)->u_debugreg[num]))
#define __SI_FAULT 0
/*
* SIGTRAP si_codes
*/
#define TRAP_BRKPT (__SI_FAULT|1) /* process breakpoint */
#define TRAP_TRACE (__SI_FAULT|2) /* process trace trap */
#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */
#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint/watchpoint */
#define NSIGTRAP 4
void print_trap_si_code(siginfo_t *siginfo)
{
int si_code = siginfo->si_code;
switch(si_code) {
case SI_KERNEL:
printf("SIGTRAP was sent by the kernel.\n");
break;
case SIGTRAP:
case SIGTRAP | 0x80:
printf("This is a syscall-stop.\n");
break;
case TRAP_BRKPT:
printf("Process breakpoint.\n");
break;
case TRAP_TRACE:
printf("Process trace trap.\n");
break;
case TRAP_BRANCH:
printf("Process taken branch trap.\n");
break;
case TRAP_HWBKPT:
printf("Hardware breakpoint/watchpoint.\n");
break;
default:
printf("unkonwn trap si_code: %d\n", si_code);
break;
}
}
int handle_break(pid_t pid)
{
siginfo_t siginfo;
struct user_regs_struct regs;
int status, signo, ret;
ret = waitpid(pid, &status, 0);
if (ret == -1) {
perror("tracer, failed waiting tracee");
exit(1);
}
if (WIFEXITED(status)) {
printf("tracer, tracee exited!\n");
return 1;
}
ret = ptrace(PTRACE_GETREGS, pid, NULL, (void *) &regs);
if (ret != 0) {
perror("tracer, failed get regs");
exit(1);
}
printf("rip: %llx\n", regs.rip);
signo = WSTOPSIG(status);
printf("stopped by %s\n", strsignal(signo));
if (signo == SIGTRAP) {
ret = ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo);
if (ret != 0) {
perror("tracer, failed to get siginfo\n");
return 0;
}
print_trap_si_code(&siginfo);
}
return 0;
}
int set_hwbp(pid_t pid, void *addr)
{
unsigned long dr_7 = 0;
if (ptrace(PTRACE_POKEUSER, pid, DR_OFFSET(0), addr) != 0) {
perror("tracer, faile to set DR_0\n");
return 1;
}
dr_7 = dr_7 | 0x01; // set dr_0 local
dr_7 = dr_7 | 0x02; // set dr_0 global
// dr_7 = dr_7 & ((~0x0f) << 16); // type exec, and len 0
if (ptrace(PTRACE_POKEUSER, pid, DR_OFFSET(7), (void *) dr_7) != 0) {
perror("tracer, faile to set DR_7\n");
return 1;
}
return 0;
}
int clear_dr6(pid_t pid)
{
if (ptrace(PTRACE_POKEUSER, pid, DR_OFFSET(6), 0) != 0) {
perror("tracer, failed to clear DR_6\n");
return 1;
}
return 0;
}
int get_dr6(pid_t pid, long *dr6)
{
errno = 0;
*dr6 = ptrace(PTRACE_PEEKUSER, pid, DR_OFFSET(6), &dr6);
return errno;
}
void run_tracee(char *tracee_path)
{
char *basec, *bname;
char *argv[2] = {};
if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0) {
perror("tracee, failed setting traceme\n");
exit(1);
}
if (kill(getpid(), SIGSTOP) != 0) {
perror("tracee, failed stopping tracee");
exit(1);
}
basec = strdup(tracee_path);
bname = basename(tracee_path);
argv[0] = bname;
argv[1] = NULL;
execv(tracee_path, argv);
}
/**
* hw_bp tracee 0x400526
*/
int main(int argc, char **argv)
{
pid_t tracee_pid;
siginfo_t siginfo;
int status, ret, brk_cnt = 0;
unsigned long addr = 0x400526;
long dr6;
if (argc < 3) {
fprintf(stderr, "tracer, no program specified!\n");
return 1;
}
addr = strtol(argv[2], NULL, 16); // addr is a hex string
printf("tracer, tracing program: %s\n", argv[1]);
tracee_pid = fork();
if (tracee_pid == 0) { // within tracee
run_tracee(argv[1]);
fprintf(stderr, "tracee, we shoudl never reach here!\n");
exit(1);
} else if (tracee_pid < 0) {
perror("tracer, failed forking tracee process\n");
exit(1);
}
// within tracer
ret = waitpid(tracee_pid, &status, 0);
if (ret == -1) {
perror("tracer, failed waiting tracee");
exit(1);
}
// kill tracee on exit
if (ptrace(PTRACE_SETOPTIONS, tracee_pid,
NULL, (void *) PTRACE_O_EXITKILL) != 0) {
perror("tracer, faile setting PTRACE_O_EXITKILL for tracee\n");
exit(1);
}
// // hwbp works only after execv is executed, otherwise
// // the debug registers will be rest after execv
// if (set_hwbp(tracee_pid, (void *) addr) != 0) {
// fprintf(stderr, "faield to set harware break point at 0x%lx\n", addr);
// }
if (ptrace(PTRACE_CONT, tracee_pid, NULL, NULL) != 0) {
perror("tracer, resume tracee\n");
exit(1);
}
ret = waitpid(tracee_pid, &status, 0);
if (ret == -1) {
perror("tracer, failed waiting tracee");
exit(1);
}
// ok, now we are safe to set hardware break point here
if (set_hwbp(tracee_pid, (void *) addr) != 0) {
fprintf(stderr, "faield to set harware break point at 0x%lx\n", addr);
}
while(1) {
if (ptrace(PTRACE_CONT, tracee_pid, NULL, NULL) != 0) {
perror("tracer, resume tracee\n");
exit(1);
}
printf("break count: %d\n", ++brk_cnt);
if (handle_break(tracee_pid) != 0) {
break;
}
printf("\n");
if (clear_dr6(tracee_pid) != 0) {
break;
}
if (ptrace(PTRACE_SINGLESTEP, tracee_pid, NULL, (void *) 0) != 0) {
perror("tracer, resume tracee\n");
exit(1);
}
if (handle_break(tracee_pid) != 0) {
break;
}
if (get_dr6(tracee_pid, &dr6) != 0) {
break;
}
printf("dr6: %lx\n", dr6);
printf("\n");
}
// printf("dr offset: %ld\n", (long) DR_OFFSET(0));
// printf("dr offset: %ld\n", (long) DR_OFFSET(1));
return 0;
}
You can’t perform that action at this time.