Модераторы: xvr
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> ptrace 
:(
    Опции темы
MAKCim
Дата 3.2.2008, 11:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



есть код
Код

#include <sys/ptrace.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>

static unsigned char shellcode[32] = {
    0x31, 0xFF, 0xB8, 0x0C, 0x00, 0x00, 0x00, 0x0F, 0x05, 0x48, 0x8D,
    0xB8, 0x00, 0x10, 0x00, 0x00, 0xB8, 0x0C, 0x00, 0x00, 0x00, 0x0F,
    0x05, 0x48, 0x2D, 0x00, 0x10, 0x00, 0x00, 0xCC, 0x90, 0x90
};

int main(int argc, char * argv[]) {
    struct user_regs_struct regs;
    pid_t pid = (pid_t)atoi(argv[1]);
    if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0)
        return 1;
    if (wait(NULL) < 0)
        return 2;
    if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
        return 3;
    unsigned long * ptr = (unsigned long*)shellcode;
    unsigned long rip = regs.rip & ~4095;
    unsigned long address = regs.rip;
    long word;
    do {
        errno = 0;
        if ((word = ptrace(PTRACE_PEEKTEXT, pid, (void*)rip, NULL)) < 0 && errno)
            return 4;
        if (ptrace(PTRACE_POKETEXT, pid, (void*)rip, *ptr) < 0)
            return 5;
        *ptr = (unsigned long)word;
        rip += 8;
        ++ptr;
    } while (!(rip & 0x20));
    rip -= 32;
    regs.rip = rip;
    ptr -= 8;
    if (ptrace(PTRACE_SETREGS, pid, NULL, &regs) < 0)
        return 6;
    if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0)
        return 7;
    if (wait(NULL) < 0)
        return 8;
    for (; !(rip & 0x20) && ((word = ptrace(PTRACE_POKETEXT, pid, (void*)rip, *ptr)) >= 0 || !errno); rip += 8, ++ptr);
    if (errno)
        return 9;
    regs.rip = address;
    if (ptrace(PTRACE_SETREGS, pid, NULL, &regs) < 0)
        return 10;
    return 0;
}


shellcode соответствует следующему коду
Код

xor    edi, edi
mov    eax, 12
syscall
lea    rdi, qword [rax + 4096]
mov    eax, 12
syscall
sub    rax, 4096
int3
nop
nop

смысл программы заключается во внедрении шеллкода увеличения brk процесса pid
вот тестовая программа
Код

int main() {
    int count;
    for (count = 1; ;)
        while (count++); 
    return 0;
}

все отрабатывает отлично
если изменить программу таким образом
Код

int main() {
    for (;;) {
        sleep(10);
    }
    return 0;
}

brk не меняется, в этом случае даже если изменить шеллкод на
Код

static unsigned char shellcode[32] = {
    0x31, 0xFF, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0x0F, 0x05, 0x48, 0x8D,
    0xB8, 0x00, 0x10, 0x00, 0x00, 0xB8, 0x0C, 0x00, 0x00, 0x00, 0x0F,
    0x05, 0x48, 0x2D, 0x00, 0x10, 0x00, 0x00, 0xCC, 0x90, 0x90
};


что соответствует
Код

xor    edi, edi
mov    eax, 60 ; sys_exit()
syscall
lea    rdi, qword [rax + 4096]
mov    eax, 12
syscall
sub    rax, 4096
int3
nop
nop

то процесс не завершается
в чем может быть причина?


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
MAKCim
Дата 4.2.2008, 09:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



никто не в курсе?


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
JackYF
Дата 4.2.2008, 13:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


полуавантюрист
****


Профиль
Группа: Участник
Сообщений: 5814
Регистрация: 28.8.2004
Где: страна тысячи озё р

Репутация: 3
Всего: 162



ну мне просто знаний не хватает, хотя я честно прочитал весь пост smile


--------------------
Пожаловаться на меня как модератора можно здесь.
PM MAIL Jabber   Вверх
MAKCim
Дата 4.2.2008, 14:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



ошибка еще больше локализована
если убрать выравнивание по размеру страницы
Код

