gdb прерывается, когда программа открывает определенный файл

Предыстория: при запуске программы под strace я заметил, что '/dev/urandom' подвергается open редактированию. Я хотел бы знать, откуда идет этот звонок (это не часть самой программы, это часть системы).

Итак, используя gdb, я пытаюсь прервать (используя catch syscall open) выполнение программы, когда выдается вызов open, поэтому я могу увидеть обратную трассировку. Проблема в том, что open вызывается часто, например, несколько сотен раз, поэтому я не могу сузить конкретный вызов, открывающий /dev/urandom. Как мне сузить конкретный вызов? Есть ли способ фильтровать по аргументам, и если да, то как это сделать для системного вызова?

Любой совет будет полезен - может быть, я все делаю неправильно.


person zdav    schedule 02.05.2011    source источник
comment
Вы можете просто сделать: взломать, если strcmp($rdi,/dev/urandom) == 0   -  person André Puel    schedule 30.12.2012


Ответы (3)


GDB — довольно мощный инструмент, но требует некоторого обучения.

По сути, вы хотите установить условную точку останова.

Сначала используйте флаг -i для strace или objdump -d, чтобы найти адрес открытой функции или, что более реалистично, что-то в цепочке ее получения, например, в файле plt.

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

break * 0x080482c8 

Далее вам нужно сделать его условным

(В идеале вы могли бы сравнить строковый аргумент с желаемой строкой. Я не заставлял это работать в течение первых нескольких минут попытки)

Будем надеяться, что мы можем предположить, что строка является константой где-то в программе или в одной из загружаемых ею библиотек. Вы можете заглянуть в /proc/pid/maps, чтобы получить представление о том, что и где загружено, затем использовать grep, чтобы убедиться, что строка действительно находится в файле, objdump -s, чтобы найти ее адрес, и gdb, чтобы убедиться, что вы загрузили на самом деле нашел его в памяти, объединив старшую часть адреса из карт с младшей частью из файла. (EDIT: вероятно, проще использовать ldd для исполняемого файла, чем искать в /proc/pid/maps)

Далее вам нужно будет кое-что узнать об аби платформы, над которой вы работаете, в частности о том, как передаются аргументы. В последнее время я работаю над arm, и это очень приятно, так как первые несколько аргументов просто помещаются в регистры r0, r1, r2... и т. д. x86 немного менее удобен - похоже, они помещаются в стек, т.е. * ($esp+4), *($esp+8), *($esp+12).

Итак, давайте предположим, что мы на x86, и мы хотим проверить, что первый аргумент в esp+4 равен адресу, который мы нашли для константы, которую мы пытаемся перехватить. Только esp+4 — это указатель на указатель char. Поэтому нам нужно разыменовать его для сравнения.

cond 1 *(char **)($esp+4)==0x8048514

Затем вы можете ввести run и надеяться на лучшее.

Если вы уловили условие точки останова и просмотр информационных регистров и команда x для проверки памяти кажутся правильными, то вы можете использовать команду return для просеивания обратно вверх по стеку вызовов, пока не найдете что-то знакомое.

person Chris Stratton    schedule 03.05.2011
comment
Спасибо за помощь! Вы почти привели меня туда... Я отредактировал свой ответ в полном объеме. - person zdav; 04.05.2011
comment
Извините, не знал, что у вас 64-битная система. - person Chris Stratton; 04.05.2011
comment
ок, кажется, я выяснил: адреса вроде не меняются после перезапуска процесса и с таким же успехом можно узнать с помощью (gdb) info functions [[regex]] - person phil294; 05.12.2016
comment
the address we found for the constant - когда мы нашли адрес? как узнать адрес строки Hello.txt, не зная, когда и где она инициализирована? Другими словами, откуда вы взяли 0x8048514? - person phil294; 05.12.2016

Как сказал Андре Пуэль:

break open if strcmp($rdi,"/dev/urandom") == 0

Может сделать работу.

person Community    schedule 04.12.2016

(Адаптировано из редактирования вопроса)

Следуя ответу Криса, вот процесс, который в конечном итоге дал мне то, что я искал:

(Я пытаюсь найти, какие функции вызывают системный вызов open в "/dev/urandom")

  1. используйте ldd для исполняемого файла, чтобы найти загруженные библиотеки
  2. grep через каждую библиотеку (команда оболочки) в поисках «urandom»
  3. открыть файл библиотеки в шестнадцатеричном редакторе и найти адрес строки
  4. узнайте, как параметры передаются в системных вызовах (для открытия файл является первым параметром. на x86_64 он передается в rdi - ваш пробег может отличаться
  5. теперь мы можем установить условную точку останова: break open if $rdi == _addr_
  6. запустите программу и дождитесь перерыва
  7. запустите bt, чтобы увидеть обратную трассировку

После всего этого я обнаружил, что g_random_int() и g_rand_new() в glib используют urandom. Gtk+ и ORBit вызывали эти функции — если кому интересно.

person Community    schedule 30.05.2014