
Событийно-ориентированный фреймворк для отладки, трассировки и манипуляции многоядерными процессами.
libptrace — это фреймворк для отладки, трассировки и управления процессами/потоками, работающий на основе событий. Он написан на C и имеет привязки для Python 2.7 и 3.7.
Предполагается использование в качестве библиотеки. API спроектирован с учётом поддержки разных платформ. Хотя текущая версия работает только на 32- и 64-разрядных версиях Windows (поддерживается wow64), архитектура и абстракции позволяют добавлять поддержку других платформ и даже удалённую отладку под тем же API.
Фреймворк учитывает многоядерность и может легко запускать несколько циклов событий одновременно. Отладка групп процессов или конвейеров, а также трассировка большого количества процессов могут масштабироваться путём увеличения числа ядер выполнения.
Я написал начальную версию libptrace в 2006 году, ещё будучи студентом, и перелицензировал её для полного использования компанией Immunity Inc. в 2011 году, где я тогда работал. Примерно в то время фреймворк предполагалось интегрировать в Immunity Debugger, хотя я всегда старался держать его отдельно, чтобы его можно было использовать автономно.
С этой целью фреймворк получил значительное развитие в Immunity, и я благодарен за возможность активно разрабатывать его в рабочее время и наблюдать, как он становится более зрелым. Я переработал большую его часть с учётом многоядерности, создал привязки для Python и улучшил абстракции.
После выхода x64dbg было решено прекратить работу над Immunity Debugger и сосредоточиться на других задачах. Это приостановило разработку libptrace, и в последующие годы он пылился во внутреннем git-репозитории, пока после приобретения Immunity Inc. компанией Cyxtera Technologies, ныне входящей в Cyxtera Cybersecurity Inc., не было решено выпустить проект под лицензией LGPL версии 2.1 в надежде, что он получит распространение и дальнейшее развитие.
Я хочу искренне поблагодарить Immunity Inc., а также Cyxtera Technologies и Cyxtera Cybersecurity Inc. за этот выпуск. Также хочу отдельно поблагодарить Дейва Айтела (Dave Aitel), который продвинул этот релиз через бюрократические уровни и уберег меня от бюрократической части процесса. Было бы грустно увидеть, как мои труды пропадают без цели, и без их готовности выпустить разработанную внутри libptrace в виде открытого исходного кода именно это и произошло бы.
Я также хочу поблагодарить нескольких коллег, которые тратили время на использование или работу над фреймворком, в первую очередь Массимилиано Олдани (Massimiliano Oldani), Родерика Асселино (Roderick Asselineau) и Кристоса Калканиса (Christos Kalkanis). Моя благодарность также распространяется на Леннерта Буйтенхека (Lennert Buytenhek) за его интрузивные реализации AVL-дерева и связного списка, которые я в итоге использовал.
Хотя с момента последней работы над проектом прошло более 4 лет, я надеюсь, что люди найдут его полезным. Я считаю, что архитектура и исходный код достаточно чисты, и на данный момент это позволяет относительно легко расширять фреймворк и переносить его на другие платформы. Надеюсь, когда-нибудь это превратится в настоящую кроссплатформенную библиотеку отладки с единым согласованным API.
Наконец, я хотел бы посвятить этот проект моей потерянной дочери, Юзуй Хойзер (Yuzuyu Huizer), с которой я надеюсь когда-нибудь воссоединиться. Я люблю тебя.
-- Ronald Huizer [email protected]
Текущий поддерживаемый метод сборки — кросс-компиляция проекта с использованием MinGW и CMake. Система сборки была протестирована на Ubuntu 19.04.
32-разрядный установщик можно собрать с помощью:
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=mingw-w64-x86.cmake .
make
makensis libptrace-setup.nsi
64-разрядный установщик можно собрать с помощью:
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=mingw-w64-x64.cmake .
make
makensis -DUSE64 libptrace-setup.nsi
После выполнения описанных выше шагов сборки 32-разрядный установщик будет находиться по пути libptrace-setup32.exe, а 64-разрядный — по пути libptrace-setup64.exe.
Установщик автоматически определит, какие версии Python установлены и являются ли они 32- или 64-разрядными. Найденные версии будут предложены установщиком, а версии, которые не были найдены, будут выделены серым цветом.
Релизные загрузки можно найти здесь.
Каталог doc/ безнадёжно устарел. Он включён в качестве отправной точки для более актуальной документации. Пожалуйста, не используйте его.
Несколько примеров скриптов можно найти в каталоге python/scripts. Они будут установлены в Program Files\Immunity Inc\libptrace или, в случае 32-разрядной версии, в Program Files (x86)\Immunity Inc\libptrace.
Эти примеры ни в коем случае не исчерпывают возможностей фреймворка, но они должны послужить хорошей отправной точкой для тех, кто хочет его использовать. C API документирован не очень хорошо, но некоторые примеры можно найти в каталоге unittests/windows. Каталог python/, содержащий привязки Python, также даёт хороший обзор. Наконец, каталог include/libptrace содержит заголовочные файлы, которые являются открытыми, и, следовательно, представляют хороший список функций API.
Следует отметить, что Python API в настоящее время является довольно ограниченным подмножеством C API.
В качестве примера общий рабочий процесс для трассировки вызовов RegOpenKeyExW в исполняемом файле будет выглядеть так:
import _ptrace
def bp_handler(bp, thread):
(key, subkey, options, sam, result) = _ptrace.cconv.args_get(thread, "%u%p%u%u%p")
subkey = thread.process.read_utf16(subkey)
print('T{}: RegOpenKeyEx({}, "{}", 0x{:08x}, 0x{:08x}, 0x{:08x})'
.format(thread.id, key, subkey, options, sam, result), end='')
def attached_handler(process):
bp = _ptrace.breakpoint_sw("advapi32!RegOpenKeyExW", bp_handler)
process.breakpoint_set(bp)
handlers = _ptrace.event_handlers()
handlers.attached = attached_handler
_ptrace.execv(r"C:\Windows\Notepad.exe", [], handlers, 0)
_ptrace.main()
Если также требуется возвращаемое значение RegOpenKeyExW, проще всего установить точку останова на адрес возврата вызова функции. Это избавляет от необходимости анализа кода для статического определения путей выхода из функции:
def bp_end_handler(bp, thread):
print("=", _ptrace.cconv.retval_get(thread))
def bp_handler(bp, thread):
(key, subkey, options, sam, result) = _ptrace.cconv.args_get(thread, "%u%p%u%u%p")
subkey = thread.process.read_utf16(subkey)
print('T{}: RegOpenKeyEx({}, "{}", 0x{:08x}, 0x{:08x}, 0x{:08x})'
.format(thread.id, key, subkey, options, sam, result), end='')
retaddr = _ptrace.cconv.retaddr_get(thread)
if thread.process.breakpoint_find(retaddr) is None:
bp_end = _ptrace.breakpoint_sw(retaddr, bp_end_handler)
thread.process.breakpoint_set(bp_end)
Ситуация с авторскими правами разъяснена в каждом отдельном файле. В основном они принадлежат Cyxtera Cybersecurity Inc., Рональду Хойзеру (Ronald Huizer) или обоим одновременно. Некоторые файлы имеют сторонних правообладателей, например Леннерта Буйтенхека (Lennert Buytenhek).
Распространяется под лицензией GNU Lesser General Public License версии 2.1. Дополнительную информацию см. в COPYING и COPYING.LESSER.