unsigned long rip = regs.rip /* & ~4095 */;

в обоих случаях все работает
 smile 


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
xvr
Дата 4.2.2008, 18:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 20
Всего: 223



Цитата(MAKCim @ 4.2.2008,  14:15)
ошибка еще больше локализована
если убрать выравнивание по размеру страницы
Код

unsigned long rip = regs.rip /* & ~4095 */;

в обоих случаях все работает
 smile

Посмотри куда смотрит rip при записи, судя по всему это должно быть где то в libc, мог затереть что-то жизненно важное  smile 
PM MAIL   Вверх
MAKCim
Дата 4.2.2008, 18:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



Цитата(xvr @  4.2.2008,  18:28 Найти цитируемый пост)
Посмотри куда смотрит rip при записи, судя по всему это должно быть где то в libc, мог затереть что-то жизненно важное 

RIP действительно содержит адрес инструкции в libc
как с выравниванием, так и без
но проблема не в этом
смысл программы заключается в инжектировании достаточно большого фрагмента кода в активный процесс
для этого сначала внедряется небольшой шеллкод, который должен увеличить brk процесса
после этого по адресу, который соответствует старому значению brk, внедряется основной код
естественно, при инжектировании шеллкода затирается часть кода libc
но после его отработки, содержимое восстанавливается
в процессе работы шеллкода нет никаких обращений к каким-либо функциям libc, которые могли бы использовать часть затертого кода, идет прямой вызов sys_brk() посредством syscall
в любом случае, если бы проблема была в этом, программа не работала бы совсем


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
xvr
Дата 4.2.2008, 19:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 20
Всего: 223



Цитата(MAKCim @ 4.2.2008,  18:51)
Цитата(xvr @  4.2.2008,  18:28 Найти цитируемый пост)
Посмотри куда смотрит rip при записи, судя по всему это должно быть где то в libc, мог затереть что-то жизненно важное 

RIP действительно содержит адрес инструкции в libc
как с выравниванием, так и без
но проблема не в этом
смысл программы заключается в инжектировании достаточно большого фрагмента кода в активный процесс
для этого сначала внедряется небольшой шеллкод, который должен увеличить brk процесса
после этого по адресу, который соответствует старому значению brk, внедряется основной код
естественно, при инжектировании шеллкода затирается часть кода libc
но после его отработки, содержимое восстанавливается
в процессе работы шеллкода нет никаких обращений к каким-либо функциям libc, которые могли бы использовать часть затертого кода, идет прямой вызов sys_brk() посредством syscall
в любом случае, если бы проблема была в этом, программа не работала бы совсем

В 2х вариантах есть разница в том КАКИЕ функции в libc временно затираются. Возможно это и не имеет значения, но все может быть.
Возможно какая то интерференция возврата из syscall'а (sleep в данном случае) и изменении регистра rip через ptrace. Можно попробовать сделать пару PTRACE_SINGLESTEP перед инжектированием кода и сменой rip.
А может проще инжектировать кусок кода в стек?


PM MAIL   Вверх
MAKCim
Дата 4.2.2008, 19:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



Цитата(xvr @  4.2.2008,  19:19 Найти цитируемый пост)
Возможно какая то интерференция возврата из syscall'а (sleep в данном случае) и изменении регистра rip через ptrace

нет
возврат из sleep() идет по новому RIP
я смотрел реализацию sys_ptrace(), при установке нового значения RIP, изменяется старое значение RIP в стеке (которое было сохранено после syscall для sleep())
Цитата(xvr @  4.2.2008,  19:19 Найти цитируемый пост)
А может проще инжектировать кусок кода в стек?

нет
механизм EDB (Execute Disable Bit) не позволит



--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
xvr
Дата 4.2.2008, 22:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 20
Всего: 223



Цитата(MAKCim @ 4.2.2008,  19:49)
Цитата(xvr @  4.2.2008,  19:19 Найти цитируемый пост)
Возможно какая то интерференция возврата из syscall'а (sleep в данном случае) и изменении регистра rip через ptrace

