I am trying to learn how breakpoints software works with pctrace (inserting INT3) in the code.
For this I have followed a series of examples from different sites to create a simple disassembler, and I have been doing a kind of merge with them according to what interested me.
The main code is here: https://eli.thegreenplace.net/2011/01/27/how-debuggers-work-part-2-breakpoints/
The code requires that you pass the address where you want to insert the breakpoint manually.
I am using the example: http://www.alexonlinux.com/wp-content/uploads/2008/03/sleeper.c
Then, using objdump -d, I get the address between the two prints and pass it to the disassembler.
The result I get is this:
debugger started
In debugger process 15819
In debuggie process 15820
Child started. EIP = 0xb7f41000
Original data at 0x08048429: 0xffffffff
After trap, data at 0x08048429: 0xffffffff
Time before debugger falling asleep: 1593599313
As seen, Original and After data are the same but this is wrong, After trap should be 0xffffffcc.
The prints are not printed either:
printf ("~~~~~~~~~~~~> Before breakpoint \ n");
// The breakpoint
printf ("~~~~~~~~~~~~> After breakpoint \ n")
I cannot understand why it is not replacing well, the insertion I am doing:
/ * Write the trap instruction 'int 3' into the address * /
unsigned data_with_trap = (data & 0xFFFFFF00) | 0xCC;
ptrace (PTRACE_POKETEXT, child_pid, (void *) addr, (void *) data_with_trap);
// Finish Placing breakpoint ...
Does anyone see any problem whit this code?
Part of the whole code:
void run_debugger(pid_t child_pid)
{
int wait_status;
struct user_regs_struct regs;
printf("debugger started\n");
printf( "In debugger process %ld\n", (long)getpid() );
wait(&wait_status);
ptrace(PTRACE_GETREGS, child_pid, 0, ®s);
printf("Child started. EIP = 0x%08x\n", regs.eip);
// Placing breakpoint...
unsigned addr = 0x8048429;
unsigned data = ptrace(PTRACE_PEEKTEXT, child_pid, (void*)addr, 0);
printf("Original data at 0x%08x: 0x%08x\n", addr, data);
/* Write the trap instruction 'int 3' into the address */
unsigned data_with_trap = (data & 0xFFFFFF00) | 0xCC;
ptrace(PTRACE_POKETEXT, child_pid, (void*)addr, (void*)data_with_trap);
// Finish Placing breakpoint...
unsigned readback_data = ptrace(PTRACE_PEEKTEXT, child_pid, (void*)addr, 0);
printf("After trap, data at 0x%08x: 0x%08x\n", addr, readback_data);
printf( "Time before debugger falling asleep: %ld\n", (long)time( NULL ) );
sleep( 5 );
printf( "Time after debugger falling asleep: %ld. Resuming debuggie...\n", (long)time( NULL ) );
ptrace(PTRACE_CONT, child_pid, 0, 0);
wait(&wait_status);
if (WIFSTOPPED(wait_status)) {
printf("Child got a signal: %s\n", strsignal(WSTOPSIG(wait_status)));
}
else {
perror("wait");
return;
}
ptrace(PTRACE_GETREGS, child_pid, 0, ®s);
printf("Child stopped at EIP = 0x%08x\n", regs.eip);
/* Remove the breakpoint by restoring the previous data
** at the target address, and unwind the EIP back by 1 to
** let the CPU execute the original instruction that was
** there.
*/
ptrace(PTRACE_POKETEXT, child_pid, (void*)addr, (void*)data);
regs.eip -= 1;
ptrace(PTRACE_SETREGS, child_pid, 0, ®s);
/* The child can continue running now */
ptrace(PTRACE_CONT, child_pid, 0, 0);
wait(&wait_status);
if (WIFEXITED(wait_status)) {
printf("Child exited\n");
}
else {
printf("Unexpected signal\n");
}
}
void do_debuggie( void )
{
char* argv[] = { NULL };
char* envp[] = { NULL };
printf( "In debuggie process %ld\n", (long)getpid() );
if (ptrace( PTRACE_TRACEME, 0, NULL, NULL ))
{
perror( "ptrace" );
return;
}
execve( "sleeper", argv, envp );
}
int main(int argc, char** argv)
{
pid_t child_pid;
if (argc < 2) {
fprintf(stderr, "Expected a program name as argument\n");
return -1;
}
child_pid = fork();
if (child_pid == 0)
do_debuggie();
// argv[1];
else if (child_pid > 0)
run_debugger(child_pid);
else {
perror("fork");
return -1;
}
return 0;
}
Thank you!
User contributions licensed under CC BY-SA 3.0