mirror of https://github.com/pwndbg/pwndbg.git
Fixes piebase and breakrva on remote debugging (#500)
Three things here: 1. This fixes `piebase` and `breakrva` commands - a bug with remote targets mentioned in https://github.com/pwndbg/pwndbg/issues/488#issuecomment-403213457. 2. It also adds a check if result address is still in the memory pages belonging to the given module. This works now as: ``` pwndbg> breakrva main Offset 0x555555554601 rebased to module /home/dc/pwndbg_bug/a.out as 0xaaaaaaaa8601 is beyond module's memory pages: 0x555555554000 0x555555555000 r-xp 1000 0 /home/dc/pwndbg_bug/a.out 0x555555754000 0x555555755000 r--p 1000 0 /home/dc/pwndbg_bug/a.out 0x555555755000 0x555555756000 rw-p 1000 1000 /home/dc/pwndbg_bug/a.out ``` 3. It gives a better output for `piebase`: ``` pwndbg> piebase 1 Calculated VA from /home/dc/pwndbg_bug/a.out = 0x555555554001 ``` --- To reproduce the fixed bug, launch any binary on a gdbserver: ``` gdbserver 127.0.0.1:4444 ./a.out ``` Then start a debugging session: ``` gdb -q -ex 'target remote 127.0.0.1:4444' ./a.out ``` and fire e.g. `breakrva 123`. --- Below you can see the bug case and explanation why it occured: ``` pwndbg> breakrva 1 There are no mappings for specified address or module. 'breakrva': Break at RVA from PIE base. Traceback (most recent call last): File "/home/dc/pwndbg/pwndbg/commands/__init__.py", line 109, in __call__ return self.function(*args, **kwargs) File "/home/dc/pwndbg/pwndbg/commands/__init__.py", line 200, in _OnlyWhenRunning return function(*a, **kw) File "/home/dc/pwndbg/pwndbg/commands/pie.py", line 61, in breakrva spec = "*%#x" % (addr) TypeError: %x format: an integer is required, not NoneType ``` So what is the issue here? 1. We have the same logic in both `piebase` and `breakrva` - if the user doesn't specify second argument - a module name - we retrieve it with `get_exe_name`: ```python def breakrva(offset=None, module=None): offset = int(offset) if not module: module = get_exe_name() addr = translate_addr(offset, module) spec = "*%#x" % (addr) # [ ... - some more code, not important here ] ``` 2. The `get_exe_name` returns just `pwndbg.auxv.get().get('AT_EXECFN', pwndbg.proc.exe)`. The difference is important here. On the case shown above the `pwndbg.auxv.get()['AT_EXECFN']` returns `./a.out` while `pwndbg.proc.exe` returns the full path: `/home/dc/pwndbg_bug/a.out`. 3. This `module` is then passed to `translate_addr` as can be seen on the code above. 4. The `translate_addr` tries to retrieve memory page (`Page` instance) which belongs to the module: ```python def translate_addr(offset, module): mod_filter = lambda page: module in page.objfile pages = list(filter(mod_filter, pwndbg.vmmap.get())) if not pages: print('There are no mappings for specified address or module.') return # [ ... - some more code, not important here ] ``` 5. The `translate_addr` returns `None` because the `page.objfile` for e.g. binary objfile returns its full path as can be seen below: ``` (Pdb) pwndbg.vmmap.get()[0].objfile '/home/dc/pwndbg_bug/a.out' ``` 6. Because we returned `None`, the `spec = "*%#x" % (addr)` string formatting for breakrva or `print(hex(addr))` for piebase fails.pull/502/head
parent
b392843d9f
commit
33a5c2720f
Loading…
Reference in new issue