forked from libdebug/libdebug
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request libdebug#136 from libdebug/dev
Dev
- Loading branch information
Showing
406 changed files
with
14,258 additions
and
12,439 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -123,6 +123,7 @@ venv.bak/ | |
|
||
# mkdocs documentation | ||
/site | ||
docs/from_pydoc/ | ||
|
||
# mypy | ||
.mypy_cache/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
--- | ||
icon: material/queue-first-in-last-out | ||
search: | ||
boost: 4 | ||
--- | ||
# :material-queue-first-in-last-out: Default VS ASAP Mode | ||
For most commands that can be issued in **libdebug**, it is necessary that the traced process stops running. When the traced process stops running as a result of a [stopping event](../../stopping_events/stopping_events), **libdebug** can inspect the state and intervene in its control flow. When one of these commands is used in the script as the process is still running, **libdebug** will wait for the process to stop before executing the command. | ||
|
||
In the following example, the content of the `RAX` register is printed after the program hits the breakpoint or stops for any other reason: | ||
|
||
```python | ||
from libdebug import debugger | ||
|
||
d = debugger("program") | ||
d.run() | ||
|
||
d.breakpoint("func") | ||
|
||
d.cont() | ||
|
||
print(f"RAX: {hex(d.regs.rax)}") | ||
``` | ||
|
||
!!! INFO "Script execution" | ||
Please note that, after resuming execution of the tracee process, the script will continue to run. This means that the script will not wait for the process to stop before continuing with the rest of the script. If the next command is a **libdebug** command that requires the process to be stopped, the script will then wait for a [stopping event](../../stopping_events/stopping_events) before executing that command. | ||
|
||
In the following example, we make a similar scenario, but show how you can inspect the state of the process by arbitrarily stopping it in the default mode. | ||
|
||
```python | ||
d = debugger("program") | ||
|
||
d.run() | ||
|
||
d.breakpoint("func") | ||
|
||
d.cont() | ||
|
||
print(f"RAX: {hex(d.regs.rax)}") # (1) | ||
|
||
d.cont() | ||
d.interrupt() # (2) | ||
|
||
print(f"RAX: {hex(d.regs.rax)}") # (3) | ||
|
||
d.cont() | ||
|
||
[...] | ||
``` | ||
|
||
1. This is the value of RAX at the breakpoint. | ||
2. Stop the process shortly after the process resumes. | ||
3. This is the value of RAX at the arbitrary stop (shortly after the breakpoint). | ||
|
||
## :material-run-fast: ASAP Mode | ||
If you want the command to be executed As Soon As Possible (ASAP) instead of waiting for a [stopping event](../../stopping_events/stopping_events), you can specify it when creating the [Debugger](../../from_pydoc/generated/debugger/debugger/) object. In this mode, the debugger will stop the process and issue the command as it runs your script without waiting. The following script has the same behavior as the previous one, using the corresponding option: | ||
|
||
```python | ||
d = debugger("program", auto_interrupt_on_command=True) | ||
|
||
d.run() | ||
|
||
d.breakpoint("func") | ||
|
||
d.cont() | ||
d.wait() | ||
|
||
print(f"RAX: {hex(d.regs.rax)}") # (1) | ||
|
||
d.cont() | ||
|
||
print(f"RAX: {hex(d.regs.rax)}") # (2) | ||
|
||
d.cont() | ||
|
||
[...] | ||
``` | ||
|
||
1. This is the value of RAX at the breakpoint. | ||
2. This is the value of RAX shortly after the breakpoint. The process is forcibly stopped to read the register. | ||
|
||
For the sake of this example the `wait()` method is used to wait for the [stopping event](../../stopping_events/stopping_events) (in this case, a breakpoint). This enforces the syncronization of the execution to the stopping point that we want to reach. Read more about the `wait()` method in the section dedicated to [control flow](../control_flow) commands. | ||
|
||
!!! TIP "Pwning with **libdebug**" | ||
Respectable pwners in the field find that the ASAP polling mode is particularly useful when writing exploits. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
--- | ||
icon: material/arrow-down-right | ||
search: | ||
boost: 4 | ||
--- | ||
# :material-arrow-down-right: Control Flow Commands | ||
|
||
Control flow commands allow you to set step through the code, stop execution and resume it at your pleasure. | ||
|
||
## :material-ray-end-arrow: Stepping | ||
A basic feature of any debugger is the ability to step through the code. **libdebug** provides several methods to step, some of which will be familiar to users of other debuggers. | ||
|
||
### :material-debug-step-into: Single Step | ||
The `step()` command executes the instruction at the instruction pointer and stops the process. When possible, it uses the hardware single-step feature of the CPU for better performance. | ||
|
||
!!! ABSTRACT "Function Signature" | ||
```python | ||
d.step() | ||
``` | ||
|
||
### :material-debug-step-over: Next | ||
The `next()` command executes the current instruction at the instruction pointer and stops the process. If the instruction is a function call, it will execute the whole function and stop at the instruction following the call. In other debuggers, this command is known as "step over". | ||
|
||
Please note that the `next()` command resumes the execution of the program if the instruction is a function call. This means that the debugger can encounter [stopping events](../../stopping_events/stopping_events) in the middle of the function, causing the command to return before the function finishes. | ||
|
||
!!! ABSTRACT "Function Signature" | ||
```python | ||
d.next() | ||
``` | ||
|
||
!!! WARNING "Damn heuristics!" | ||
The `next()` command uses heuristics to determine if the instruction is a function call and to find the stopping point. This means that the command may not work as expected in some cases (e.g. functions called with a jump, non-returning calls). | ||
|
||
### :material-debug-step-over::material-debug-step-over: Step Until | ||
|
||
The `step_until()` command executes single steps until a specific address is reached. Optionally, you can also limit steps to a maximum count (default value is -1, meaning no limit). | ||
|
||
!!! ABSTRACT "Function Signature" | ||
```python | ||
d.step_until(position, max_steps=-1, file='hybrid') | ||
``` | ||
|
||
The file parameter can be used to specify the choice on relative addressing. Refer to the [memory access](../memory_access/#absolute-and-relative-addressing) section for more information on addressing modes. | ||
|
||
## :material-step-forward: Continuing | ||
|
||
The `cont()` command continues the execution. | ||
|
||
!!! ABSTRACT "Function Signature" | ||
```python | ||
d.cont() | ||
``` | ||
|
||
For example, in the following script, **libdebug** will not wait for the process to stop before checking d.dead. To change this behavior, you can use the `wait()` command right after the `cont()`. | ||
```python | ||
from libdebug import debugger | ||
|
||
d = debugger("program_that_dies_tragically") | ||
|
||
d.run() | ||
|
||
d.cont() | ||
|
||
if d.dead: | ||
print("The program is dead!") | ||
|
||
``` | ||
|
||
### :material-clock-alert-outline: The `wait()` Method | ||
|
||
The `wait()` command is likely the most important in **libdebug**. Loved by most and hated by many, it instructs the debugger to wait for a [stopping event](../../stopping_events/stopping_events) before continuing with the execution of the script. | ||
|
||
!!! ABSTRACT "Example" | ||
In the following script, **libdebug** will wait for the process to stop before printing "provola". | ||
```python | ||
from libdebug import debugger | ||
|
||
d = debugger("program_that_dies_tragically") | ||
|
||
d.run() | ||
|
||
d.cont() | ||
d.wait() | ||
|
||
print("provola") | ||
``` | ||
|
||
### :material-stop: Interrupt | ||
You can manually issue a stopping signal to the program using the `interrupt()` command. Clearly, this command is issued as soon as it is executed within the script. | ||
|
||
!!! ABSTRACT "Function Signature" | ||
```python | ||
d.interrupt() | ||
``` | ||
|
||
## :material-debug-step-out: Finish | ||
|
||
The `finish()` command continues execution until the current function returns or a breakpoint is hit. In other debuggers, this command is known as "step out". | ||
|
||
!!! ABSTRACT "Function Signature" | ||
```python | ||
d.finish(heuristic='backtrace') | ||
``` | ||
|
||
!!! WARNING "Damn heuristics!" | ||
The `finish()` command uses heuristics to determine the end of a function. While **libdebug** allows to choose the heuristic, it is possible that none of the available options work in some specific cases. (e.g. tail-calls, non-returning calls). | ||
|
||
### Available Heuristics | ||
The `finish()` command allows you to choose the heuristic to use. If you don't specify any, the `"backtrace"` heuristic will be used. The following heuristics are available: | ||
|
||
| Heuristic | Description | | ||
|-----------|-------------| | ||
| `backtrace` | The `backtrace` heuristic uses the return address on the function stack frame to determine the end of the function. This is the default heuristic but may fail in case of broken stack, rare execution flows, and obscure compiler optimizations. | | ||
| `step-mode` | The `step-mode` heuristic uses repeated single steps to execute instructions until a `ret` instruction is reached. Nested calls are handled, when the calling convention is respected. This heuristic is slower and may fail in case of rare execution flows and obscure compiler optimizations. | |
Oops, something went wrong.