This commit enhances the heap commands UX for statically linked binaries
and removes typeinfo module bloat.
The typeinfo module had this typeinfo.load function that was looking up a given type.
If it didn't find the type, it fallbacked to compiling many many system
headers in order to add a symbol for a given type into the program. This was
supposed to be used for missing glibc malloc symbols like malloc_chunk.
However, the exact reason it was used: the struct malloc_chunk was never
defined in a header file and was always defined in a malloc.c or another
.c file in glibc sources.
Another place the typeinfo.load logic of compiling headers was/is used
is the `dt` command, which is a windbg alias for getting struct layout
type information, e.g.:
```
pwndbg> dt 'struct malloc_chunk'
struct malloc_chunk
+0x0000 mchunk_prev_size : size_t
+0x0008 mchunk_size : size_t
+0x0010 fd : struct malloc_chunk *
+0x0018 bk : struct malloc_chunk *
+0x0020 fd_nextsize : struct malloc_chunk *
+0x0028 bk_nextsize : struct malloc_chunk *
pwndbg>
```
However, the whole big issue with typeinfo.load compilation of headers
was that most of the time it didn't work because e.g. some headers
defined in other paths were missing or that two different headers used
the same struct/function name and the compilation failed.
Since this logic almost never gave good results, I am removing it.
Regarding UX for statically linked binaries: we use `info dll` command
to see if a binary is statically linked. While this method is not
robust, as it may give us wrong results if the statically linked binary
used `dlopen(...)` it is probably good enough.
Now, if a heap related command is executed on statically linked binaries, it
will inform the user and set the resolving of libc heap symbols via
heuristics. Then, it also says to the user they have to set the glibc
version and re-run the command.
This commit tries to fix the issue of our `set context-clear-screen on`
option resetting the scrollback buffer on some terminals like
gnome-terminal (fwiw it did not happen on terminator or on tmux).
It also adds info to tips about that option.
Turns out the mprotect command didn't ever work, as it was amd64 only, but used x86 syscall numbers to call mprotect. I have refactored the command to use shellcraft to generate the shellcode that calls mprotect. I have also unit-tested this command.
Fixes the `nextproginst` command and adds two simple tests for it.
The command had two following issues:
1) It assumed that the program vmmap was always the first vmmap with
proc.exe objfile name -- this assumption has two flaws. First, newer
linkers will create the first memory page for the binary file as
read-only. This is because you do not need the ELF header content to be
executable, and that was the case in old linkers or linux distributions.
As an example, see those vmmap from a simple hello world binary compiled
on Ubuntu 18.04 vs Ubuntu 22.04:
Ubuntu 18.04:
```
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x555555554000 0x555555555000 r-xp 1000 0 /home/dc/a.out
0x555555754000 0x555555755000 r--p 1000 0 /home/dc/a.out
0x555555755000 0x555555756000 rw-p 1000 1000 /home/dc/a.out
[...]
```
Ubuntu 22.04:
```
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x555555554000 0x555555555000 r--p 1000 0 /home/user/a.out
0x555555555000 0x555555556000 r-xp 1000 1000 /home/user/a.out
0x555555556000 0x555555557000 r--p 1000 2000 /home/user/a.out
0x555555557000 0x555555558000 r--p 1000 2000 /home/user/a.out
0x555555558000 0x555555559000 rw-p 1000 3000 /home/user/a.out
```
So, before this commit on Ubuntu 22.04 we ended up taking the first
vmmap which was non-executable and we compared the program counter
register against it after each instruction step executed by the
nextproginstr command. As a result, we ended up never getting back to
the user and just finishing the debugged program this way!
Now, after this commit, we will grab only and all the executable pages for
the binary that we debug and compare and compare against them.
2) The second problem was that we printed out the current Pwndbg context
after executing nextproginstr succesfully. This does not seem to make
much sense because the context should be printed by the prompt hook.
(Without removing this, we ended up printing the context twice)
* add patch command
This commit adds the `patch`, `patch_list` and `patch_revert` commands
and adds the `pwntools==4.8.0` as Pwndbg dependency.
The current implementation could be further improved by:
- adding tests :)
- maybe moving `patch_list` and `patch_revert` to `patch --list` and
`patch --revert` flags?
- better handling of incorrect args/pwnlib exceptions
* lint
* Improve vmmap on coredump files
With this commit we now recognize coredumps better and also finally have
a simple test for vmmap commands on:
- a running binary
- on a loaded coredump file with loaded binary
- on a loaded coredump file without a loaded binary
We also stop saving vmmaps for `maintenance info sections` sections
which have a start address of 0x0. While there could potentially be a
coredump file from a binary with start=0x0, this should work in most
cases.
We could in theory do a slighty better: we could take the vmmap at 0 and
try to read memory from it. However, I am not sure if it is a good idea
to try such memory read?
* remove unused import
* add missing crash_simple.asm
* fix vmmap coredump test on different ubuntu mem layouts
* use /proc/$pid/maps for vmmap tests
* fix formatting
* fix import
* fix test
* fix test
* fix test
* fix lint
* fix test
* fix test
* fix test
* fix test
* fix lint
* another fixup for ubuntu 22.04
* another fixup for ubuntu 22.04
* lint
* Add a regression test for find_fake_fast
The test program creates a fake chunk size field in its .data section
with a set NON_MAIN_ARENA flag. The Python test runs the find_fake_fast
command on an address succeeding the fake chunk. A gdb.MemoryError
indicates regression - issue #1142
* Make linter happy
Call fetch_lazy() on the gdb.Value acquired in get_heap() and wrap it in
a try/except block. Return None if gdb.MemoryError is raised.
Let get_arena_for_chunk() handle None returned by get_heap().
Fixes#1142