1

I'm trying to read the register values of a running process. This is the code of the process I'm trying to trace:

#include <stdio.h>

int x=0;

int main(){
    while(1){
        x++;
        printf("%d\n",x);
    }
    return 0;
}

and this is the ptrace program that I'm using to do it:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/wait.h>

void dumpRegs(int pid){
    printf("------------------------\n");
    struct user_regs_struct regs;
    ptrace(PTRACE_GETREGS,pid,NULL, &regs);
    printf("rbx: %lx.\n", regs.rbx);
    printf("r15: %lx.\n",regs.r15);
    printf("r14: %lx.\n",regs.r14);
    printf("r13: %lx.\n",regs.r13);
    printf("r12: %lx.\n",regs.r12);
    printf("rbp: %lx.\n",regs.rbp);
    printf("rbx: %lx.\n",regs.rbx);
    printf("r11: %lx.\n",regs.r11);
    printf("r10: %lx.\n",regs.r10);
    printf("r9: %lx.\n",regs.r9);
    printf("r8: %lx.\n",regs.r8);
    printf("rax: %lx.\n",regs.rax);
    printf("rcx: %lx.\n",regs.rcx);
    printf("rdx: %lx.\n",regs.rdx);
    printf("rsi: %lx.\n",regs.rsi);
    printf("rdi: %lx.\n",regs.rdi);
    printf("orig_rax: %lx.\n",regs.orig_rax);
    printf("rip: %lx.\n",regs.rip);
    printf("cs: %lx.\n",regs.cs);
    printf("eflags: %lx.\n",regs.eflags);
    printf("rsp: %lx.\n",regs.rsp);
    printf("ss: %lx.\n",regs.ss);
    printf("fs_base: %lx.\n",regs.fs_base);
    printf("gs_base: %lx.\n",regs.gs_base);
    printf("ds: %lx.\n",regs.ds);
    printf("es: %lx.\n",regs.es);
    printf("fs: %lx.\n",regs.fs);
    printf("gs: %lx.\n",regs.gs);
}

int main(int argc, char **argv){
    printf("begin\n");
    int pid=atoi(argv[1]);//the pid of the process
    int status;
    ptrace(PTRACE_ATTACH,pid);//attach to process
    waitpid(pid,&status,0);

    do{
        ptrace(PTRACE_SINGLESTEP,pid);
        dumpRegs(pid);
    }while(getchar()!='q');

    ptrace(PTRACE_DETACH,pid);//attach to process
    printf("end\n");

    return 0;
}

The code attaches to the process just fine, I can tell because it stops printing the value of x, and I can also see it in top and htop, but no matter how many iterations of the do...while loop it goes through, the output of dumpRegs stays the same. I would think that at least some of the registers would change their values even in such a simple process, so I think I must be doing something wrong. I've posted a sample of the output I'm getting below.

output:

rbx: 9.
r15: 9.
r14: 7ff23e124600.
r13: 1.
r12: 9.
rbp: 559d2ee03010.
rbx: 9.
r11: 246.
r10: 64.
r9: 8.
r8: 1.
rax: fffffffffffffe00.
rcx: 7ff23de65730.
rdx: 9.
rsi: 559d2ee03010.
rdi: 1.
orig_rax: 1.
rip: 7ff23de65730.
cs: 33.
eflags: 246.
rsp: 7ffcee0ce6f8.
ss: 2b.
fs_base: 7ff23e318700.
gs_base: 0.
ds: 0.
es: 0.
fs: 0.
gs: 0.

I'm running this on 64 bit Debian and compiling with gcc.

Sam
  • 21
  • 2
  • 1
    You don't seem to be tracking whether the system calls are successful. You should be doing that extensively to make sure that you are succeeding in making the calls. Beyond that, I don't think I can help, though. – Jonathan Leffler Jul 28 '18 at 22:34
  • Thank you! Apparently the PTRACE_SINGLESTEP request is returning an error value, (-1) so I'll have to look into what could make it fail. – Sam Jul 28 '18 at 22:42
  • Do you need to send a SIGCONT signal to the child so that it continues after it is stopped? I'm not sure which side of the PTRACE_SINGLESTEP that would be. At least you've got something to look into, anyway. Good luck! – Jonathan Leffler Jul 28 '18 at 22:46
  • Thanks for your help! I've solved my issue and posted the answer below. – Sam Jul 28 '18 at 23:08

1 Answers1

1

I was calling ptrace like this:

ptrace(PTRACE_SINGLESTEP,pid);

But it needs to be called like this:

ptrace(PTRACE_SINGLESTEP,pid,NULL,NULL);

If you don't include the NULL arguments, PTRACE_SINGLESTEP will return a -1. I also added a PTRACE_CONT before detaching.

Here is the updated code:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/wait.h>

int x=0;

void dumpRegs(int pid){
    printf("------------------------\n");
    printf("%d\n",x);
    struct user_regs_struct regs;
    ptrace(PTRACE_GETREGS,pid,NULL, &regs);
    printf("cs: %lx.\n",regs.cs);
    printf("ds: %lx.\n",regs.ds);
    printf("eflags: %lx.\n",regs.eflags);
    printf("es: %lx.\n",regs.es);
    printf("fs: %lx.\n",regs.fs);
    printf("fs_base: %lx.\n",regs.fs_base);
    printf("gs: %lx.\n",regs.gs);
    printf("gs_base: %lx.\n",regs.gs_base);
    printf("orig_rax: %lx.\n",regs.orig_rax);
    printf("r10: %lx.\n",regs.r10);
    printf("r11: %lx.\n",regs.r11);
    printf("r12: %lx.\n",regs.r12);
    printf("r13: %lx.\n",regs.r13);
    printf("r14: %lx.\n",regs.r14);
    printf("r15: %lx.\n",regs.r15);
    printf("r8: %lx.\n",regs.r8);
    printf("r9: %lx.\n",regs.r9);
    printf("rax: %lx.\n",regs.rax);
    printf("rbp: %lx.\n",regs.rbp);
    printf("rbx: %lx.\n", regs.rbx);
    printf("rbx: %lx.\n",regs.rbx);
    printf("rcx: %lx.\n",regs.rcx);
    printf("rdi: %lx.\n",regs.rdi);
    printf("rdx: %lx.\n",regs.rdx);
    printf("rip: %lx.\n",regs.rip);
    printf("rsi: %lx.\n",regs.rsi);
    printf("rsp: %lx.\n",regs.rsp);
    printf("ss: %lx.\n",regs.ss);
}

int main(int argc, char **argv){
    printf("begin\n");
    int pid=atoi(argv[1]);//the pid of the process
    int status;
    ptrace(PTRACE_ATTACH,pid);//attach to process
    waitpid(pid,&status,0);

    do{
        x++;
        printf("%d",ptrace(PTRACE_SINGLESTEP,pid,NULL,NULL));
        dumpRegs(pid);
    }while(getchar()!='q');

    printf("%d",ptrace(PTRACE_CONT,pid,NULL,NULL));
    ptrace(PTRACE_DETACH,pid);//attach to process
    printf("end\n");

    return 0;
}
Sam
  • 21
  • 2
  • You might find [this](https://stackoverflow.com/a/18603766/1475978) interesting. It is about ptracing a multithreaded process, and includes an example program. – Nominal Animal Jul 29 '18 at 06:03