нет
возврат из sleep() идет по новому RIP
я смотрел реализацию sys_ptrace(), при установке нового значения RIP, изменяется старое значение RIP в стеке (которое было сохранено после syscall для sleep())

Но чудес не бывает - что то мешает коду исполнится  smile 

Цитата

Цитата(xvr @  4.2.2008,  19:19 Найти цитируемый пост)
А может проще инжектировать кусок кода в стек?

нет
механизм EDB (Execute Disable Bit) не позволит
А может тогда найти кусок исполняемого адресного пр-ва вне libc (через /proc/xxx/maps) и инжектировать туда?

PM MAIL   Вверх
MAKCim
Дата 4.2.2008, 23:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



Цитата(xvr @  4.2.2008,  22:02 Найти цитируемый пост)
Но чудес не бывает - что то мешает коду исполнится

вот и я думаю, что не бывает  smile 
Цитата(xvr @  4.2.2008,  22:02 Найти цитируемый пост)
А может тогда найти кусок исполняемого адресного пр-ва вне libc (через /proc/xxx/maps) и инжектировать туда?

решение вспомогательной задачи окажется больше решения основной  smile
хотелось бы разобраться в чем проблема


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
xvr
Дата 4.2.2008, 23:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 20
Всего: 223



Цитата(MAKCim @ 4.2.2008,  23:03)
Цитата(xvr @  4.2.2008,  22:02 Найти цитируемый пост)
Но чудес не бывает - что то мешает коду исполнится

вот и я думаю, что не бывает  smile 
Цитата(xvr @  4.2.2008,  22:02 Найти цитируемый пост)
А может тогда найти кусок исполняемого адресного пр-ва вне libc (через /proc/xxx/maps) и инжектировать туда?

решение вспомогательной задачи окажется больше решения основной  smile
хотелось бы разобраться в чем проблема

Не совсем понятно как разбираться (точнее совсем не понятно)  smile Можно попытаться проверить исполнение собственно вызовов ptrace - записи кода и установки rip соотвественно чтением кода и регистров. Можно протереть int3 все вокруг точки возврата и посмотреть куда он реально попадает.  smile Пока больше идей нет  smile 
PM MAIL   Вверх
MAKCim
Дата 5.2.2008, 00:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



Цитата(xvr @  4.2.2008,  23:23 Найти цитируемый пост)
записи кода и установки rip соотвественно чтением кода и регистров

проверял, все нормально

так, сейчас изменил программу следующим образом
Код

int main(int argc, char * argv[]) {
    struct user_regs_struct regs;
    pid_t pid = (pid_t)atoi(argv[1]);
    if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0)
        return 1;
    if (wait(NULL) < 0)
        return 2;
    if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
        return 3;
    unsigned long * ptr = (unsigned long*)shellcode;
    unsigned long rip = regs.rip & ~4095;
    printf("%p\n", (void*)rip);
    unsigned long address = regs.rip;
    long word;
    do {
        errno = 0;
        if ((word = ptrace(PTRACE_PEEKTEXT, pid, rip, NULL)) < 0 && errno)
            return 4;
        if (ptrace(PTRACE_POKETEXT, pid, rip, *ptr) < 0)
            return 5;
        *ptr = (unsigned long)word;
        rip += 8;
        ++ptr;
    } while (!(rip & 0x20));
    rip -= 32;
    regs.rip = rip;
    ptr -= 8;
    if (ptrace(PTRACE_SETREGS, pid, NULL, &regs) < 0)
        return 6;
    if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0)
        return 7;
    if (wait(NULL) < 0)
        return 8;
    struct user_regs_struct r;
    ptrace(PTRACE_GETREGS, pid, NULL, &r);
    printf("%p\n", (void*)r.rip);
    for (; !(rip & 0x20) && ((word = ptrace(PTRACE_POKETEXT, pid, rip, *ptr)) >= 0 || !errno); rip += 8, ++ptr);
    if (errno)
        return 9;
    regs.rip = address;
    if (ptrace(PTRACE_SETREGS, pid, NULL, &regs) < 0)
        return 10;
    if (ptrace(PTRACE_DETACH, pid, NULL, NULL))
        return 11;
    return 0;
}

