pyx64dbg 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyx64dbg-0.1.0/LICENSE +21 -0
- pyx64dbg-0.1.0/MANIFEST.in +5 -0
- pyx64dbg-0.1.0/PKG-INFO +163 -0
- pyx64dbg-0.1.0/README.md +108 -0
- pyx64dbg-0.1.0/pyproject.toml +45 -0
- pyx64dbg-0.1.0/pyx64dbg/CLI/__init__.py +0 -0
- pyx64dbg-0.1.0/pyx64dbg/CLI/ipython_cli.py +83 -0
- pyx64dbg-0.1.0/pyx64dbg/CLI/main.py +34 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/__init__.py +0 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/assets/icon.svg +38 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/async_slot.py +25 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/breakpoints_view.py +155 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/debug_controls_view.py +159 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/debugger_state.py +18 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/debugger_worker.py +357 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/disassembly_view.py +418 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/extended_registers_view.py +280 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/interactive_console_view.py +47 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/main.py +44 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/main_window.py +440 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/placeholders.py +64 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/pty_view/index.html +67 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/pty_view/xterm-addon-fit.js +2 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/pty_view/xterm.css +209 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/pty_view/xterm.js +2 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/pty_view.py +151 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/registers_view.py +130 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/stdio_view.py +49 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/styles/breakpoints_view.qss +35 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/styles/disassembly_view.qss +64 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/styles/extended_registers_view.qss +24 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/styles/main_window.qss +9 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/styles/registers_view.qss +36 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/styles/symbols_view.qss +36 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/styles/watch_view.qss +11 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/symbols_view.py +141 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/top_menu.py +98 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/utils.py +36 -0
- pyx64dbg-0.1.0/pyx64dbg/GUI/watch_view.py +198 -0
- pyx64dbg-0.1.0/pyx64dbg/__init__.py +9 -0
- pyx64dbg-0.1.0/pyx64dbg/breakpoint.py +61 -0
- pyx64dbg-0.1.0/pyx64dbg/callback_list.py +32 -0
- pyx64dbg-0.1.0/pyx64dbg/control.py +260 -0
- pyx64dbg-0.1.0/pyx64dbg/debugger.py +225 -0
- pyx64dbg-0.1.0/pyx64dbg/get_mappings.py +186 -0
- pyx64dbg-0.1.0/pyx64dbg/interactive_console/__init__.py +0 -0
- pyx64dbg-0.1.0/pyx64dbg/interactive_console/console_aliases.py +115 -0
- pyx64dbg-0.1.0/pyx64dbg/interactive_console/console_functions.py +92 -0
- pyx64dbg-0.1.0/pyx64dbg/interactive_console/disassembly_function.py +158 -0
- pyx64dbg-0.1.0/pyx64dbg/interactive_console/exception_trap.py +25 -0
- pyx64dbg-0.1.0/pyx64dbg/interactive_console/exceptions.py +25 -0
- pyx64dbg-0.1.0/pyx64dbg/interactive_console/interactive_console.py +182 -0
- pyx64dbg-0.1.0/pyx64dbg/memory.py +381 -0
- pyx64dbg-0.1.0/pyx64dbg/number_types/__init__.pyi +1557 -0
- pyx64dbg-0.1.0/pyx64dbg/number_types/number_types.cpp +774 -0
- pyx64dbg-0.1.0/pyx64dbg/parse_elf.py +127 -0
- pyx64dbg-0.1.0/pyx64dbg/process_exited_error.py +23 -0
- pyx64dbg-0.1.0/pyx64dbg/ptrace/__init__.pyi +60 -0
- pyx64dbg-0.1.0/pyx64dbg/ptrace/ptrace.cpp +317 -0
- pyx64dbg-0.1.0/pyx64dbg/ptrace/utils.cpp +31 -0
- pyx64dbg-0.1.0/pyx64dbg/ptrace/utils.hpp +22 -0
- pyx64dbg-0.1.0/pyx64dbg/ptrace/xstate.cpp +219 -0
- pyx64dbg-0.1.0/pyx64dbg/ptrace/xstate.hpp +25 -0
- pyx64dbg-0.1.0/pyx64dbg/py.typed +0 -0
- pyx64dbg-0.1.0/pyx64dbg/registers.py +383 -0
- pyx64dbg-0.1.0/pyx64dbg/shared_object.py +21 -0
- pyx64dbg-0.1.0/pyx64dbg/stack.py +230 -0
- pyx64dbg-0.1.0/pyx64dbg/stdio_tube.py +135 -0
- pyx64dbg-0.1.0/pyx64dbg/symbols.py +145 -0
- pyx64dbg-0.1.0/pyx64dbg/vector_register.py +436 -0
- pyx64dbg-0.1.0/pyx64dbg.egg-info/PKG-INFO +163 -0
- pyx64dbg-0.1.0/pyx64dbg.egg-info/SOURCES.txt +76 -0
- pyx64dbg-0.1.0/pyx64dbg.egg-info/dependency_links.txt +1 -0
- pyx64dbg-0.1.0/pyx64dbg.egg-info/entry_points.txt +3 -0
- pyx64dbg-0.1.0/pyx64dbg.egg-info/requires.txt +11 -0
- pyx64dbg-0.1.0/pyx64dbg.egg-info/top_level.txt +1 -0
- pyx64dbg-0.1.0/setup.cfg +4 -0
- pyx64dbg-0.1.0/setup.py +34 -0
pyx64dbg-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yoav Shamay
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pyx64dbg-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyx64dbg
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A debugger implemented in Python
|
|
5
|
+
Author-email: Yoav Shamay <yoavsh97@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Yoav Shamay
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
Project-URL: Homepage, https://github.com/yoav-shamay/pyx64dbg
|
|
28
|
+
Project-URL: Repository, https://github.com/yoav-shamay/pyx64dbg
|
|
29
|
+
Keywords: debugger,ptrace,x86-64,linux
|
|
30
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
31
|
+
Classifier: Development Status :: 3 - Alpha
|
|
32
|
+
Classifier: Intended Audience :: Developers
|
|
33
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
34
|
+
Classifier: Programming Language :: Python :: 3
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
40
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
41
|
+
Requires-Python: >=3.10
|
|
42
|
+
Description-Content-Type: text/markdown
|
|
43
|
+
License-File: LICENSE
|
|
44
|
+
Requires-Dist: capstone
|
|
45
|
+
Requires-Dist: pyelftools
|
|
46
|
+
Requires-Dist: ipython
|
|
47
|
+
Requires-Dist: prompt_toolkit
|
|
48
|
+
Requires-Dist: pyside6
|
|
49
|
+
Requires-Dist: nest_asyncio
|
|
50
|
+
Provides-Extra: dev
|
|
51
|
+
Requires-Dist: black; extra == "dev"
|
|
52
|
+
Requires-Dist: jinja2; extra == "dev"
|
|
53
|
+
Requires-Dist: pytest; extra == "dev"
|
|
54
|
+
Dynamic: license-file
|
|
55
|
+
|
|
56
|
+
# PyX64Dbg
|
|
57
|
+
|
|
58
|
+

