libdebug ist eine Open-Source-Python-Bibliothek zur Automatisierung des Debuggens einer ausführbaren Binärdatei.
Mit libdebug haben Sie die volle Kontrolle über den Ablauf Ihrer debuggten ausführbaren Datei. Damit können Sie:
Wenn Sie dieselbe ausführbare Datei mehrmals ausführen, kann die Auswahl effizienter Implementierungen den Unterschied machen. Aus diesem Grund priorisiert libdebug die Leistung.
Homepage: https://libdebug.org
Dokumentation: https://docs.libdebug.org
Ubuntu:
sudo apt install -y python3 python3-dev libdwarf-dev libelf-dev libiberty-dev linux-headers-generic libc6-dbg
Debian:
sudo apt install -y python3 python3-dev libdwarf-dev libelf-dev libiberty-dev linux-headers-generic libc6-dbg
Arch Linux:
sudo pacman -S python libelf libdwarf gcc make debuginfod
Fedora:
sudo dnf install -y python3 python3-devel kernel-devel binutils-devel libdwarf-devel
python3 -m pip install libdebug
PyPy3 wird unterstützt, aber nicht empfohlen, da es bei den meisten unserer Tests schlechter abschneidet.
Wenn Sie mit den aktuellsten Funktionen auf dem Laufenden bleiben möchten (und es Ihnen nichts ausmacht, sich in einem instabilen Zweig zu befinden), können Sie von einem anderen Zweig (z. B. dev) aus installieren.
python3 -m pip install git+https://github.com/libdebug/libdebug.git@dev
Nachdem Sie libdebug installiert haben, können Sie es in Ihren Skripten verwenden. Hier ist ein einfaches Beispiel für die Verwendung von libdebug zum Debuggen einer Binärdatei:
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 ()
Das obige Skript führt den test
im Arbeitsverzeichnis aus und stoppt bei der Funktion, die dem Symbol „Funktion“ entspricht. Anschließend wird der Wert des RAX-Registers gedruckt und der Prozess abgebrochen.
Mit libdebug kann noch viel mehr gemacht werden. Bitte lesen Sie die Dokumentation, um mehr zu erfahren.
libdebug bietet viele erweiterte Funktionen. Schauen Sie sich dieses Skript an, das mit Signalen zaubert:
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 ()
Mit libdebug können Sie außerdem alle Befehle so schnell wie möglich ausführen, ohne auf ein Stoppereignis warten zu müssen. Um diesen Modus zu aktivieren, können Sie auto_interrupt_on_command=True
verwenden
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 ()
Wenn Sie beabsichtigen, libdebug in Ihrer Arbeit zu verwenden, zitieren Sie dieses Repository bitte mit dem folgenden 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},
}