т. е после записи шеллкода и установки нового RIP, вызывается ptrace() с PTRACE_SINGLESTEP
дальше выполняется (якобы) одна инструкция
после этого идет чтение RIP и...он становится на 2 меньше исходного
т. е если, допустим до PTRACE_SINGLESTEP выровненный RIP был равен  0x2b4ea0ed6000
то после PTRACE_SINGLESTEP он становится равным  0x2b4ea0ed5ffe
я в шоке  smile 

кстати, проверял также через GDB, результат тот же
так что дело не в моей программе
может баг?  smile 


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
xvr
Дата 5.2.2008, 09:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 20
Всего: 223



Цитата(MAKCim @ 5.2.2008,  00:47)
Цитата(xvr @  4.2.2008,  23:23 Найти цитируемый пост)
записи кода и установки rip соотвественно чтением кода и регистров

проверял, все нормально

так, сейчас изменил программу следующим образом
Код

int main(int argc, char * argv[]) {
    struct user_regs_struct regs;
    pid_t pid = (pid_t)atoi(argv[1]);
    if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0)
        return 1;
    if (wait(NULL) < 0)
        return 2;
    if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
        return 3;
    unsigned long * ptr = (unsigned long*)shellcode;
    unsigned long rip = regs.rip & ~4095;
    printf("%p\n", (void*)rip);
    unsigned long address = regs.rip;
    long word;
    do {
        errno = 0;
        if ((word = ptrace(PTRACE_PEEKTEXT, pid, rip, NULL)) < 0 && errno)
            return 4;
        if (ptrace(PTRACE_POKETEXT, pid, rip, *ptr) < 0)
            return 5;
        *ptr = (unsigned long)word;
        rip += 8;
        ++ptr;
    } while (!(rip & 0x20));
    rip -= 32;
    regs.rip = rip;
    ptr -= 8;
    if (ptrace(PTRACE_SETREGS, pid, NULL, &regs) < 0)
        return 6;
    if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0)
        return 7;
    if (wait(NULL) < 0)
        return 8;
    struct user_regs_struct r;
    ptrace(PTRACE_GETREGS, pid, NULL, &r);
    printf("%p\n", (void*)r.rip);
    for (; !(rip & 0x20) && ((word = ptrace(PTRACE_POKETEXT, pid, rip, *ptr)) >= 0 || !errno); rip += 8, ++ptr);
    if (errno)
        return 9;
    regs.rip = address;
    if (ptrace(PTRACE_SETREGS, pid, NULL, &regs) < 0)
        return 10;
    if (ptrace(PTRACE_DETACH, pid, NULL, NULL))
        return 11;
    return 0;
}

т. е после записи шеллкода и установки нового RIP, вызывается ptrace() с PTRACE_SINGLESTEP
дальше выполняется (якобы) одна инструкция
после этого идет чтение RIP и...он становится на 2 меньше исходного
т. е если, допустим до PTRACE_SINGLESTEP выровненный RIP был равен  0x2b4ea0ed6000
то после PTRACE_SINGLESTEP он становится равным  0x2b4ea0ed5ffe
я в шоке  smile 

кстати, проверял также через GDB, результат тот же
так что дело не в моей программе
может баг?  smile

Мда, может и баг  smile 
А может стоит добавить в shellcode штук 16 NOP'ов в начало и устанавливать rip куда-нибудь в их середину, и пусть он пляшет насколько захочет  smile 
PM MAIL   Вверх
MAKCim
Дата 5.2.2008, 12:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



Цитата(xvr @  5.2.2008,  09:02 Найти цитируемый пост)
А может стоит добавить в shellcode штук 16 NOP'ов в начало и устанавливать rip куда-нибудь в их середину, и пусть он пляшет насколько захочет

переставил 2 NOP-а с конца вперед
помогло (но RIP все равно ушел на 2 байта назад)
однако поведение непонятно
если адрес не выравнивать, то RIP не декрементируется
 smile 


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Программирование под Unix/Linux"
xvr
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой "Код".
  • Вопросы мобильной разработки тут
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr.

 
 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема »


 




[ Время генерации скрипта: 0.1350 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.