|
|
59
|
+

|
|
60
|
+

|
|
61
|
+
|
|
62
|
+
**PyX64Dbg** is a Python-based debugger for x86-64 Linux binaries.
|
|
63
|
+
|
|
64
|
+
PyX64Dbg utilizes the Linux `ptrace` system call and the `/proc` filesystem (`procfs`) to trace and introspect ELF processes. These low-level operating system primitives are abstracted into an intuitive Python object model, enabling direct manipulation of process memory, CPU registers, and execution flow.
|
|
65
|
+
|
|
66
|
+
The tool features through three primary interfaces: a **Python API** designed for automated reverse engineering and binary analysis, a **Graphical User Interface (GUI)** for visual debugging, and a robust **IPython-based CLI** for debugging from the terminal.
|
|
67
|
+
|
|
68
|
+
## Key Features
|
|
69
|
+
|
|
70
|
+
- **Python API:** Automate reverse engineering, exploit development, or testing using a clean, object-oriented interface. Unlike GDB, PyX64Dbg acts as a standard Python library you can import and use anywhere.
|
|
71
|
+
- **Graphical Interface (GUI):** Built with PySide6, featuring disassembly views, memory watches, register panels, and an embedded interactive terminal.
|
|
72
|
+
- **Command Line Interface (CLI):** An interactive IPython REPL that supports live Python syntax, auto-completion, and inline evaluation.
|
|
73
|
+
- **Advanced Target Support:** Native handling of PIE (Position Independent Executables), ASLR, shared libraries (`ld.so`), and dynamic symbols.
|
|
74
|
+
- **C-Like Type System:** A custom extension providing native types (`Int32`, `UInt64`, `Float80`, etc.) that strictly follow C promotion, overflow, and truncation rules.
|
|
75
|
+
- **Extended Registers (AVX/SSE):** Supports CPU `xstate`, including `XMM`, `YMM`, and FPU (`st`) vector registers. The API allows you to seamlessly treat vector data as a C-style union across all possible integer and floating-point array representations.
|
|
76
|
+
|
|
77
|
+
## Prerequisites
|
|
78
|
+
|
|
79
|
+
- **Operating System**: Linux (x86-64 architecture only)
|
|
80
|
+
- **Python**: 3.10 or later
|
|
81
|
+
- **C++ Compiler**: A C++20 compatible compiler (e.g., `g++` or `clang`) and Python development headers are required to compile the `ptrace` and numeric type extensions during installation.
|
|
82
|
+
|
|
83
|
+
## Installation
|
|
84
|
+
|
|
85
|
+
### From PyPI (Recommended)
|
|
86
|
+
```bash
|
|
87
|
+
pip install pyx64dbg
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### From Source (Development)
|
|
91
|
+
Clone the repository and install it in editable mode:
|
|
92
|
+
```bash
|
|
93
|
+
git clone https://github.com/yoav-shamay/pyx64dbg.git
|
|
94
|
+
cd pyx64dbg
|
|
95
|
+
pip install -e .
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Usage
|
|
99
|
+
|
|
100
|
+
### Graphical Interface (GUI)
|
|
101
|
+
Start the visual debugger (requires a desktop session like X11 or Wayland):
|
|
102
|
+
```bash
|
|
103
|
+
pyx64dbg-gui
|
|
104
|
+
```
|
|
105
|
+
*Tip: The full IPython CLI is embedded directly into the GUI and is available via the "Interactive Console" tab at the bottom.*
|
|
106
|
+
|
|
107
|
+
### Command Line Interface (CLI)
|
|
108
|
+
Launch the interactive IPython console:
|
|
109
|
+
```bash
|
|
110
|
+
pyx64dbg [/path/to/binary]
|
|
111
|
+
```
|
|
112
|
+
Once inside, simply type `help` to see a list of available commands and aliases (e.g., `run`, `step`, `bps`, `dis`).
|
|
113
|
+
|
|
114
|
+
## Python API Showcase
|
|
115
|
+
|
|
116
|
+
PyX64Dbg is built to be scripted. You can easily interact with binaries directly from Python.
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from pyx64dbg import Debugger
|
|
120
|
+
from pyx64dbg.number_types import UInt64
|
|
121
|
+
|
|
122
|
+
# 1. Spawn process and attach debugger
|
|
123
|
+
dbg = Debugger.start_and_debug("./target_binary")
|
|
124
|
+
|
|
125
|
+
# 2. Set a breakpoint at the 'main' function
|
|
126
|
+
main_addr = dbg.symbols["main"]
|
|
127
|
+
dbg.breakpoints.add_breakpoint(main_addr)
|
|
128
|
+
|
|
129
|
+
# 3. Run until the breakpoint is hit
|
|
130
|
+
dbg.control.continue_execution()
|
|
131
|
+
|
|
132
|
+
# 4. Read memory and native vector registers
|
|
133
|
+
rip = dbg.registers.rip
|
|
134
|
+
rsp_val = dbg.memory.read_number(dbg.registers.rsp, UInt64)
|
|
135
|
+
ymm0_floats = dbg.registers.ymm0.f32 # Access YMM0 as an array of 32-bit floats
|
|
136
|
+
|
|
137
|
+
print(f"[+] Halted at RIP: 0x{rip:x}")
|
|
138
|
+
print(f"[+] Stack pointer value: 0x{rsp_val:x}")
|
|
139
|
+
print(f"[+] YMM0 state: {ymm0_floats}")
|
|
140
|
+
|
|
141
|
+
# 5. Clean up - kill the process
|
|
142
|
+
dbg.control.kill_process()
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Limitations
|
|
146
|
+
|
|
147
|
+
- Supported exclusively on Linux ELF binaries running on `x86-64`.
|
|
148
|
+
- Relies on the `ptrace` system call and the `/proc` filesystem. It will not function in hardened environments where these features are disabled.
|
|
149
|
+
|
|
150
|
+
## Testing
|
|
151
|
+
|
|
152
|
+
The repository includes a suite of integration tests that run against provided pre-compiled C binaries to verify register states, memory reading, and edge cases.
|
|
153
|
+
|
|
154
|
+
To run the tests:
|
|
155
|
+
```bash
|
|
156
|
+
pytest test/
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
*Note: If you wish to rebuild the test executables from source, a `Makefile` is provided in `test/executables/`. Rebuilding may cause certain tests to fail if the compiler generates different instruction offsets.*
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
pyx64dbg-0.1.0/README.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# PyX64Dbg
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
**PyX64Dbg** is a Python-based debugger for x86-64 Linux binaries.
|
|
8
|
+
|
|
9
|
+
PyX64Dbg utilizes the Linux `ptrace` system call and the `/proc` filesystem (`procfs`) to trace and introspect ELF processes. These low-level operating system primitives are abstracted into an intuitive Python object model, enabling direct manipulation of process memory, CPU registers, and execution flow.
|
|
10
|
+
|
|
11
|
+
The tool features through three primary interfaces: a **Python API** designed for automated reverse engineering and binary analysis, a **Graphical User Interface (GUI)** for visual debugging, and a robust **IPython-based CLI** for debugging from the terminal.
|
|
12
|
+
|
|
13
|
+
## Key Features
|
|
14
|
+
|
|
15
|
+
- **Python API:** Automate reverse engineering, exploit development, or testing using a clean, object-oriented interface. Unlike GDB, PyX64Dbg acts as a standard Python library you can import and use anywhere.
|
|
16
|
+
- **Graphical Interface (GUI):** Built with PySide6, featuring disassembly views, memory watches, register panels, and an embedded interactive terminal.
|
|
17
|
+
- **Command Line Interface (CLI):** An interactive IPython REPL that supports live Python syntax, auto-completion, and inline evaluation.
|
|
18
|
+
- **Advanced Target Support:** Native handling of PIE (Position Independent Executables), ASLR, shared libraries (`ld.so`), and dynamic symbols.
|
|
19
|
+
- **C-Like Type System:** A custom extension providing native types (`Int32`, `UInt64`, `Float80`, etc.) that strictly follow C promotion, overflow, and truncation rules.
|
|
20
|
+
- **Extended Registers (AVX/SSE):** Supports CPU `xstate`, including `XMM`, `YMM`, and FPU (`st`) vector registers. The API allows you to seamlessly treat vector data as a C-style union across all possible integer and floating-point array representations.
|
|
21
|
+
|
|
22
|
+
## Prerequisites
|
|
23
|
+
|
|
24
|
+
- **Operating System**: Linux (x86-64 architecture only)
|
|
25
|
+
- **Python**: 3.10 or later
|
|
26
|
+
- **C++ Compiler**: A C++20 compatible compiler (e.g., `g++` or `clang`) and Python development headers are required to compile the `ptrace` and numeric type extensions during installation.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
### From PyPI (Recommended)
|
|
31
|
+
```bash
|
|
32
|
+
pip install pyx64dbg
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### From Source (Development)
|
|
36
|
+
Clone the repository and install it in editable mode:
|
|
37
|
+
```bash
|
|
38
|
+
git clone https://github.com/yoav-shamay/pyx64dbg.git
|
|
39
|
+
cd pyx64dbg
|
|
40
|
+
pip install -e .
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
### Graphical Interface (GUI)
|
|
46
|
+
Start the visual debugger (requires a desktop session like X11 or Wayland):
|
|
47
|
+
```bash
|
|
48
|
+
pyx64dbg-gui
|
|
49
|
+
```
|
|
50
|
+
*Tip: The full IPython CLI is embedded directly into the GUI and is available via the "Interactive Console" tab at the bottom.*
|
|
51
|
+
|
|
52
|
+
### Command Line Interface (CLI)
|
|
53
|
+
Launch the interactive IPython console:
|
|
54
|
+
```bash
|
|
55
|
+
pyx64dbg [/path/to/binary]
|
|
56
|
+
```
|
|
57
|
+
Once inside, simply type `help` to see a list of available commands and aliases (e.g., `run`, `step`, `bps`, `dis`).
|
|
58
|
+
|
|
59
|
+
## Python API Showcase
|
|
60
|
+
|
|
61
|
+
PyX64Dbg is built to be scripted. You can easily interact with binaries directly from Python.
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from pyx64dbg import Debugger
|
|
65
|
+
from pyx64dbg.number_types import UInt64
|
|
66
|
+
|
|
67
|
+
# 1. Spawn process and attach debugger
|
|
68
|
+
dbg = Debugger.start_and_debug("./target_binary")
|
|
69
|
+
|
|
70
|
+
# 2. Set a breakpoint at the 'main' function
|
|
71
|
+
main_addr = dbg.symbols["main"]
|
|
72
|
+
dbg.breakpoints.add_breakpoint(main_addr)
|
|
73
|
+
|
|
74
|
+
# 3. Run until the breakpoint is hit
|
|
75
|
+
dbg.control.continue_execution()
|
|
76
|
+
|
|
77
|
+
# 4. Read memory and native vector registers
|
|
78
|
+
rip = dbg.registers.rip
|
|
79
|
+
rsp_val = dbg.memory.read_number(dbg.registers.rsp, UInt64)
|
|
80
|
+
ymm0_floats = dbg.registers.ymm0.f32 # Access YMM0 as an array of 32-bit floats
|
|
81
|
+
|
|
82
|
+
print(f"[+] Halted at RIP: 0x{rip:x}")
|
|
83
|
+
print(f"[+] Stack pointer value: 0x{rsp_val:x}")
|
|
84
|
+
print(f"[+] YMM0 state: {ymm0_floats}")
|
|
85
|
+
|
|
86
|
+
# 5. Clean up - kill the process
|
|
87
|
+
dbg.control.kill_process()
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Limitations
|
|
91
|
+
|
|
92
|
+
- Supported exclusively on Linux ELF binaries running on `x86-64`.
|
|
93
|
+
- Relies on the `ptrace` system call and the `/proc` filesystem. It will not function in hardened environments where these features are disabled.
|
|
94
|
+
|
|
95
|
+
## Testing
|
|
96
|
+
|
|
97
|
+
The repository includes a suite of integration tests that run against provided pre-compiled C binaries to verify register states, memory reading, and edge cases.
|
|
98
|
+
|
|
99
|
+
To run the tests:
|
|
100
|
+
```bash
|
|
101
|
+
pytest test/
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
*Note: If you wish to rebuild the test executables from source, a `Makefile` is provided in `test/executables/`. Rebuilding may cause certain tests to fail if the compiler generates different instruction offsets.*
|
|
105
|
+
|
|
106
|
+
## License
|
|
107
|
+
|
|
108
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools", "wheel", "pybind11"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pyx64dbg"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A debugger implemented in Python"
|
|
9
|
+
authors = [
|
|
10
|
+
{ name = "Yoav Shamay", email = "yoavsh97@gmail.com" }
|
|
11
|
+
]
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
license = { file = "LICENSE" }
|
|
14
|
+
requires-python = ">=3.10"
|
|
15
|
+
dependencies = ["capstone", "pyelftools", "ipython", "prompt_toolkit", "pyside6", "nest_asyncio"]
|
|
16
|
+
keywords = ["debugger", "ptrace", "x86-64", "linux"]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Operating System :: POSIX :: Linux",
|
|
19
|
+
"Development Status :: 3 - Alpha",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"License :: OSI Approved :: MIT License",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Programming Language :: Python :: 3.14",
|
|
28
|
+
"Topic :: Software Development :: Debuggers"
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://github.com/yoav-shamay/pyx64dbg"
|
|
33
|
+
Repository = "https://github.com/yoav-shamay/pyx64dbg"
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
dev = ["black", "jinja2", "pytest"]
|
|
37
|
+
|
|
38
|
+
[project.scripts]
|
|
39
|
+
pyx64dbg = "pyx64dbg.CLI.main:main"
|
|
40
|
+
pyx64dbg-gui = "pyx64dbg.GUI.main:main"
|
|
41
|
+
|
|
42
|
+
[tool.setuptools.package-data]
|
|
43
|
+
# Include type stubs, the py.typed marker, and all GUI web/styling assets
|
|
44
|
+
"pyx64dbg" = ["py.typed", "**/*.pyi"]
|
|
45
|
+
"pyx64dbg.GUI" = ["pty_view/*", "styles/*.qss", "assets/*"]
|
|
File without changes
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from IPython.terminal.embed import InteractiveShellEmbed
|
|
4
|
+
from IPython.terminal.prompts import Prompts, Token
|
|
5
|
+
from pyx64dbg.interactive_console.interactive_console import InteractiveConsole, banner
|
|
6
|
+
import atexit
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
class ConsolePrompt(Prompts):
|
|
10
|
+
"""
|
|
11
|
+
An implementation of the IPython Prompts class to define a custom prompt for our interactive console.
|
|
12
|
+
We want to show "PyX64Dbg> " as the prompt for our console.
|
|
13
|
+
"""
|
|
14
|
+
def in_prompt_tokens(self, cli=None):
|
|
15
|
+
"""
|
|
16
|
+
Override of the in_prompt_tokens method to return our custom prompt.
|
|
17
|
+
"""
|
|
18
|
+
return [(Token.Prompt, "PyX64Dbg> ")]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class IPythonCLI:
|
|
22
|
+
"""
|
|
23
|
+
A class that manages the IPython CLI for the debugger.
|
|
24
|
+
Uses the InteractiveConsole class to manage the console state, and uses IPython for the shell itself.
|
|
25
|
+
"""
|
|
26
|
+
def __init__(self, file_name: Optional[str] = None, verbose: bool = False, use_external_pty: bool = False) -> None:
|
|
27
|
+
self._verbose: bool = verbose
|
|
28
|
+
# create the interactive console object. We want stdio to appear in the terminal, so we don't redirect it to a PTY.
|
|
29
|
+
self.interactive_console = InteractiveConsole(
|
|
30
|
+
file_name,
|
|
31
|
+
redirect_stdio_to_pty=use_external_pty,
|
|
32
|
+
disable_pty_echo=False, # if we are using an external PTY, we don't disable the echo as we want to see what we are typing
|
|
33
|
+
)
|
|
34
|
+
# register our callbacks for updating aliases
|
|
35
|
+
self.interactive_console.update_aliases_callbacks.add(self._refresh_aliases)
|
|
36
|
+
|
|
37
|
+
def _refresh_aliases(self, aliases: dict[str, object]) -> None:
|
|
38
|
+
"""
|
|
39
|
+
The callback for refreshing the aliases in the interactive console.
|
|
40
|
+
Moves the aliases to the IPython shell's user namespace so that they are accessible to the user.
|
|
41
|
+
"""
|
|
42
|
+
self.shell.push(aliases)
|
|
43
|
+
|
|
44
|
+
def _show_simple_error(
|
|
45
|
+
self,
|
|
46
|
+
exc_tuple=None,
|
|
47
|
+
filename=None,
|
|
48
|
+
tb=None,
|
|
49
|
+
tb_offset=None,
|
|
50
|
+
exception_only=False,
|
|
51
|
+
running_compiled_code=False,
|
|
52
|
+
):
|
|
53
|
+
"""
|
|
54
|
+
Custom error handler to show only the exception type and message without the full traceback.
|
|
55
|
+
This is in order to simplify the error output for the user.
|
|
56
|
+
"""
|
|
57
|
+
# if we are not provided exc_tuple, take it from sys.exc_info() to get the current exception
|
|
58
|
+
if exc_tuple is not None:
|
|
59
|
+
exc_type, exc_value, _ = exc_tuple
|
|
60
|
+
else:
|
|
61
|
+
exc_type, exc_value, _ = sys.exc_info()
|
|
62
|
+
# use the console printing error message with the name of the exception class and its msg
|
|
63
|
+
self.interactive_console.print_error(exc_type.__name__, exc_value)
|
|
64
|
+
|
|
65
|
+
def start_console(self) -> None:
|
|
66
|
+
"""
|
|
67
|
+
Starts the IPython interactive console.
|
|
68
|
+
"""
|
|
69
|
+
atexit.register(self.interactive_console.handle_exit) # register the console exit handler using atexit
|
|
70
|
+
# create the InteractiveShellEmbed object for the console, with linux colors and no banner (we have our own banner that we print separately)
|
|
71
|
+
self.shell = InteractiveShellEmbed(colors="linux", display_banner=False)
|
|
72
|
+
# define custom prompt (PyX64Dbg>) for the console
|
|
73
|
+
self.shell.prompts = ConsolePrompt(self.shell)
|
|
74
|
+
# if verbose mode is disabled, use the custom simple error handler that shows reduced error information to simplify console output
|
|
75
|
+
if not self._verbose:
|
|
76
|
+
self.shell.showtraceback = self._show_simple_error
|
|
77
|
+
# allow to call functions without parentheses, e. g. "s" instead of "s()"
|
|
78
|
+
self.shell.autocall = 2
|
|
79
|
+
# Disable the kernel from printing the autocall expansion to keep the CLI cleaner
|
|
80
|
+
self.shell.show_rewritten_input = False
|
|
81
|
+
print(banner, end='') # banner already has a newline at the end
|
|
82
|
+
# start the shell with the initial aliases from the interactive console
|
|
83
|
+
self.shell(local_ns=self.interactive_console.get_aliases())
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The entry point for the CLI tool.
|
|
3
|
+
Parses command line arguments and starts the IPython CLI for the debugger.
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
import argparse
|
|
7
|
+
from pyx64dbg.CLI.ipython_cli import IPythonCLI
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def parse_arguments() -> argparse.Namespace:
|
|
11
|
+
"""
|
|
12
|
+
Parses the command line arguments for the CLI tool.
|
|
13
|
+
Returns an argparse.Namespace object containing the parsed arguments.
|
|
14
|
+
"""
|
|
15
|
+
parser = argparse.ArgumentParser(prog='pyx64dbg',
|
|
16
|
+
description='A debugger for x64 Linux binaries, written in Python')
|
|
17
|
+
# optional filename argument
|
|
18
|
+
parser.add_argument("filename", nargs="?", default=None, help="The file to debug")
|
|
19
|
+
# verbose option (full tracebacks)
|
|
20
|
+
parser.add_argument("-v", "--verbose", action="store_true", help="Print verbose output in case of errors, including full traceback")
|
|
21
|
+
args = parser.parse_args()
|
|
22
|
+
return args
|
|
23
|
+
|
|
24
|
+
def main():
|
|
25
|
+
"""
|
|
26
|
+
The entry point for the CLI tool.
|
|
27
|
+
"""
|
|
28
|
+
args = parse_arguments()
|
|
29
|
+
file_name = args.filename
|
|
30
|
+
console = IPythonCLI(file_name, verbose=args.verbose)
|
|
31
|
+
console.start_console()
|
|
32
|
+
|
|
33
|
+
if __name__ == "__main__":
|
|
34
|
+
main()
|
|
File without changes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
2
|
+
<!-- Refined Handle - Slightly larger, still anchored to boundary -->
|
|
3
|
+
<rect x="78.3" y="78.3" width="18" height="7" transform="rotate(45 78.3 78.3)" fill="black" rx="3.5" />
|
|
4
|
+
|
|
5
|
+
<!-- Centered Magnifying Glass Frame -->
|
|
6
|
+
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="2.5" fill="none" />
|
|
7
|
+
|
|
8
|
+
<!-- Organic Bug Design - Centered and contained -->
|
|
9
|
+
<g transform="translate(50, 46) scale(1.1)" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
10
|
+
<!-- Hollow Head -->
|
|
11
|
+
<path d="M -5.5,-8.5 C -7,-17 7,-17 5.5,-8.5" />
|
|
12
|
+
|
|
13
|
+
<!-- Antennae -->
|
|
14
|
+
<path d="M -2.5,-14 C -4,-18 -7,-19 -9,-18" />
|
|
15
|
+
<path d="M 2.5,-14 C 4,-18 7,-19 9,-18" />
|
|
16
|
+
|
|
17
|
+
<!-- Natural Curved Body -->
|
|
18
|
+
<path d="M -5.5,-8.5
|
|
19
|
+
C -10,-8.5 -13,0 -11,8
|
|
20
|
+
C -9,18 -5,26 0,26
|
|
21
|
+
C 5,26 9,18 11,8
|
|
22
|
+
C 13,0 10,-8.5 5.5,-8.5
|
|
23
|
+
Z" />
|
|
24
|
+
|
|
25
|
+
<!-- Curved Wing Split -->
|
|
26
|
+
<path d="M 0,-8.5 Q 0,10 0,26" stroke-width="1.2" />
|
|
27
|
+
|
|
28
|
+
<!-- Organic Curved Legs -->
|
|
29
|
+
<path d="M -9,0 C -13,-2 -15,0 -16,4" />
|
|
30
|
+
<path d="M 9,0 C 13,-2 15,0 16,4" />
|
|
31
|
+
|
|
32
|
+
<path d="M -11,9 C -15,9 -17,13 -17,17" />
|
|
33
|
+
<path d="M 11,9 C 15,9 17,13 17,17" />
|
|
34
|
+
|
|
35
|
+
<path d="M -9,18 C -11,21 -12,27 -11,31" />
|
|
36
|
+
<path d="M 9,18 C 11,21 12,27 11,31" />
|
|
37
|
+
</g>
|
|
38
|
+
</svg>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import asyncio
|
|
3
|
+
from functools import wraps
|
|
4
|
+
from typing import Any, Callable, ParamSpec, Awaitable
|
|
5
|
+
|
|
6
|
+
P = ParamSpec("P") # parameter specifications of the callables
|
|
7
|
+
|
|
8
|
+
# save a reference to all background tasks created so they aren't discarded by the garbage collecotr.
|
|
9
|
+
background_tasks: set[asyncio.Task[Any]] = set()
|
|
10
|
+
|
|
11
|
+
def async_slot(func: Callable[P, Awaitable[Any]]) -> Callable[P, None]:
|
|
12
|
+
"""
|
|
13
|
+
Decorator to connect async methods to standard Qt signals.
|
|
14
|
+
Automatically schedules the coroutine on the active asyncio event loop.
|
|
15
|
+
"""
|
|
16
|
+
# define the wrapper function
|
|
17
|
+
@wraps(func)
|
|
18
|
+
def wrapper(*args: P.args, **kwargs: P.kwargs):
|
|
19
|
+
# Catch any arguments the signal emits and pass them to the async function
|
|
20
|
+
task = asyncio.create_task(func(*args, **kwargs))
|
|
21
|
+
# save a reference to the task to prevent it from getting garbage collected, and remove it once the task is done
|
|
22
|
+
background_tasks.add(task)
|
|
23
|
+
task.add_done_callback(background_tasks.discard)
|
|
24
|
+
|
|
25
|
+
return wrapper
|