-
Notifications
You must be signed in to change notification settings - Fork 7
/
debugger.c
130 lines (108 loc) · 3.06 KB
/
debugger.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/user.h>
void run_child(const char* childProg);
void run_debugger(pid_t pid);
int main(int argc, char* argv[]) {
pid_t pid;
if (argc < 2) {
printf("Give at least one argument which is the program name\n");
return -1;
}
pid = fork();
if (pid == 0) {
// child process
run_child(argv[1]);
} else if (pid >= 1) {
// parent process
run_debugger(pid);
} else {
// error in forking
perror("Error in forking the child");
return -1;
}
return 0;
}
void run_child(const char* childProg) {
if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
perror("Error in ptrace\n");
return;
}
execl(childProg, childProg, NULL);
}
int count_instructions(pid_t pid) {
int wait_status;
unsigned counter = 0;
wait(&wait_status);
while(WIFSTOPPED(wait_status)) {
++counter;
if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0) < 0) {
perror("Error in ptrace\n");
return 0;
}
wait(&wait_status);
}
/* printf("The child executed with %d instructions\n", pid); */
return counter;
}
long set_breakpoint(pid_t pid, unsigned long int addr) {
long data = ptrace(PTRACE_PEEKTEXT, pid, (void *) addr, 0);
long old_data = data;
printf("Setting a breakpoint at %x\n", addr);
printf("Value at the address %x %x\n", addr, data);
data = (data & ~0xff) | 0xcc;
ptrace(PTRACE_POKETEXT, pid, (void *)addr, data);
printf("Value at the address %x after setting the int 3 opcode %x\n", addr, data);
printf("Done setting the breatpoint at %x\n\n", addr);
return old_data;
}
void set_rip(pid_t pid, unsigned long int addr) {
struct user_regs_struct regs;
printf("Setting the instruction pointer to address %x\n", addr);
memset(®s, 0, sizeof(regs));
ptrace(PTRACE_GETREGS, pid, NULL, ®s);
#ifdef __i386__
regs.eip = addr;
#else
regs.rip = addr;
#endif
ptrace(PTRACE_SETREGS, pid, NULL, ®s);
printf("Done setting the instruction pointer\n\n");
}
unsigned long int get_rip(pid_t pid) {
struct user_regs_struct regs;
ptrace(PTRACE_GETREGS, pid, NULL, ®s);
#ifdef __i386__
return regs.eip;
#else
return regs.rip;
#endif
}
void run_debugger(pid_t pid) {
int wait_status;
unsigned long int addr = 0x80483e9;
/* unsigned long int addr = 0x400534; */
/* Wait for the child to stop first */
wait(&wait_status);
/* Set breakpoint at the address - 80483e9 */
long old_data = set_breakpoint(pid, addr);
ptrace(PTRACE_CONT, pid, NULL, NULL);
wait(&wait_status);
printf("Hit a breakpoint\n");
/* Restore the code at the address - 80483e9 */
ptrace(PTRACE_POKETEXT, pid, (void *)addr, old_data);
printf("Restored the old value %x at the address %x\n", old_data, addr);
/* Set the correct address at the eip/rip to resume the execution */
/* after the breakpoint has been hit. */
set_rip(pid, addr);
ptrace(PTRACE_CONT, pid, NULL, NULL);
wait(&wait_status);
if (WIFEXITED(wait_status)) {
printf("Child process exited\n");
} else {
printf("Unexpected signal");
}
}