
Um framework de depuração, rastreamento e manipulação de processos multi-core orientado a eventos.
libptrace é um framework de depuração, rastreamento e manipulação de processos/threads orientado a eventos. Ele é escrito em C e possui bindings para Python 2.7 e 3.7.
Ele é destinado a ser usado como uma biblioteca. A API foi projetada pensando em suporte multiplataforma. Embora a versão atual funcione apenas em versões de 32 e 64 bits (wow64 é suportado) do Windows, o design e as abstrações são tais que outras plataformas e até suporte a depuração remota podem ser adicionados sob a mesma API.
Ele é ciente de múltiplos núcleos/threads e pode ser facilmente usado para executar múltiplos loops de eventos concorrentemente. Depurar grupos de processos ou pipelines, ou rastrear um grande número de processos, pode ser escalado aumentando os núcleos de execução dessa forma.
Escrevi a versão inicial do libptrace em 2006 enquanto ainda estava na universidade, e relicenciei para uso total pela Immunity Inc. em 2011, meu empregador na época. Nessa época, o framework deveria ser integrado ao Immunity Debugger, embora eu sempre tenha me preocupado em manter o framework separado, para que pudesse ser usado de forma autônoma.
Com esse objetivo em mente, ele viu muito desenvolvimento na Immunity, e sou grato por ter podido desenvolver ativamente nele durante meu horário de trabalho e ver o framework se tornar mais maduro. Redesenhei a maior parte para ser ciente de múltiplos núcleos, fornecer bindings Python e criar melhores abstrações.
Com o eventual lançamento do x64dbg, foi decidido que não trabalharíamos mais no Immunity Debugger e, em vez disso, focaríamos nossos esforços em outras coisas. Isso também estagnou o desenvolvimento do libptrace, e nos anos seguintes ele acumulou poeira no repositório git interno, até que após a aquisição da Immunity Inc. pela Cyxtera Technologies, agora sob a Cyxtera Cybersecurity Inc., foi decidido lançar o projeto sob a LGPL versão 2.1 para que pudesse, esperançosamente, ter adoção e desenvolvimento adicional.
Quero agradecer gentilmente à Immunity Inc., bem como à Cyxtera Technologies e à Cyxtera Cybersecurity Inc. por tornar este lançamento possível. Também gostaria de agradecer especificamente a Dave Aitel por empurrar este lançamento através de camadas de gerência e me proteger das partes burocráticas do processo. Teria sido triste ver meu trabalho perdido e sem propósito, e sem a disposição deles em liberar o desenvolvimento do libptrace que foi feito internamente como código aberto, isso é o que teria acontecido.
Também quero agradecer a vários colegas de trabalho que passaram tempo usando ou trabalhando no framework, principalmente Massimiliano Oldani, Roderick Asselineau e Christos Kalkanis. Meus agradecimentos também se estendem a Lennert Buytenhek por suas implementações de árvore AVL intrusiva e lista ligada que acabei usando.
Embora já tenham se passado mais de 4 anos desde que qualquer trabalho foi feito no projeto, espero que as pessoas o achem útil. Acredito que o design e o código-fonte sejam relativamente limpos, e neste ponto permitem que o framework seja estendido e portado para outras plataformas com relativa facilidade. Espero que um dia isso possa se tornar uma verdadeira biblioteca de depuração multiplataforma sob uma única API consistente.
Finalmente, gostaria de dedicar este projeto à minha filha perdida, Yuzuyu Huizer, com quem espero um dia me reunir. Eu te amo.
-- Ronald Huizer [email protected]
O método de compilação atualmente suportado é por cross-compilação do projeto usando MinGW e CMake. O sistema de compilação foi testado no Ubuntu 19.04.
Um instalador de 32 bits pode ser construído usando:
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=mingw-w64-x86.cmake .
make
makensis libptrace-setup.nsi
Um instalador de 64 bits pode ser construído usando:
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=mingw-w64-x64.cmake .
make
makensis -DUSE64 libptrace-setup.nsi
Após seguir as etapas de compilação acima, o instalador de 32 bits estará em libptrace-setup32.exe e o instalador de 64 bits estará em libptrace-setup64.exe.
O instalador determinará automaticamente quais versões do Python estão instaladas e se são de 32 ou 64 bits. As versões que foram encontradas serão oferecidas pelo instalador, e as versões que não foram encontradas serão exibidas em cinza.
Downloads de versões podem ser encontrados aqui.
O diretório doc/ está irremediavelmente desatualizado. Ele está incluído como um ponto de partida para documentação mais atual. Por favor, não o use.
Vários scripts de exemplo podem ser encontrados no diretório python/scripts. Eles serão instalados em Program Files\Immunity Inc\libptrace ou, no caso da versão de 32 bits, Program Files (x86)\Immunity Inc\libptrace.
Esses exemplos não mostram o framework de forma exaustiva, mas devem fornecer um bom ponto de partida para qualquer pessoa que queira usar o framework. A API C não foi bem documentada, mas alguns exemplos podem ser encontrados no diretório unittests/windows. O diretório python/, que contém os bindings Python, também fornece uma boa visão geral. Finalmente, o diretório include/libptrace contém os arquivos de cabeçalho que são públicos e, como tal, fornecem uma boa lista de funções da API.
Deve-se notar que a API Python atualmente é um subconjunto bastante limitado da API C.
Como exemplo, o fluxo de trabalho geral para rastrear chamadas RegOpenKeyExW em um executável seria:
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()
Se o valor de retorno de RegOpenKeyExW também for desejado, é mais fácil definir um breakpoint no endereço de retorno da chamada de função. Isso evita a necessidade de análise de código para determinar caminhos de saída da função estaticamente:
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)
A situação dos direitos autorais é esclarecida em cada arquivo individual. Eles são detidos principalmente pela Cyxtera Cybersecurity Inc., Ronald Huizer, ou ambos ao mesmo tempo. Alguns poucos arquivos têm detentores de direitos autorais de terceiros, como Lennert Buytenhek.
Distribuído sob a versão 2.1 da GNU Lesser General Public License. Veja COPYING e COPYING.LESSER para mais informações.