diff --git a/madbg/api.py b/madbg/api.py index 85e0dc3..70d7af5 100644 --- a/madbg/api.py +++ b/madbg/api.py @@ -1,6 +1,4 @@ -import os import re -import signal import sys from traceback import format_exc from contextlib import nullcontext diff --git a/madbg/consts.py b/madbg/consts.py index 5330aa9..aa26390 100644 --- a/madbg/consts.py +++ b/madbg/consts.py @@ -6,6 +6,8 @@ STDERR_FILENO = 2 DEFAULT_ADDR = ('127.0.0.1', 0xdb9) +# TODO: add flag to use unsafe injection +# TODO: for normal injection have infinite timeout DEFAULT_CONNECT_TIMEOUT = 10. MESSAGE_LENGTH_FMT = 'I' diff --git a/madbg/debugger.py b/madbg/debugger.py index 891cc26..df2da19 100644 --- a/madbg/debugger.py +++ b/madbg/debugger.py @@ -1,14 +1,12 @@ from __future__ import annotations import runpy import os -import signal import sys from bdb import BdbQuit from contextlib import contextmanager, nullcontext from typing import ContextManager from prompt_toolkit.input.vt100 import Vt100Input from prompt_toolkit.output.vt100 import Vt100_Output -from inspect import currentframe from IPython.terminal.debugger import TerminalPdb from IPython.terminal.interactiveshell import TerminalInteractiveShell @@ -81,13 +79,19 @@ def notify_client_connect(self, tty_config: TTYConfig): def notify_client_disconnect(self): self.num_clients -= 1 + print(0) if self.num_clients == 0: # TODO: can we use self.stop_here (from ipython code) instead of the debugging global? + print(1) if self.pt_app.app.is_running: + print(2) self.pt_app.app.exit('quit') + print(3) elif self.running_app.app.is_running: + print(4) # TODO: need to unregister the signal handler self.running_app.app.exit() + print(5) def preloop(self): if self.num_clients == 0: @@ -106,12 +110,16 @@ def trace_dispatch(self, frame, event, arg, check_debugging_global=False): return None bdb_quit = False try: + print('a') return super().trace_dispatch(frame, event, arg) except BdbQuit: bdb_quit = True finally: + print('x') if self.quitting or bdb_quit: + print('y') self._on_done() + print('z') def _on_done(self): print_to_ctty('Debugger stopped') diff --git a/madbg/server.py b/madbg/server.py index fc04ce7..0be6eec 100644 --- a/madbg/server.py +++ b/madbg/server.py @@ -3,6 +3,7 @@ import struct from asyncio import Protocol, StreamReader, StreamWriter, AbstractEventLoop, start_server, new_event_loop, \ get_event_loop, Future +from dataclasses import dataclass, field from threading import Thread from typing import Any, Set @@ -20,6 +21,11 @@ # own terminal size and type... This doesn't go hand in hand with the current IPythonDebugger # design, as it assumes it is singletonic, and it has one output PTY. +@dataclass +class State: + address: tuple + future: Future = field(default_factory=Future) + class ClientMulticastProtocol(Protocol): def __init__(self, loop: AbstractEventLoop): self.loop: AbstractEventLoop = loop @@ -120,33 +126,31 @@ def make_sure_listening_at(cls, addr: Addr): with cls.STATE as state: if state is None: # TODO: receive addr as arg - cls.STATE.set(Future()) + cls.STATE.set(State(addr)) debugger = RemoteIPythonDebugger() prepare_injection(debugger) Thread(daemon=True, target=cls._run, args=(addr, debugger)).start() - elif state.done(): + elif state.future.done(): # Raise the exception - state.result() + state.future.result() else: - # TODO - raise RuntimeError('No support for double bind') + if addr != state.address: + # TODO + raise RuntimeError('No support for double bind') """ Next steps: - - attach - need to do something very minimal during attach, like registering a signal handler or add pending action - pending action is better than another fucking signal, but it will wait for stuck syscalls... - pyinjector.pyinjector.InjectorError: injector_inject returned -1: The target process unexpectedly stopped by signal 17. - pyinjector issues: - - getting the python error back to us or at least know that it failed - - threads - - deadlock + - pyinjector issues: + - getting the python error back to us or at least know that it failed + - threads + - deadlock - client-level detach (c-z, c-\) - support mac n windows python -c $'import madbg; madbg.start()\nwhile 1: print(__import__("time").sleep(1) or ":)")' +python -c $'while 1: print(__import__("time").sleep(1) or ":)")' - There is only one debugger with one session - A trace can start at any thread because of a set_trace(), or a client setting it - A trace can start when there is no client connected, but should print a warning to tty diff --git a/setup.cfg b/setup.cfg index d7ee46a..82265f4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,9 +3,11 @@ packages = madbg python_requires = >=3.7 install_requires = click - IPython>=7.17.0 + # Need https://github.com/ipython/ipython/pull/13311 + IPython>=7.30.0 prompt_toolkit - hypno>=0.1.3 + # TODO + hypno>=1.1.0 [metadata] name = madbg