0

I've been following some instructions on how to use ptrace that are found here. I am on ubuntu 14.04, x64, and I have been altering bits of the example code to work with my x64 machine, such as eax to rax, and changing 4s to 8s where appropriate. The forth example is supposed to reverse the output of ls, but it does not. I get this:

bin       Debugger.depend  dummy1.s       main_tut2.cpp  main_tut4.cpp  obj
Debugger.cbp  Debugger.layout  main_tut1.cpp  main_tut3.cpp  main_tut5.cpp
bin       Debugger.depend  dummy1.s       main_tut2.cpp  main_tut4.cpp  obj
Debugger.cbp  Debugger.layout  main_tut1.cpp  main_tut3.cpp  main_tut5.cpp

And I believe I should be getting it reversed if my code works correctly, something like this:

jbo ppc.4tut_niam ppc.2tut_niam s.1ymmud dneped.reggubeD nib
ppc.5tut_niam ppc.3tut_niam ppc.1tut_niam tuoyal.reggubeD pbc.reggubeD
jbo ppc.4tut_niam ppc.2tut_niam s.1ymmud dneped.reggubeD nib
ppc.5tut_niam ppc.3tut_niam ppc.1tut_niam tuoyal.reggubeD pbc.reggubeD

I have found an error in the code printed in the page I linked above (here) which is 20 lines up from the bottom in my code, but I think I have corrected that. This is the incorrect line:

                str = (char *)calloc((params[2] + 1) * sizeof(char));

It has one arguement but needs two. I believe it should be:

                str = (char *)calloc(params[2] + 1, (params[2] + 1) * sizeof(char));

But if I have that wrong, I would be happy to be corrected. I also tried:

                str = (char *)calloc(1, (params[2] + 1) * sizeof(char));

I'm still not sure which would be correct, if either...

Is this the reason why it's not working? Or is it something else, maybe another problem relating to being on x64 that I haven't accounted for? Bonus points for anyone who can tell me what calloc is doing in this instance and why the second arguement is as it is.

EDIT:

I have just tried printing str both before and after the reversal... it's just a bunch of question marks. When I debug, it seems the entire contents of str is -1s. This further suggests that something is wrong with my call to calloc()...

Anyway, here is my version of the code:

#include <iostream>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>         // For fork()
//#include <linux/user.h>   // For constants ORIG_EAX for 32bit etc
#include <sys/user.h>       // For constants ORIG_RAX for 64bit etc
#include <sys/reg.h>
#include <sys/syscall.h>    // For SYS_write etc
#include <cstring>          // For strlen()

/** ptrace(enum __ptrace_request,   // behaviour of ptrace
           pid_t pid,               // Process ID
           void *addr,              // Address to read in user area
           void *data);             //
**/

/**
PTRACE_TRACEME,   PTRACE_PEEKTEXT, PTRACE_PEEKDATA, PTRACE_PEEKUSER,   PTRACE_POKETEXT,
PTRACE_POKEDATA,  PTRACE_POKEUSER, PTRACE_GETREGS,  PTRACE_GETFPREGS,  PTRACE_SETREGS,
PTRACE_SETFPREGS, PTRACE_CONT,     PTRACE_SYSCALL,  PTRACE_SINGLESTEP, PTRACE_DETACH
**/

const int long_size = sizeof(long);

void reverse(char *str) {

    int i, j;
    char temp;

    for (i = 0, j = strlen(str) - 2; i <= j; i++, j--) {
        temp = str[i];
        str[i] = str[j];
        str[j] = temp;
    }
}

void getData(pid_t child, long addr, char *str, int len) {

    char *laddr;
    int i, j;
    union u {
        long val;
        char chars[long_size];
    } data;

    i = 0;
    j = len / long_size;
    laddr = str;

    while(i < j) {
        data.val = ptrace(PTRACE_PEEKDATA, child, addr + i * 8, NULL);
        memcpy(laddr, data.chars, long_size);
        i++;
        laddr += long_size;
    }

    j = len % long_size;

    if (j != 0) {
        data.val = ptrace(PTRACE_PEEKDATA, child, addr + i * 8, NULL);
        memcpy(laddr, data.chars, j);
    }

    str[len] = '\0';
}

