Несколько ответов здесь и статья о внедрении кода , на которую вы ссылались в своем ответе, охватывают фрагменты того, что я считаю оптимальным gdb
-ориентированным решением, но ни один из них не объединяет все это и не охватываетвсе точки.Кодовое выражение решения немного длинное, поэтому вот краткое изложение важных шагов:
- Загрузка кода для внедрения .Большинство ответов, опубликованных здесь, используют то, что я считаю лучшим подходом - вызовите
dlopen()
в подчиненном процессе, чтобы создать ссылку в общей библиотеке, содержащей введенный код.В этой статье вы связались с автором, вместо этого загрузили перемещаемый объектный файл и связали его вручную с подчиненным.Это, откровенно говоря, безумие - перемещаемые объекты не являются «готовыми к работе» и включают перемещения даже для внутренних ссылок.А ручная компоновка утомительна и подвержена ошибкам - гораздо проще позволить реальной работе динамического компоновщика во время выполнения.Это, в первую очередь, означает получение libdl
в процессе, но для этого есть много вариантов. - Создание объезда .Большинство ответов, опубликованных здесь до сих пор, включали в себя поиск записи PLT для интересующей функции, использование которой для нахождения соответствующей записи GOT, а затем изменение записи GOT для указания на введенную функцию.Это хорошо до некоторой степени, но некоторые функции компоновщика - например, использование
dlsym
- могут обойти GOT и обеспечить прямой доступ к интересующей функции.Единственный способ быть уверенным в перехвате всех вызовов определенной функции - это переписать начальные инструкции кода этой функции в памяти, чтобы создать «обходной» путь, перенаправляющий выполнение на введенную функцию. - Созданиебатут (опционально).Часто при выполнении такого рода инъекций вы захотите вызвать исходную функцию, вызов которой вы перехватываете.Способ сделать это с помощью обхода функции заключается в создании небольшого кода «батут», который включает перезаписанные инструкции исходной функции, а затем переход к оставшейся части оригинала.Это может быть сложным, поскольку любые IP-относительные инструкции в скопированном наборе необходимо изменить, чтобы учесть их новые адреса.
- Автоматизируйте все это .Эти шаги могут быть утомительными, даже если вы делаете некоторые из простых решений, опубликованных в других ответах.Лучший способ убедиться, что шаги выполняются правильно каждый раз с переменными параметрами (внедрение различных функций и т. Д.), - это автоматизировать их выполнение.Начиная с серии 7.0,
gdb
включает возможность писать новые команды в Python.Эта поддержка может быть использована для реализации решения «под ключ» для внедрения и обхода кода в / в подчиненном процессе.
Вот пример.У меня есть такие же исполняемые файлы a
и b
, как и раньше, и inject2.so
, созданный из следующего кода:
#include <unistd.h>
#include <stdio.h>
int (*rand__)(void) = NULL;
int
rand(void)
{
int result = rand__();
printf("rand invoked! result = %d\n", result);
return result % 47;
}
Затем я могу поместить свою команду Python detour
в detour.py
и получитьследующий gdb
сеанс:
(gdb) source detour.py
(gdb) exec-file a
(gdb) set follow-fork-mode child
(gdb) catch exec
Catchpoint 1 (exec)
(gdb) run
Starting program: /home/llasram/ws/detour/a
a: 1933263113
a: 831502921
[New process 8500]
b: 918844931
process 8500 is executing new program: /home/llasram/ws/detour/b
[Switching to process 8500]
Catchpoint 1 (exec'd /home/llasram/ws/detour/b), 0x00007ffff7ddfaf0 in _start ()
from /lib64/ld-linux-x86-64.so.2
(gdb) break main
Breakpoint 2 at 0x4005d0: file b.c, line 7.
(gdb) cont
Continuing.
Breakpoint 2, main (argc=1, argv=0x7fffffffdd68) at b.c:7
7 {
(gdb) detour libc.so.6:rand inject2.so:rand inject2.so:rand__
(gdb) cont
Continuing.
rand invoked! result = 392103444
b: 22
Program exited normally.
В дочернем процессе я создаю обход от функции rand()
в libc.so.6
к функции rand()
в inject2.so
и сохраняю указатель набатут для оригинального rand()
в переменной rand__
inject2.so
.И, как и ожидалось, введенный код вызывает исходный код, отображает полный результат и возвращает этот результат по модулю 47.
Из-за длины я просто ссылаюсь на вставку, содержащую код моего detour
команда .Это довольно поверхностная реализация (особенно с точки зрения создания батута), но она должна хорошо работать в большом проценте случаев.Я протестировал его с gdb
7.2 (последняя выпущенная версия) в Linux с 32-битными и 64-битными исполняемыми файлами.Я не тестировал его на OS X, но любые различия должны быть относительно незначительными.