1

I am having trouble resetting a process after I have hit a breakpoint with Ptrace. I am essentially wrapping this code in python.
I am running this on 64 bit Ubuntu.

I understand the concept of resetting the data at the location and decrementing the instruction pointer, but after I get the trap signal and do that, my process is not finishing. Code snippet:

# Continue to bp
res = libc.ptrace(PTRACE_CONT,pid,0,0)
libc.wait(byref(wait_status))

if _wifstopped(wait_status):
    print('Breakpoint hit. Signal: %s' % (strsignal(_wstopsig(wait_status))))
else:
    print('Error process failed to stop')
    exit(1)

# Reset Instruction pointer
data = get_registers(pid)
print_rip(data)
data.rip -= 1
res = set_registers(pid,data)

# Verify rip
print_rip(get_registers(pid))
# Reset Instruction
out = set_text(pid,c_ulonglong(addr),c_ulonglong(initial_data))

if out != 0:
    print_errno()

print_text(c_ulonglong(addr),c_ulonglong(get_text(c_void_p(addr))))

And I run a PTRACE_DETACH right after returning from this code. When I run this, it hits the breakpoint the parent process returns successfully, but the child does not resume and finish its code. If I comment out the call to the breakpoint function it just attaches ptrace to the process and then detaches it, and the program runs fine.
The program itself is just a small c program that prints 10 times to a file.

Full code is in this paste

Is there an error anyone sees with my breakpoint code?

Chris
  • 4,425
  • 5
  • 34
  • 49

1 Answers1

2

I ended up writing a C program that was as exact a duplicate of the python code as possible:

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <syscall.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/reg.h>
#include <sys/user.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>

void set_unset_bp(pid){
        int wait_status;
        struct user_regs_struct regs;
        unsigned long long addr = 0x0000000000400710;
        unsigned long long data = ptrace(PTRACE_PEEKTEXT,pid,(void *)addr,0);
        printf("Orig data: 0x%016x\n",data);
        unsigned long long trap = (data & 0xFFFFFFFFFFFFFF00) | 0xCC;
        ptrace(PTRACE_POKETEXT,pid,(void *)addr,(void *)trap);
        ptrace(PTRACE_CONT,pid,0,0);    
        wait(&wait_status);
        if(WIFSTOPPED(wait_status)){
                printf("Signal recieved: %s\n",strsignal(WSTOPSIG(wait_status)));
        }else{
                perror("wait");
        }

        ptrace(PTRACE_POKETEXT,pid,(void *)addr,(void *)data);
        ptrace(PTRACE_GETREGS,pid,0,&regs);
        regs.rip -=1;
        ptrace(PTRACE_SETREGS,pid,0,&regs);
        data = ptrace(PTRACE_PEEKTEXT,pid,(void *)addr,0);
        printf("Data after resetting bp data: 0x%016x\n",data);
        ptrace(PTRACE_CONT,pid,0,0);
}

int main(void){
        //Fork child process
        extern int errno;
        int pid = fork();
        if(pid ==0){//Child
                ptrace(PTRACE_TRACEME,0,0,0);   
                int out = execl("/home/chris/workspace/eliben-debugger/print","/home/chris/workspace/eliben-debugger/print",0);
                if(out != 0){ 
                        printf("Error Value is: %s\n", strerror(errno));
                }
        }else{ //Parent

                wait(0);
                printf("Got stop signal, we just execv'd\n");
                set_unset_bp(pid);
                printf("Finished setting and unsetting\n");    
                wait(0);
                printf("Got signal, detaching\n");
                ptrace(PTRACE_DETACH,pid,0,0);
                wait(0);
                printf("Parent exiting after waiting for child to finish\n");
        }
        exit(0);    
}  

After comparing the output to my Python output I noticed that according to python my original data was 0xfffffffffffe4be8 and 0x00000000fffe4be8.
This lead me to believe that my return data was getting truncated to a 32 bit value.

I changed my get and set methods to something like this, setting the return type to a void pointer:

def get_text(addr):
    restype = libc.ptrace.restype
    libc.ptrace.restype = c_void_p
    out = libc.ptrace(PTRACE_PEEKTEXT,pid,addr, 0)
    libc.ptrace.restype = restype
    return out

def set_text(pid,addr,data):
    return libc.ptrace(PTRACE_POKETEXT,pid,addr,data)

Can't tell you how it works yet, but I was able to get the child process executing successfully after the trap.

Chris
  • 4,425
  • 5
  • 34
  • 49