void putData(pid_t child, long addr, char *str, int len) {

    char *laddr;
    int i, j;
    union u {
        long val;
        char chars[long_size];
    } data;

    i = 0;
    j = len / long_size;
    laddr = str;

    while(i < j) {
        memcpy(data.chars, laddr, long_size);
        ptrace(PTRACE_POKEDATA, child, addr + i * 8, data.val);
        i++;
        laddr += long_size;
    }

    j = len % long_size;

    if (j != 0) {
        memcpy(data.chars, laddr, j);
        ptrace(PTRACE_POKEDATA, child, addr + i * 8, data.val);
    }
}

int main()
{
    pid_t child;
    child = fork();

    if (child == 0) {

        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        execl("/bin/ls", "ls", NULL);

    } else {

        long orig_rax;
        long params[3];
        int status;
        char *str, *laddr;
        int toggle = 0;

        while(1) {

            wait(&status);
            if (WIFEXITED(status))
                break;

            orig_rax = ptrace(PTRACE_PEEKUSER, child, 8 * ORIG_RAX, NULL);

            if (orig_rax == SYS_write) {

                if (toggle == 0) {

                    toggle = 1;
                    params[0] = ptrace(PTRACE_PEEKUSER, child, 8 * RBX, NULL);
                    params[1] = ptrace(PTRACE_PEEKUSER, child, 8 * RCX, NULL);
                    params[2] = ptrace(PTRACE_PEEKUSER, child, 8 * RDX, NULL);
                    str = (char *)calloc(params[2] + 1, (params[2] + 1) * sizeof(char));

                    getData(child, params[1], str, params[2]);
                    reverse(str);
                    putData(child, params[1], str, params[2]);

                } else {

                    toggle = 0;
                }
            }

            ptrace(PTRACE_SYSCALL, child, NULL, NULL);
        }
    }

    execl("/bin/ls", "ls", NULL);

    return 0;
}

Any assistance would be greatly appreciated!

Iron Attorney
  • 1,003
  • 1
  • 9
  • 22
  • 1
    If anything, `str = calloc(params[2] + 1, sizeof (char));` but `sizeof (char)` is always 1 so you could inline that. – melpomene Nov 02 '16 at 19:49
  • 1
    Possible duplicate of [ptrace with PTRACE_PEEKDATA in Ubuntu](http://stackoverflow.com/questions/40355632/ptrace-with-ptrace-peekdata-in-ubuntu) – Mark Plotnick Nov 02 '16 at 21:51
  • @melpomene right yes! That would make more sense. I will leave the sizeof() there, maybe with a comment about inlining the value in certain circumstances, as this is my tutorial file. – Iron Attorney Nov 02 '16 at 23:14
  • However, it hasn't fixed the error... @MarkPlotnick you might be right, this may will be a duplicate of that. I have read through that, and the other question linked in that questions answer, but I'm still not entirely clear. Are they saying that on x64 you need to replace eax, ebx, ecx and edx with rdi, rsi, rdx, r10, r8 and r9? – Iron Attorney Nov 02 '16 at 23:16
  • 1
    Yes, in x86-32, system call params are in ebx, ecx, edx, esi, edi, and ebp. In x86-64, they're in rdi, rsi, rdx, r10, r8 and r9. – Mark Plotnick Nov 02 '16 at 23:37
  • Ah! Ok. So do I leave RAX as is? – Iron Attorney Nov 02 '16 at 23:53
  • That's fixed it btw, thanks alot both of you! – Iron Attorney Nov 02 '16 at 23:55
  • 1
    Yes, system call number is in eax on x86-32, rax on x86-64. – Mark Plotnick Nov 03 '16 at 01:31

1 Answers1

0

So thanks to @melpmene and @MarkPlotnick for the answers. I have struggled to figure out some of the other answers covering the same topic, and another resource I found that suggested how to convert the x32 code to x64 code wasn't entirely accurate (at least for my system), so here is what I needed to do:

1)

str = (char *)calloc(params[2] + 1 * sizeof (char))

should be

str = (char *)calloc(params[2] + 1, sizeof (char))

2)

EBX, ECX and EDX should be replaced by RDI, RSI and RDX

Iron Attorney
  • 1,003
  • 1
  • 9
  • 22