libdebug は、バイナリ実行可能ファイルのデバッグを自動化するオープンソースの Python ライブラリです。
libdebug を使用すると、デバッグされた実行可能ファイルのフローを完全に制御できます。これを使用すると、次のことが可能になります。
同じ実行可能ファイルを複数回実行する場合、効率的な実装を選択すると違いが生じる可能性があります。このため、libdebug はパフォーマンスを優先します。
ホームページ: https://libdebug.org
ドキュメント: https://docs.libdebug.org
Ubuntu:
sudo apt install -y python3 python3-dev libdwarf-dev libelf-dev libiberty-dev linux-headers-generic libc6-dbg
デビアン:
sudo apt install -y python3 python3-dev libdwarf-dev libelf-dev libiberty-dev linux-headers-generic libc6-dbg
アーチ Linux:
sudo pacman -S python libelf libdwarf gcc make debuginfod
フェドーラ:
sudo dnf install -y python3 python3-devel kernel-devel binutils-devel libdwarf-devel
python3 -m pip install libdebug
PyPy3 はサポートされていますが、ほとんどのテストでパフォーマンスが低下するため、推奨されません。
最先端の機能を常に最新の状態に保ちたい場合 (不安定なブランチにいることを気にしない場合)、別のブランチ (例: dev) からインストールできます。
python3 -m pip install git+https://github.com/libdebug/libdebug.git@dev
libdebug がインストールされたので、スクリプトでそれを使用できるようになります。以下は、libdebug を使用してバイナリをデバッグする方法の簡単な例です。
from libdebug import debugger
d = debugger ( "./test" )
# Start debugging from the entry point
d . run ()
my_breakpoint = d . breakpoint ( "function" )
# Continue the execution until the breakpoint is hit
d . cont ()
# Print RAX
print ( f"RAX is { hex ( d . regs . rax ) } " )
# Write to memory
d . memory [ 0x10ad , 8 , "binary" ] = b"Hello! x00 x00 "
# Continue the execution
d . cont ()
上記のスクリプトは作業ディレクトリでバイナリtest
を実行し、記号「function」に対応する関数で停止します。次に、RAX レジスタの値を出力し、プロセスを強制終了します。
libdebug でできることは他にもたくさんあります。詳細については、ドキュメントをお読みください。
libdebug は多くの高度な機能を提供します。シグナルを使って魔法を実行しているこのスクリプトを見てください。
from libdebug import debugger , libcontext
libcontext . terminal = [ 'tmux' , 'splitw' , '-h' ]
# Define signal catchers
def catcher_SIGUSR1 ( t : ThreadContext , catcher : SignalCatcher ) -> None :
t . signal = 0x0
print ( f"SIGUSR1: Signal number { catcher } " )
def catcher_SIGINT ( t : ThreadContext , catcher : SignalCatcher ) -> None :
print ( f"SIGINT: Signal number { catcher } " )
def catcher_SIGPIPE ( t : ThreadContext , catcher : SignalCatcher ) -> None :
print ( f"SIGPIPE: Signal number { catcher } " )
def handler_geteuid ( t : ThreadContext , handler : SyscallHandler ) -> None :
t . regs . rax = 0x0
# Initialize the debugger
d = debugger ( '/path/to/executable' , continue_to_binary_entrypoint = False , aslr = False )
# Register signal catchers
catcher1 = d . catch_signal ( "SIGUSR1" , callback = catcher_SIGUSR1 )
catcher2 = d . catch_signal ( "SIGINT" , callback = catcher_SIGINT )
catcher3 = d . catch_signal ( "SIGPIPE" , callback = catcher_SIGPIPE )
# Register signal hijackings
d . hijack_signal ( "SIGQUIT" , "SIGTERM" )
d . hijack_signal ( "SIGINT" , "SIGPIPE" , recursive = True )
# Define which signals to block
d . signals_to_block = [ "SIGPOLL" , "SIGIO" , "SIGALRM" ]
d . handle_syscall ( "geteuid" , on_exit = handler_geteuid )
# Continue execution
d . cont ()
# Disable the catchers after execution
catcher1 . disable ()
catcher2 . disable ()
catcher3 . disable ()
bp = d . breakpoint ( 0xdeadc0de , hardware = True )
d . cont ()
d . wait ()
d . gdb ()
libdebug を使用すると、停止イベントを待つことなく、すべてのコマンドをできるだけ早く実行することもできます。このモードを有効にするには、 auto_interrupt_on_command=True
使用できます。
from libdebug import debugger
d = debugger ( "/path/to/executable" , auto_interrupt_on_command = True )
pipes = d . run ()
bp = d . breakpoint ( "function" )
d . cont ()
# Read shortly after the cont is issued
# The process is forcibly stopped to read the register
value = d . regs . rax
print ( f"RAX is { hex ( value ) } " )
system_offset = d . symbols . filter ( "system" )[ 0 ]. start
libc_base = d . maps . filter ( "libc" )[ 0 ]. base
system_address = libc_base + system_offset
d . memory [ 0x12ebe , 8 , "libc" ] = int . to_bytes ( system_address , 8 , "little" )
d . cont ()
d . wait ()
# Here we should be at the breakpoint
# This value is read while the process is stopped at the breakpoint
ip_value = d . regs . rip
print ( f"RIP is { hex ( ip_value ) } " )
d . kill ()
作業で libdebug を使用する場合は、次の biblatex を使用してこのリポジトリを引用してください。
@software{libdebug_2024,
title = {libdebug: {Build} {Your} {Own} {Debugger}},
copyright = {MIT Licence},
url = {https://libdebug.org},
publisher = {libdebug.org},
author = {Digregorio, Gabriele and Bertolini, Roberto Alessandro and Panebianco, Francesco and Polino, Mario},
year = {2024},
doi = {10.5281/zenodo.13151549},
}