libptrace是一个事件驱动的进程/线程调试、追踪和操作框架。它使用C语言编写,并具有Python 2.7和3.7的绑定。
它的设计初衷是作为库使用。API在设计时考虑了跨平台支持。虽然当前版本仅运行在32位和64位(支持wow64)的Windows上,但其设计和抽象使得其他平台甚至远程调试支持可以在同一API下添加。
它是多核/多线程感知的,可以轻松地同时运行多个事件循环。通过增加执行核心数量,可以扩展调试进程组或管道,或追踪大量进程的能力。
我在2006年还在大学时编写了libptrace的初始版本,并于2011年将其重新授权给当时的雇主Immunity Inc.以供全面使用。大约在这段时间,该框架本打算集成到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树和链表实现。
尽管该项目已经四年多没有进行了,但我希望人们会发现它很有用。我相信设计和源代码相对干净,并且在这一点上,该框架可以相对容易地扩展到其他平台。希望有一天,它能在统一一致的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。