Использование ptrace для обратного чтения ls, похоже, не работает

Я следовал некоторым инструкциям по использованию ptrace, которые можно найти здесь. У меня Ubuntu 14.04, x64, и я изменяю фрагменты примера кода для работы с моей машиной x64, например, eax на rax и меняю 4s на 8s, где это уместно. В четвертом примере предполагается инвертировать вывод ls, но это не так. Я получаю это:

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

И я полагаю, что должен изменить его, если мой код работает правильно, примерно так:

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

Я обнаружил ошибку в коде, напечатанном на странице, на которую я ссылался выше (здесь), что на 20 строк ниже в моем коде, но я думаю, что исправил это. Это неправильная строка:

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

У него есть один аргумент, но нужно два. Я считаю, что это должно быть:

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

Но если я ошибаюсь, буду рад, если меня поправят. Я также пробовал:

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

Я до сих пор не уверен, что было бы правильно, если бы...

Это причина, почему он не работает? Или это что-то другое, может быть, другая проблема, связанная с x64, которую я не учел? Бонусные баллы для любого, кто может сказать мне, что делает calloc в этом случае и почему второй аргумент такой, какой он есть.

РЕДАКТИРОВАТЬ:

Я только что пробовал печатать str как до, так и после разворота... это просто куча вопросительных знаков. Когда я отлаживаю, кажется, что все содержимое str равно -1s. Это также говорит о том, что что-то не так с моим вызовом calloc()...

Во всяком случае, вот моя версия кода:

#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;
}

Будем очень благодарны любой помощи!


person Iron Attorney    schedule 02.11.2016    source источник
comment
Во всяком случае, str = calloc(params[2] + 1, sizeof (char));, но sizeof (char) всегда равно 1, поэтому вы можете встроить это.   -  person melpomene    schedule 02.11.2016
comment
Возможный дубликат ptrace с PTRACE_PEEKDATA в Ubuntu   -  person Mark Plotnick    schedule 03.11.2016
comment
@melpomene точно да! Это имело бы больше смысла. Я оставлю sizeof() там, возможно, с комментарием о встраивании значения в определенных обстоятельствах, так как это мой учебный файл.   -  person Iron Attorney    schedule 03.11.2016
comment
Однако это не устранило ошибку ... @MarkPlotnick, возможно, вы правы, это может быть дубликат этого. Я прочитал это и другой вопрос, связанный с ответом на этот вопрос, но мне все еще не совсем ясно. Говорят, что на x64 нужно заменить eax, ebx, ecx и edx на rdi, rsi, rdx, r10, r8 и r9?   -  person Iron Attorney    schedule 03.11.2016
comment
Да, в x86-32 параметры системных вызовов находятся в ebx, ecx, edx, esi, edi и ebp. В x86-64 они находятся в rdi, rsi, rdx, r10, r8 и r9.   -  person Mark Plotnick    schedule 03.11.2016
comment
Ах! В порядке. Так что, оставить RAX как есть?   -  person Iron Attorney    schedule 03.11.2016
comment
Кстати, это исправлено, большое спасибо вам обоим!   -  person Iron Attorney    schedule 03.11.2016
comment
Да, номер системного вызова находится в eax на x86-32, rax на x86-64.   -  person Mark Plotnick    schedule 03.11.2016


Ответы (1)


Так что спасибо @melpmene и @MarkPlotnick за ответы. Я изо всех сил пытался выяснить некоторые другие ответы, охватывающие ту же тему, и другой найденный мной ресурс, который предлагал, как преобразовать код x32 в код x64, был не совсем точным (по крайней мере, для моей системы), так что вот что я необходимо сделать:

1)

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

должно быть

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

2)

EBX, ECX и EDX следует заменить на RDI, RSI и RDX.

person Iron Attorney    schedule 03.11.2016