LINUX.ORG.RU

ptrace


0

0

есть код

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, rip, NULL) && errno) < 0)
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_CONT, pid, NULL, NULL) < 0)
return 7;
if (wait(NULL) < 0)
return 8;
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;
return 0;
}

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

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

в чем причина?


аналогично, по всей очевидности находясь в vdso вы уверены, что а) тупая запись по текущему eip - это правильно? б) выравнивание eip на страницу - это правильно?

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от rei3er

>> regs.eax = -1;
> в каком месте?

думай

hint: бывает, что системные вызовы рестартуются ядром после получения сигнала.

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

> по всей очевидности находясь в vdso
с чего вы взяли?
> а) тупая запись по текущему eip - это правильно?
правильно
> б) выравнивание eip на страницу - это правильно?
правильно
shellcode - 32 байта
если к rip прибавить 32, то может быть выход за пределы виртуальной страницы, которая к тому же может не отображаться на физическую страницу
поэтому идет выравнивание
т. к наименьший возможный размер страницы, описываемой PTE равен 4096, то выравнивание безопасно

rei3er
() автор топика
Ответ на: комментарий от klalafuda

> hint: бывает, что системные вызовы рестартуются ядром после получения > сигнала.
это поведение задается явно через SA_RESTART

rei3er
() автор топика
Ответ на: комментарий от rei3er

>> по всей очевидности находясь в vdso
> с чего вы взяли?

тогда наводящий вопрос: в каком состоянии находится целевой процесс после выполнения последовательности ptrace(ATTACH, pid)->wait(pid)?

ps: IMHO чтобы он не находился в vdso нужно явным образом постараться. например, вызвать системный вызов руками через int80/syscall/etc, что явно не есть штатное поведение подавляющего большинства приложений.

> если к rip прибавить 32, то может быть выход за пределы виртуальной страницы, которая к тому же может не отображаться на физическую страницу
поэтому идет выравнивание т. к наименьший возможный размер страницы, описываемой PTE равен 4096, то выравнивание безопасно.

хорошо, допустим. хотя в случае, если целевой процесс многопоточный, столь брутальное изменение текущего eip может принести массу сюрпризов.

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от rei3er

>> hint: бывает, что системные вызовы рестартуются ядром после получения >> сигнала.
> это поведение задается явно через SA_RESTART

http://www.usenix.org/events/expcs07/papers/22-spillane.pdf

там показано, где, как и почему нужно сбрасывать номер системного вызова и ещё много чего интересного.

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

> если целевой процесс многопоточный
да, будут проблемы
это понятно
сейчас же программа для тестирования не многопоточная

int main() {
int i;
while (1) {
int i = 1;
while (i++);
}
}

> в каком состоянии находится целевой процесс после выполнения
> последовательности ptrace(ATTACH, pid)->wait(pid)?
в TASK_STOPPED

> IMHO чтобы он не находился в vdso нужно явным образом постараться
вышеприведенная программа не использует никаких библиотечных функций и системных вызовов

rei3er
() автор топика
Ответ на: комментарий от klalafuda

> там показано, где, как и почему нужно сбрасывать номер системного
> вызова и ещё много чего интересного.
то, для чего его сбрасывали в -1 там, не имеет ничего общего с тем, чего добиваюсь я
за статью спасибо

rei3er
() автор топика
Ответ на: комментарий от klalafuda


почему на простое сообщение вида
"-if (ptrace(PTRACE_POKETEXT, pid, rip, ptr) +if (ptrace(PTRACE_POKETEXT, pid, rip, ptr)" форум выдает "ошибка добавления?" :-?

поубивав бы всех программистов как класс :-/

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от rei3er

>> заменить if
> не помогает

ну значит бага есть ещё где-то :) хорошо. тогда поменять код на что-то более ощущабельное, a'la write(2, "Hello world!\n").

ps: а что собственно хочется то? запустить именно brk() или просто посмотреть, что какой то код запускается?

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

> а что собственно хочется то? запустить именно brk() или просто
> посмотреть, что какой то код запускается?
да, именно brk() (ну или mmap()) для выделения памяти в отладочном процессе и последующего инжекта в эту область основного кода
вместо brk() пробовал exit()... реакции нет никакой
ощущение, что код не выполняется

rei3er
() автор топика
Ответ на: комментарий от klalafuda

> например, вызвать системный вызов руками через int80/syscall/etc

ptrace() только это и делает, ничего более, так что результат будет тот же.

Agent666
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.