Копирование строки в стек в gdb

#c #pointers #gdb

#c #указатели #gdb

Вопрос:

Почему

Я хочу использовать gdb как способ перехвата open системного вызова и заставить приложение получить дескриптор другого файла, чем он запрашивал. Что-то вроде:

 replace-file filea=fileb cat filea
# prints out contents of fileb
 

Я могу перехватить open системный вызов, но мне нужно указать новое имя файла, которое должно быть строкой, находящейся в памяти подчиненного устройства.
Я хотел избежать использования malloc для этого, потому что тогда я зависел от того, что библиотека доступна в нижней части, и вместо этого сохранял ее в стеке («после» части, используемой процессом), поскольку она нужна мне только для следующей кодовой строки, и у меня нет проблем с ее последующей перезаписью.

Что

Однако мне трудно писать в стек.
Я знаю, что стек растет вниз, поэтому я пытаюсь уменьшить указатель стека на размер моей строки, скопировать строку в указатель, а затем увеличить указатель стека обратно. У меня возникли проблемы с копированием строки в местоположение, на которое указывает указатель стека.

Что у меня есть до сих пор:

 # script.gdb
handle all pass    handle al pass
set print thread-events off

set $file_a = "/etc/fstab"
set $file_b = "/etc/passwd"
set $len = $_strlen($file_b)
set $len = $len   1

catch syscall open
commands
  silent
  # $rax == return value
  # IF x64, $rdi == filename
  set $outside = ! $outside
  if ( $_streq((char *)$rdi, $file_a) )

    printf "rsp: %dn", $rsp
    set $rsp = $rsp - $len

    printf "rsp: %dn", $rsp
    call strcpy($rsp, $file_b)
    printf "rsp: %dn", $rsp
    printf "%d: %sn", $rsp,$rsp

    set $rsp = $rsp   $len
  end
  continue
end
run
 

Тестовый пример:

     $ gdb -batch -q -x script.gdb --args python -c "print open('/etc/fstab').read()"
Catchpoint 1 (syscall 'open' [2])
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
rsp: -10392
rsp: -10404
$1 = -10404
rsp: -10404
-10404: /etc/passwd
Traceback (most recent call last):
  File "<string>", line 1, in <module>
IOError: [Errno 38] Function not implemented: '/etc/fstab'
[Inferior 1 (process 25336) exited with code 01]
 

Комментарии:

1. Возможно ли, что проблема в выравнивании стека? x86-64 в Linux ожидает выравнивания стека на 16 байт. Так что что-то вроде set $old = $rsp , set $rsp = $rsp - $len , set $rsp = (unsigned long long)$rsp amp; (unsigned long long)~0xf , ..... , set $rsp = $old может сработать

2. @Andrew нет. Хотя выравнивание интересно, потому что в нем упоминается «strcpy-sse2-unaligned». Я подозреваю, что strcpy здесь плохой и его нужно заменить чем-то другим

3. В настоящее время я думаю, что проблема заключается в выполнении кода в середине системного вызова. Ошибки, которые я получаю, выглядят примерно так github.com/mozilla/rr/issues/605

Ответ №1:

Ваши аргументы для strcpy неверны. Это:

 char *strcpy(char *dest, const char *src);
 

тем не менее, у вас есть:

 call strcpy($newfile, $rsp)
 

Я предполагаю, что $newfile это действительно $file_b новое имя, которое вы хотите использовать, поэтому это должно быть src, в то время $rsp как вы хотите поместить новое имя файла, поэтому dest .

Вам также необходимо сохранить измененное значение $rsp into $rdi , чтобы open увидеть измененный параметр.

Комментарии:

1. Это был хороший шаг, но он еще не работает — отредактировано с результатом. Я думаю, что я пишу поверх другой части стека, потому Function not implemented: '/etc/fstab что явно связано с моим именем файла

2. Я заглянул в исходный код GDB, и я не думаю, что это будет работать в настоящее время. Использование call внутри системного вызова catch приводит к повреждению внутреннего состояния GDB, так что системный вызов завершается некорректно. Я думаю, что ответом может быть написание вспомогательной функции python, которая копирует строку в стек по одному байту за раз, чтобы вы могли избежать использования call .

3. можете ли вы связать меня с источником? Звучит очень интересно

4. @Nitz Я думаю, что это хорошая отправная точка sourceware.org/git/gitweb.cgi ? p= binutils-gdb.git;a= blob; f = gdb / … если вы включите ‘set debug infrun 1’ и ‘set debug lin-lwp 1’, вы увидите, что lp->syscall_state состояние, которое, как ожидается, будет кэшироваться между входом и выходом системного вызова, повреждается при использовании вызова (пока остановлено при вводе системного вызова). Если вы используете gdb в gdb и размещаете на lp->syscall_state нем контрольную точку, должно быть достаточно легко увидеть, где именно это происходит.