Skip to content
Permalink
Browse files

Merge dev to beta (#506)

* Fixes `u` command `module object is not callable` (#311)

pwndbg> u 0x404030
'u': Starting at the specified address, disassemble
    N instructions (default 5).
Traceback (most recent call last):
  File "/home/dc/installed/pwndbg/pwndbg/commands/__init__.py", line 99, in __call__
    return self.function(*args, **kwargs)
  File "/home/dc/installed/pwndbg/pwndbg/commands/__init__.py", line 191, in _OnlyWhenRunning
    return function(*a, **kw)
  File "/home/dc/installed/pwndbg/pwndbg/commands/windbg.py", line 292, in u
    pwndbg.commands.nearpc(where, n)
TypeError: 'module' object is not callable

* refactored wrapper (#280)

* added command got to display status of the got table

Signed-off-by: degrigis <degrigis@gmail.com>

* return when checksec is not available and added decorator OnlyWhenRunning

Signed-off-by: degrigis <degrigis@gmail.com>

* removed duplicated code for pie and not pie binaries

Signed-off-by: degrigis <degrigis@gmail.com>

* inserted support function to get checksec output and performed all requirements check initially

Signed-off-by: degrigis <degrigis@gmail.com>

* corrected typo

Signed-off-by: degrigis <degrigis@gmail.com>

* reorganized the command got splitting the code in library routines and moved the checksec internal function in a separate module

Signed-off-by: degrigis <degrigis@gmail.com>

* handled exception directly inside functions and enhanced code

Signed-off-by: degrigis <degrigis@gmail.com>

* extracted only column in readelf output and enhanced exception handling

Signed-off-by: degrigis <degrigis@gmail.com>

* fix exception handling returning subprocess error

Signed-off-by: degrigis <degrigis@gmail.com>

* removed unused import and reordered

Signed-off-by: degrigis <degrigis@gmail.com>

* reordered imports

Signed-off-by: degrigis <degrigis@gmail.com>

* added wrappers module and refactored some code

Signed-off-by: degrigis <degrigis@gmail.com>

* removed not useful comment

Signed-off-by: degrigis <degrigis@gmail.com>

* removed unused import

Signed-off-by: degrigis <degrigis@gmail.com>

* moved comments in docstring

Signed-off-by: degrigis <degrigis@gmail.com>

* refactored code to use partial functions, simplified code

Signed-off-by: degrigis <degrigis@gmail.com>

* simplified a loc

Signed-off-by: degrigis <degrigis@gmail.com>

* capslock char fixed

Signed-off-by: degrigis <degrigis@gmail.com>

* removed unuseful pwndbg.arch.ptrsize check

Signed-off-by: degrigis <degrigis@gmail.com>

* refactored code and added the new module wrapper that contains every new wrapper module

Signed-off-by: degrigis <degrigis@gmail.com>

* used class style decorator for wrapper and improved code style

Signed-off-by: degrigis <degrigis@gmail.com>

* changed return with print for errors

Signed-off-by: degrigis <degrigis@gmail.com>

* removed prints debug and statically linked check moved at the top of the got function

Signed-off-by: degrigis <degrigis@gmail.com>

* refactored OnlyWithCommand decorator

Signed-off-by: degrigis <degrigis@gmail.com>

* wrappers are OnlyWithFile now

Signed-off-by: degrigis <degrigis@gmail.com>

* redirected stderr to stdout in subprocess.check_output and memoized the wrappers for readelf/file/checksec

Signed-off-by: degrigis <degrigis@gmail.com>

* reordered an import

Signed-off-by: degrigis <degrigis@gmail.com>

* removed pdb

Signed-off-by: degrigis <degrigis@gmail.com>

* fixed format string and removed desc from got command

Signed-off-by: degrigis <degrigis@gmail.com>

* consolidated decorators

Signed-off-by: degrigis <degrigis@gmail.com>

* merging

Signed-off-by: degrigis <degrigis@gmail.com>

* reordered import for travis

Signed-off-by: degrigis <degrigis@gmail.com>

* refactored some code

Signed-off-by: degrigis <degrigis@gmail.com>

* resolve travis complains

Signed-off-by: degrigis <degrigis@gmail.com>

* docstring for _extract_jumps

Signed-off-by: degrigis <degrigis@gmail.com>

* fixed isort

Signed-off-by: degrigis <degrigis@gmail.com>

* f*** isort

Signed-off-by: degrigis <degrigis@gmail.com>

* Enhance canary command

Canary command:
* Displays telescope result of places where canaries are located
* Moved to its own file (`pwndbg/commands/canary.py`)
* Moved to `ArgparsedCommand` (as discussed in #244)

* update for ida_script.py to handle ida 7.0 (#308)

* fix for ida 7.0

* using idaapi.save_database instead, change version cmp from == to >=

* Fix the current year (#319)

This triggered me

* checksec: cache output of command (#317)

* checksec: cache output of command

* checksec: use get_raw_out() for derived functions

* cp fixes from stable: malloc chunk names, remote target search bug (#323)

* Fix malloc chunk names (#318)

* heap: respect rename of malloc_chunk fields

newer glibc uses different names for the fields of malloc_chunk

* move value_from_type to typeinfo and rename to read_gdbvalue

* add comment about renaming of `[prev_]size`

* Workaround for gdb remote target search bug described in #321 (#322)

* Move vmmap to ArgparsedCommand; add sloppy_gdb_parse (#285)

* Migrate vmmap command to ArgparsedCommand

* vmmap command: better msg for no mappings

* WIP: vmmap

* Review fixes

* isort fix

* Add nextret command (#301)

* Py version check: use pwndbg.compat.py* instead of sys.version (#327)

* Dumpargs add --force to show all possible register arguments (#326)

* Added --all flag to dumpargs command

This gives possibility to dump all register argument even
if we failed to resolve arguments from metadatas.

* Display info when dumpargs not resolved call args

* Dumpargs: changed --all to --force

* Revert telescope changes as it fails when we are not on call instruction.

* Fix isort

* Fix IDA Pro decompiled code not being displayed (#328)

* Fix withHexrays decorator not returning wrapper function

* IDA xmlrpc: add cfuncptr_t marshaller & better errors

* IDA xmlrpc server: add shutdown() which can be used for dev

* Small refactor of context.py

* Fix context Hexrays decompiled code display

* Fix hard error when something else (not IDA) listens on IDA's port (#330)

* Fix hard error when something else (not IDA) listens on IDA's port

The default IDA port is 8888 and it can happen that some other program (such as
a jupyter notebook) is listening on that address. This made pwndbg unusable,
because it would crash trying to connect to IDA.

* add timeout to ida connect

* Fix exception if there is an indirect jump (#329)

This is a simple typo, but the error message that GDB gave was interesting:

Previously, if you stopped on an instruction that does an indirect jump, like
this:

```
jmp [ecx*4 + 0xdeadbeef]
```

then pwndbg would the following exception:

```
gdb.error: evaluation of this expression requires the program to have a function "malloc".
```

The reason is that the code used `memory_sz` and passed that to gdb.Value, thus
creating a string value. When casting the string to a pointer later, GDB tries
to allocate a string in the inferior which failed since malloc is not available.

The fix is, of course, to use the correct function (`memory`) that returns an
int and not a string.

* Fixes issue when we try to display context while selected thread is running #299 (#331) (#333)

* ArgparsedCommands: config, configfile, theme, themefile (#335)

* Fix Python<=2.7.6 "TypeError: Struct() argument 1 must be string, not unicode" (#336)

* Fix Python<=2.7.6 "TypeError: Struct() argument 1 must be string, not unicode"

Additional information is available here: http://python-future.org/stdlib_incompatibilities.html#struct-pack

* Completely remove libheap, as it is not ever referenced

* Expose IDA Pro commands, even when IDA is not available. (#337)

Closes #225

* Removed duplicate requirement (#339)

2 Lines stated "capstone"

* Closes #338: Fix 'This command is not documented' (#341)

* Reduce the number of times we check to see if running Android

* Do not populate the main exe symbols on Android, it's unnecessary

* Add nextproginstr command (#360)

* Add nextproginstr command

* Fix isort

* Update next.py

* Update next.py

* Update next.py

* Add possibility to prevent skipping repeating telescope values (#359)

* Merge stable to dev (#365)

* Fixes `u` command `module object is not callable` (#310)

pwndbg> u 0x404030
'u': Starting at the specified address, disassemble
    N instructions (default 5).
Traceback (most recent call last):
  File "/home/dc/installed/pwndbg/pwndbg/commands/__init__.py", line 99, in __call__
    return self.function(*args, **kwargs)
  File "/home/dc/installed/pwndbg/pwndbg/commands/__init__.py", line 191, in _OnlyWhenRunning
    return function(*a, **kw)
  File "/home/dc/installed/pwndbg/pwndbg/commands/windbg.py", line 292, in u
    pwndbg.commands.nearpc(where, n)
TypeError: 'module' object is not callable

* Fix malloc chunk names (#318)

* heap: respect rename of malloc_chunk fields

newer glibc uses different names for the fields of malloc_chunk

* move value_from_type to typeinfo and rename to read_gdbvalue

* add comment about renaming of `[prev_]size`

* Workaround for gdb remote target search bug described in #321 (#322)

* Fixes issue when we try to display context while selected thread is running #299 (#331)

* Fix tag_release (#348)

* Fix "dt" offsets which are sometimes floating-point (#355)

* Fixes #362 - broken entry command (#363)

* fix ds and da for gdb 7.11 (#364)

* fix ds and da for gdb 7.11

* add max argument to da and ds

* Support bare metal environment (#369)

* Add elf.find_elf_magic() and remove duplicate code

* Add pwndbg.abi.LinuxOnly decorator

* Support bare metal environment

Use @pwndbg.abi.LinuxOnly and pwndbg.abi.linux to disable
several util functions which search the memory to find
the AUXV, the ELF header, or the page bound.

* Add xinfo command for extended offset information (#376)

This commit adds a `xinfo` command that calculates the offset of a
specified address to other interesting locations within the address
space:

* In the most general case, simply the offset of the pointer into the
current mapping is displayed.
* If the address specified is a stack adress, the offsets to the top and
the bottom of the stack, as well as to the current stack pointer,
frame pointer and stack canary are displayed.
* If the address points into a memory mapped file, the command
additionally shows the offset to the beginning of the file in memory and
on disk.

* Fail on two commands with the same name (#372)

* More badges in README

Add "Python 2&3" and "freenode: #pwndbg" badges created with https://shields.io/

* Fix Python 2&3 badge in README

* Update README badges links

* Add dereference-limit and heap-dereference-limit parameters (#367)

* Add dereference-limit and heap-dereference-limit parameters

This allows setting the number of pointers dereferenced during 'telescope'
and in the register context.  Separately, the number of heap bins which
are dereferenced can be set.

* Cast LIMIT to an integer, and address off-by-one

* Adds $rebase(offset) function (#374)

Adds `$rebase(offset)` gdbfunction that can be used to set up a breakpoint
over an offset from program image base.

Also changed a bit the pwndbg banner displayed at startup.

* ArgparsedCommand: pass parser or description; move some cmds to ArgparsedC~ (#373)

* Fix upper stack boundary (#377)

* Fix upper_stack_boundary not working introduced in 31f468e

The `upper_stack_boundary` we returned wasn't matching the one from `vmmap`.

Previously we determined upper address by having a memory read failure.
Recent changes made it so we got a `None` instead of the address in such situation.

This adds a parameter to `find_elf_magic` which lets us get a result when gdb.MemoryError occurs.

* Small refactor: add missing newlines

* Add capstone, unicorn versions to version command (#379)

* Merge stable to dev (#381)

* Fixes `u` command `module object is not callable` (#310)

pwndbg> u 0x404030
'u': Starting at the specified address, disassemble
    N instructions (default 5).
Traceback (most recent call last):
  File "/home/dc/installed/pwndbg/pwndbg/commands/__init__.py", line 99, in __call__
    return self.function(*args, **kwargs)
  File "/home/dc/installed/pwndbg/pwndbg/commands/__init__.py", line 191, in _OnlyWhenRunning
    return function(*a, **kw)
  File "/home/dc/installed/pwndbg/pwndbg/commands/windbg.py", line 292, in u
    pwndbg.commands.nearpc(where, n)
TypeError: 'module' object is not callable

* Fix malloc chunk names (#318)

* heap: respect rename of malloc_chunk fields

newer glibc uses different names for the fields of malloc_chunk

* move value_from_type to typeinfo and rename to read_gdbvalue

* add comment about renaming of `[prev_]size`

* Workaround for gdb remote target search bug described in #321 (#322)

* Fixes issue when we try to display context while selected thread is running #299 (#331)

* Fix tag_release (#348)

* Fix "dt" offsets which are sometimes floating-point (#355)

* Fixes #362 - broken entry command (#363)

* Fix #373 for python2 env (#384)

Since the python2 use `from __future__ import unicode_literals`, so the string literals will be `unicode` type in python2.
Use `six.string_types` in `isinstance()` instead of using `str` type.

* Fix Endianess issue and Memory error on GDB (#386)

* Fix py2 import error (shlex.quotes vs pipes.quotes) (#389)

* Avoid enhancements when dereference limit is zero (#380)

* Avoid enhancements when dereference limit is zero

* Replace last element in chain with enhancements

* make everything themeable (#392)

* theme: make everything themable by avoiding explicite colors

This makes it posssible to theme everything logically grouped by
message types. This will also make it easier for future features
to keep a consistent way of coloring plus make every non-specific
coloring themeable automatically.

Direct explicit usage of colors should be avoided in future commits.

* theme: make banner fully customizable including positions

* fixup: fix wrong import during refactoring (#394)

* Fix inthook for enums in Python 3 (#393)

Fixes the problem that can be observed below:

```
pwndbg> py import re; flags = 1 | re.MULTILINE
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/lib/python3.6/enum.py", line 798, in __or__
    result = self.__class__(self._value_ | self.__class__(other)._value_)
  File "/usr/lib/python3.6/enum.py", line 291, in __call__
    return cls.__new__(cls, value)
  File "/usr/lib/python3.6/enum.py", line 533, in __new__
    return cls._missing_(value)
  File "/usr/lib/python3.6/enum.py", line 762, in _missing_
    new_member = cls._create_pseudo_member_(value)
  File "/usr/lib/python3.6/enum.py", line 788, in _create_pseudo_member_
    pseudo_member._name_ = None
AttributeError: 'int' object has no attribute '_name_'
```

* Implement asm&source syntax highlight (#390)

* Syntax-highlight: Add asm lexer in color/lexer.py

* Syntax-highlight: Add pygments to requirements.txt

* Syntax-highlight: Update lexer for supporting ARM

Support symbol, constant, comments

* Syntax-highlight: Enable asm syntax highlight

* Syntax-highlight: Add source highlight utils in commnads/context.py

* Syntax-highlight: Add disasm highlight utils in color/disasm.py

* Syntax-highlight: Implement Source code highlighting in commands/context.py

* Syntax-highlight: Add syntax_highlight() in color/syntax_highlight.py

* Fix texts

* Add color theme and prefix config for context code

* Add missed utf8 magic comment

* Fix isort

* context: bring back args section (default off) (#397)

This allows to use args section via the context-sections config
setting (default off).
Additionally introduce a nearpc-show-args config value making it
possible to disable showing it trice while using the args section.

* config: validate context-sections and show all available values (#396)

When setting an illegal value, fall back to the default sections.

* Make de-reference only works on known pages in bare metal mode and add commands to manually add pages (#385)

* Make chain.get() to check vmmap first in bare metal mode

Make chain.get() limit to de-reference within the known page in
bare metal mode.
Since the address are all valid when mmu is not enable and all
the value are valid physical address. It will be de-referenced
even these addresses are not used and actually, it is data in
the most of case. Ex. 0x1 often means the value 1, not the
address 0x1.

Also, for issue #371, some addresses may be the MMIO registers.
The read operation on these address will break the state.
It is better to limit the de-reference address range. This patch
will also fix it, hopefully.

* Add custom vmmap add/del API in vmmap.py

In some cases, ex. bare metal, the pages information can not be
detected automatically. Also, the most of pwndbg feature rely on
page information such as highlighting.
User may want to create page information manually and maintain it
by himself.

This commit add python APIs to manually add/del page information
and they are isolated.

* Fix stack page detection in bare metal mode

We can not detect the stack page size in bare metal mode by
1. finding the ELF location after the stack page
2. page fault

A simple workaround is returning the current $sp page
and assume it is the stack page.

* Add vmmap control command to add/del customized vmmap

In some cases, ex. bare metal, the pages information can not be
detected automatically. Also, the most of pwndbg feature rely on
page information such as highlighting.
User may want to create page information manually and maintain it
by himself.

I add few commands to make user can add/del pages and load page
information from ELF sections.

* Fix the command amount for auto test to pass CI

* Add warning message

* Fix descriptions

* Fix cache issue and use bisect in insert API

* Keep LinuxOnly in find_elf_magic

* remove XXX

* improve repeat functionality of commands (#395)

* hexdump: adjust shown offset from src while repeating

* nearpc: make command repeatable to show further instructions

The pc gets adjusted to the last instructions address making it
visually easy to follow where to continue reading the assembly.

This also forwards repeating of emulate() and pdisass()

* telescope: make command repeatable with adjusted offset from src

This also forwards stack() to be repeatable.

* [WIP] Stop highlight and prefix display when repeating nearpc command (#399)

Fix nearpc command repeat: highlight, prefix and instruction display

* color: make lrjust() work with multiple chars (#401)

This fixes the issue if ljust with multiple characters like
the banner separator char

* syntax: highlight code for chain format during enhance (#400)

* Fix missing enum in Python 2 (#403)

* Add developer notes (#405)

* Update DEVELOPING.md

* Better detection of extended-remote types

* Bring back possibility of empty context (#409)

* Change README about GEF / GDBINIT / PWNDBG (#413)

* Ban isort==4.3.0 (#417)

See timothycrosley/isort#652 for more information. tl;dr is `pip install isort==4.3.0` fails, which is what `pip install -Ur requirements.txt` will attempt to do.

Ban this specific version as it causes issues.

* display the frame pointer register (x29) in aarch64 context (#418)

* ensure length padding works with py2 by enforcing unicode awareness (#416)

This works around the issue of python2 not being unicode aware and
the config classes not properly returning instance of decoded raw
strings. This leads to length operations being performed on bytes
rather then logical characters.
We check for python2 and enfore decoding if not a text_type.

Fixes #412

* Profiling and performance improvements (#421)

* Add scripts for benchmarking and profiling pwndbg commands

* Fix performance issue in emulator.py

Register to unicorn enum lookup was really ineffective. Replaced with
parsing (consts) on initialization time, and only dict lookup on hot path.

* Fix performance issue in syntax_highlight.

Current code initialized pygments on each syntax_highlight(), which
apparently took some time.

* Minor performance improvements in syntax_highlight

* Memoize IDA availability.

Not sure it this is a valid solution, I have never used pwndbg with IDA.
However, we should not try to connect to ida on each context(), as this
takes 25% of current exec time.

* Explicitly source gdbinit in benchmark scripts.

* Refactor variable names in nearpc (#422)

* Try to connect to IDA on every debugger stop. (#423)

Add option to disable IDA integration completly.

* Fix Parameter config class (#404)

* Avoid to use 'type' as varialbe name

* Fix utf8 issue of Parameter.value in python2

* Fix Parameter member funcs

* Operator overwrite of Parameter

* Remove all workaround of Parameter

* Use regex to unwrap the string

* Remove impossible cases in commands/context.py after Parameter class update

* Revert "ensure length padding works with py2 by enforcing unicode awareness (#416)"

This reverts commit 8ecaa67.

* Fix #429 - osabi check for non-English GDB version (#430)

Detailed info is within the issue, but TLDR:

```
(gdb) show osabi
El actual SO ABI es «auto» (actualmente «GNU/Linux»).
El SO ABI predeterminado es «GNU/Linux».
```

* add basic rust support (#431)

When a rust binary is loaded gdb will not find the usual c types.

* Fixes #428 - pwndbg.memory.write encoding error (#432)

It seems that pwndbg.memory.write fix for Py2 introduced in 433bf23
wasn't tested properly on Py3.

In Py2 by default the `bytes` is just `str` and so doesn't accept the encoding argument.

Because of that a `from builtins import bytes` has been added.

Some more info on `builtins` module can be found here: http://python-future.org/imports.html#imports-of-builtins

* Fixes #427 - readelf parsing error on old readelf versions (#433)

Here is `readelf --program-headers <binary>` output for different readelf versions
(The `//` are commented lines; the output is truncated so it contains only useful data):

```
Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align

// GNU readelf (GNU Binutils for Debian) 2.25 (2014):
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x000000000001bad4 0x000000000001bad4  R E    200000

// GNU readelf (GNU Binutils) 2.29.1 (2017):
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x000000000001e050 0x000000000001e050  R E    0x200000
```

Our parser parsed the line after the one containing `LOAD` and expected that `Align` column value will be always prefixed with `0x`. As we can see this is not always the case...

* fix find_fake_chunk #410 (#435)

* Fixes #436 - memory write regression (#437)

* Fix regression made in #432

*This situation pushes me more and more to work on tests engine*

* Fix eX memory write on Python 2

As string literal is unicode, in Py2 the code below would fail if `bytestr` is just a `str`, due to `'0'` being unocide literal:

```
bytestr.rjust(size*2, '0')
```

* Tests framework (#375)

* Add prototype of unit tests for pwndbg

* Add test for pwndbg [filter]

* Fix isort, e2e tests, add pytest requirement

* Add comment about not handling exceptions for unittests

* Fixes after rebase

* Fix test_loads_without_crashing

* e2e tests: no colors & loading pwndbg tests

* Fix isort

* Add example of no file loaded test

* Move tests to unit_tests, add binary, add memory tests

* Isort fixes

* Move from e2e/unit tests to tests

* Add info about tests to DEVELOPING.md

* Fix tests

* review fixes

* commands filtering test: check for contents, not for equality

* Add tests launcher bash script

* Change tests launcher name from unittests to pytests

* Cleanup; better test file paths

* Add theme param to disable colors

* Better test_loads

* Skip some tests locally that can run on travis

* Fix test_loads according to travis

* Fix travis tests

* Don't check for IDA Pro if it is dissabled (#439)

* Improve behavior without IDA Pro (#442)

* Improve behavior without IDA Pro

* Fix import order

* Improved IDA Pro behaviour more

* Added only_after_first_prompt decorator

* Removed newline after import

* Added documentation

* Improved docstring

* Implement support for ptmalloc's tcache in heap/ (#420)

* Implement support for ptmalloc's tcache in heap/ (#387)

Glibc 2.26 added per-thread cache of free chunks. This implements
new "tcache" and "tcachebins" commands for displaying information about
this cache.

Note this works well only if pthread is linked in the debugged program.
Otherwise gdb cannot access thread-local variables, so it cannot find
address of tcache main struct. One can though find the address, ex. by stepping
through malloc code, and pass it to the new commands.

* Another round of review fixes.

* handle gracefully older libc, without tcache

* use aligned size for consistency with other bins

* Support hex data prefixed with 0x when using eX windbg command (#444)

When using `eX` commands and setting data to hex value prefixed with `0x`, we get an exception:

```
pwndbg> ed 0xffb21ae4 0x55616740
Traceback (most recent call last):
  File "/usr/lib/python3.6/encodings/hex_codec.py", line 19, in hex_decode
    return (binascii.a2b_hex(input), len(input))
binascii.Error: Non-hexadecimal digit found

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/dc/installed/pwndbg/pwndbg/commands/__init__.py", line 109, in __call__
    return self.function(*args, **kwargs)
  File "/home/dc/installed/pwndbg/pwndbg/commands/__init__.py", line 200, in _OnlyWhenRunning
    return function(*a, **kw)
  File "/home/dc/installed/pwndbg/pwndbg/commands/windbg.py", line 141, in ed
    return eX(4, address, data)
  File "/home/dc/installed/pwndbg/pwndbg/commands/windbg.py", line 180, in eX
    data    = codecs.decode(bytestr, 'hex')
binascii.Error: decoding with 'hex' codec failed (Error: Non-hexadecimal digit found)
```

This commit fixes this problem so that if the data input has prefix, it is stripped.

* Adds stepret command and nextret docstring (#448)

So that now we can step-until-return-like-instruction like a boss! :)

* Add stepsyscall and rename next_syscall to nextsyscall (#447)

* Add stepsyscall (and stepsc) command

So that one can break at a syscall which is e.g. inside a call.

* Rename next_syscall into nextsyscall

* Display context on next/stepsyscall only if process is alive

* Fix bins command 'There is no member named tcache_bins' (#449)

Bins command fails on a libc that doesn't use tcache at all, e.g.:

```
GNU C Library (Ubuntu GLIBC 2.23-0ubuntu10) stable release version 2.23, by Roland McGrath et al.
```

Here is the output:

```
pwndbg> bins
Traceback (most recent call last):
  File "/root/pwndbg/pwndbg/commands/__init__.py", line 109, in __call__
    return self.function(*args, **kwargs)
  File "/root/pwndbg/pwndbg/commands/__init__.py", line 200, in _OnlyWhenRunning
    return function(*a, **kw)
  File "/root/pwndbg/pwndbg/commands/heap.py", line 255, in bins
    if pwndbg.heap.current.has_tcache():
  File "/root/pwndbg/pwndbg/heap/ptmalloc.py", line 47, in has_tcache
    return (self.mp and self.mp['tcache_bins'])
gdb.error: There is no member named tcache_bins.
```

This commit fixes this issue by checking whether `tcache_bins` field is present in the `malloc_par` structure.

* Fixes bins command (#424) (#450)

The problem was that after some of the recent changes to chain/get to prevent dereferencing too much addresses and having better display when dereferencing limit is 0 (used for bare metal debugging) the bins command displayed wrong results for everything except fastbins.

This was due to the fact we are adding the dereference start address to the list.

This fixes the `bins` command by adding `include_start=True` keyword argument to the `chain.get` function. The `bins` simply uses `include_start=False`.

* Fixes #391 - kills compat.py module (#452)

* Kill compat.py completely (#453)

* Fix IDA 7 unhandled DecompilationFailure (#455)

* version command: show IDA Pro versions (#456)

* version with IDA: proper hexrays detection (#457)

* Fix emulate command crash (#459)

After we added `repeat` functionality for some commands, the emulate stopped to work:
```
pwndbg> emulate
Traceback (most recent call last):
  File "/home/dc/installed/pwndbg/pwndbg/commands/__init__.py", line 109, in __call__
    return self.function(*args, **kwargs)
  File "/home/dc/installed/pwndbg/pwndbg/commands/__init__.py", line 200, in _OnlyWhenRunning
    return function(*a, **kw)
  File "/home/dc/installed/pwndbg/pwndbg/commands/nearpc.py", line 180, in emulate
    nearpc.repeat = emulate.repeat
AttributeError: 'bool' object has no attribute 'repeat'
```

This is due to the fact the command has the same name as argument which is a bool.

* Add filtering for config and theme commands (#458)

* Add filtering for config and theme commands

* Fix isort

* Change IDA xmlrpc default port (#462)

* Fixes #460 - getting SP reg on threaded apps (#463)

* Fixes #460 - getting SP reg on threaded apps

As the issue described: as we cache registers,
we might get their values wrong as we don't invalidate cache when thread is changed.

This leads to showing wrong context stack values in threaded apps.

This commit/PR adds a new memoization solution: `reset_on_prompt` which resets cache on `gdb.events.before_prompt` event.

* Fix isort

* Fix before_prompt event on old GDB versions (#464)

* Fix before_prompt event on old GDB versions

This adds an `EventWrapper` class which behaves similar to gdb events but lets us:
* check whether event is a real gdb event or not
* call event callbacks if it is not a real gdb event

* Better comment

* Fix pwndbg.disasm.near with disabled caching (#465)

Before this changes `context_disasm` produced different display based on memoization settings.

The bug can be seen below:

```
[dc@dc:pwndbg|dev $%]$ gdb ~/test/a.out
pwndbg: loaded 166 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from /home/dc/test/a.out...(no debugging symbols found)...done.
pwndbg> set context-sections disasm
Set which context sections are displayed (controls order) to 'disasm'
pwndbg> entry
Temporary breakpoint 1 at 0x400080

Temporary breakpoint 1, 0x0000000000400080 in _start ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────
 ► 0x400080 <_start>    jmp    _start <0x400080>
    ↓
 ► 0x400080 <_start>    jmp    _start <0x400080>

Breakpoint *0x400080
pwndbg> python import pwndbg; pwndbg.memoize.memoize.caching=False
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────
 ► 0x400080 <_start>    jmp    _start <0x400080>
    ↓
 ► 0x400080 <_start>    jmp    _start <0x400080>
    ↓
 ► 0x400080 <_start>    jmp    _start <0x400080>
    ↓
 ► 0x400080 <_start>    jmp    _start <0x400080>
    ↓
 ► 0x400080 <_start>    jmp    _start <0x400080>
    ↓
 ► 0x400080 <_start>    jmp    _start <0x400080>
    ↓
 ► 0x400080 <_start>    jmp    _start <0x400080>
    ↓
 ► 0x400080 <_start>    jmp    _start <0x400080>
    ↓
 ► 0x400080 <_start>    jmp    _start <0x400080>
    ↓
 ► 0x400080 <_start>    jmp    _start <0x400080>
    ↓
 ► 0x400080 <_start>    jmp    _start <0x400080>
Breakpoint *0x400080
pwndbg>
```

The tested binary can be reproduced with this assembly code:

```asm
global _start

_start:
jmp $
```

Compiled as `nasm -f elf64 code.asm && ld code.o`.

---

About the bug:

The check for multiple identical loops or rets is done using `set(insns[-3:])`. Before this hapens the `insns` is filled with the results of `one(address)`. This calls `get_one_instruction(address)` which is cached until `reset_on_cont`. As a result, when caching is enabled the `get_one_instruction` returns the same `capstone.CsInsn` instances for given address. When it is disabled, we return other instances which are identical.

The problem was that `set(insns[-3:])` creates a set based on `capstone.CsInsn` instances and not on the instruction addresses.

The fix changes this behavior so that we compare last 3 instruction addresses.

* Fix shell commands descriptions (#466)

Before that change all shell commands had a description of `None`.

This was because we used string formatting for a docstring and if one
does so, the string isn't a docstring anymore.

This also fixes `r2` command description.

* Use gdb.VERSION instead of parsing gdb.execute result (#467)

Yay, this is finally there:

```
>>> gdb.VERSION
'8.1.0.20180409-git'
```

* Fix NameError: global name 'abi' is not defined (#469)

* typeinfo: skip failed compile attempts (#470)

* typeinfo: skip failed compile attempts

This fixes the problem that single header files that are not compilable
do not abort the compilation loop.
Errors about the failure are printed anyway be check_output we just
avoid abortion.

* Remove shell=True in subprocess.check_output

* Improve dumpargs command edge cases (#471)

* Adds `-f` alias for `--force` option
* More informative docstrings

* Fix the up and down commands when provided with an argument. (#473)

* Command for calculating PIE offsets (#474)

* PIE command

* Kill compat in piebase command

* Improve piebase command

* Improve piebase command exe name introspection

* No longer rely on executeable segment for piebase

* Fix isort (#475)

* Fixes wrong pc/ip display in context introduced in 9fd5d35 (#477)

Before this PR we could get wrong RIP (like off by one) when single stepping through the code:

```
[...]

 RIP  0x555555559850 ◂— xor    ebp, ebp
───────────────────────[ DISASM ]──────────────────────
   0x555555559850    xor    ebp, ebp
 ► 0x555555559852    mov    r9, rdx <0x7ffff7de59a0>

[...]

pwndbg> i r rip
rip            0x555555559852	0x555555559852
```

The patch fixes the issue by reassigning GDB stop signal handler to getting register values.

* Fixes 476 - segfault handling when using rr project (#478)

* Fixes #476 - segfault handling when using rr project

* Fix isort

* bug fix: tcache bin (#482)

* Fix and enhance xinfo command (#480)

* Instead of unstable parsing of readelf output, use the elftools ELF wrapper for parsing PT_LOAD segments

* Fix #434 xinfo command doesn't show File(Disk) info on non-PIE binaries

Also remove some trailing whitespace

Also fix another bug in xinfo; now it can show the disk offset of all
mmap files, not just the primary executable

* New xinfo feature: Print containing ELF sections for file-backed addresses

* Only print header for ELF sections if at least 1 section contains the address

* Fix bug in section offset calculation when printing containing ELF sections

* Refactor ELF file parsing helpers for cleaner separtion of ELF metadata parsing and enrichment, and a specific use scenario (getting a list of segments/sections containing a given virtual addr). Also makes implementing caching parse results easier

Adjust xinfo command to these API changes

* Fix bug: Reference mem_end instead of file_end

* Don't use underscore variable names; change decorator to reset_on_objfile

* Update xinfo.py

* ptmalloc multiple heaps per non-main arena support, related fixes (#479)

* Multiple ptmalloc enhancements:

* Adds support for multiple heaps per arena for the `arenas` command.

* Names every heap objfile to enable proper coloring in vmmap - fixes 451.

* Refactors the `heap` command to address issue 443.

* Adds comment for HEAP_MAX_SIZE

* Refactors Arena and HeapInfo into classes

* Adds additional comment

* Objfile event dispatching fix (#486)

* Fixes objfile caching bug.

* Disables vmmap exploration when the target isn't alive.

* Resets the objfile cache to the proper type on exit. (#487)

* isort: fix import order to make travis pass (#490)

* Heap: allocator initialization check & global_max_fast bug fix (#485)

* Bug fix: global_max_fast symbol contains the actual value not the address

* heap: return from find_fake_fast if allocator is not initialized

* Bug fix: address method should return the symbol address if it's an intergral symbols

* Revert commit c35152d

* add OnlyWhenHeapIsInitialized decorator

* Update heap.py

* Refactors heap.get_region, adds special case for get_heap_boundaries. (#489)

Occasionally, the [heap] vm region and the actual start of the heap are
different, e.g. [heap] starts at 0x61f000 but mp_.sbrk_base is 0x620000.
Return an adjusted Page object if this is the case. Also changes the
callers of these functions where appropriate.

* Leak offset probing tool (#492)

* PIE command

* Kill compat in piebase command

* Improve piebase command

* Improve piebase command exe name introspection

* No longer rely on executeable segment for piebase

* Leak probing tool

* Fix description for probeleak

* Update probeleak.py

Changed `%x` to `0x%x` in edge case scenario print/reporting.

* Reorder imports

* Improve probeleak printing

* Fix isort (#493)

* Fixes #488: wrong regs display on threaded targets (#495)

Please see #488 (comment) for explanation.

* add vis_heap_chunks (#496)

* add vis_heap_chunks

* Add top_chunk suffix only when needed

* use ArgparsedCommand and pwndbg.arch.unpack + better formatting

* Minor improvements, fix isort

* Run each test in a separate GDB session (#498)

* it would be cool to have tests that run within GDB so that we don't have to parse GDB output and deal with weird problems
* we can't run all tests in one GDB session as `file x; entry; <some pwndbg command>; file y; entry; <some wndbg command>;` may have different results - it seems either us or GDB fails to cleanup everything properly

* Fix nearpc following jumps when used w/o emulation (#499)

* Tests launcher: show passed and failed count

* Build nearpc, emulate, u, pdisass test binaries

* Add tests for emulate, nearpc, pdisass, u

* Refactored disasm and emulator

* Fix nearpc following jumps w/o emulation

* Prevent tests from calling start_binary twice

* Add test for emulate_disasm_loop

* Fix isort

* Add nasm to travis install

* Add --eval-command quit to tests invocation

This should prevent travis from staying in gdb/stalled build when something fails in weird way (like a file is missing)
```
[+] Building 'emulate_disasm.o'
make: nasm: Command not found
make: *** [emulate_disasm.o] Error 127
gdbinit.py: No such file or directory.
pytests_collect.py: No such file or directory.
No output has been received in the last 10m0s, this potentially indicates a stalled build or something wrong with the build itself.
Check the details on how to adjust your build configuration on: https://docs.travis-ci.com/user/common-build-problems/#Build-times-out-because-no-output-was-received
```

* Add test binaries

* Inform about `exception-debugger` on exceptions (#501)

Instead of hiding this feature just for devs who reads our dev guide or just knows that this exists lets make pwndbg development great again and show this command to the world!

* 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 #488 (comment).

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.

* Fixes piebase and breakrva on remote debugging (#502)

Fixes the issue caught by ecx86 in:
#500 (comment)

The commands broke when we debugged a remote target which was
hosted on a remote gdbserver (NOT a local one).

This is because we used `pwndbg.proc.exe` (changed in previous commit)
which is a local path to the binary which was then used to filter out
memory pages belonging to the binary.

To fix the issue, the AUXV's AT_EXECFN is used first which was used
before previous commit but the returned path is now normalized
(as in previous version it didn't work because if it returned path './a.out'
it couldn't match it with binary's Page.objfile which was e.g. '/blabla/a.out').

* Bump version (#505)
  • Loading branch information...
disconnect3d committed Jul 29, 2018
1 parent 187b6e5 commit 63820d299f0ffbc55e7c6b9b5cbdeef888895660
Showing with 3,830 additions and 2,767 deletions.
  1. +1 −1 .github/CONTRIBUTING.md
  2. +5 −1 .gitignore
  3. +5 −5 .travis.yml
  4. +39 −0 DEVELOPING.md
  5. +8 −3 README.md
  6. +0 −1 docs/requirements.txt
  7. +0 −5 docs/source/api/compat.rst
  8. +88 −22 ida_script.py
  9. +3 −0 profiling/.gitignore
  10. +13 −0 profiling/benchmark.sh
  11. +18 −0 profiling/profile.sh
  12. +3 −0 profiling/test.c
  13. +16 −9 pwndbg/__init__.py
  14. +61 −0 pwndbg/abi.py
  15. +5 −2 pwndbg/android.py
  16. +5 −1 pwndbg/arch.py
  17. +33 −11 pwndbg/arguments.py
  18. +2 −0 pwndbg/argv.py
  19. +3 −0 pwndbg/auxv.py
  20. +33 −16 pwndbg/chain.py
  21. +19 −2 pwndbg/color/__init__.py
  22. +12 −0 pwndbg/color/context.py
  23. +11 −4 pwndbg/color/disasm.py
  24. +135 −0 pwndbg/color/lexer.py
  25. +73 −0 pwndbg/color/message.py
  26. +72 −0 pwndbg/color/syntax_highlight.py
  27. +54 −14 pwndbg/commands/__init__.py
  28. +3 −3 pwndbg/commands/aslr.py
  29. +2 −6 pwndbg/commands/auxv.py
  30. +53 −0 pwndbg/commands/canary.py
  31. +4 −9 pwndbg/commands/checksec.py
  32. +43 −14 pwndbg/commands/config.py
  33. +143 −56 pwndbg/commands/context.py
  34. +17 −19 pwndbg/commands/cpsr.py
  35. +5 −8 pwndbg/commands/defcon.py
  36. +47 −8 pwndbg/commands/dumpargs.py
  37. +10 −13 pwndbg/commands/elf.py
  38. +17 −43 pwndbg/commands/got.py
  39. +197 −73 pwndbg/commands/heap.py
  40. +7 −1 pwndbg/commands/hexdump.py
  41. +69 −73 pwndbg/commands/ida.py
  42. +22 −25 pwndbg/commands/misc.py
  43. +45 −29 pwndbg/commands/nearpc.py
  44. +63 −5 pwndbg/commands/next.py
  45. +106 −0 pwndbg/commands/pie.py
  46. +84 −0 pwndbg/commands/probeleak.py
  47. +2 −2 pwndbg/commands/radare2.py
  48. +6 −2 pwndbg/commands/search.py
  49. +3 −1 pwndbg/commands/shell.py
  50. +1 −7 pwndbg/commands/stack.py
  51. +10 −1 pwndbg/commands/start.py
  52. +27 −12 pwndbg/commands/telescope.py
  53. +19 −9 pwndbg/commands/theme.py
  54. +39 −6 pwndbg/commands/version.py
  55. +116 −21 pwndbg/commands/vmmap.py
  56. +29 −13 pwndbg/commands/windbg.py
  57. +126 −0 pwndbg/commands/xinfo.py
  58. +0 −22 pwndbg/compat.py
  59. +104 −15 pwndbg/config.py
  60. +27 −0 pwndbg/decorators.py
  61. +35 −26 pwndbg/disasm/__init__.py
  62. +5 −2 pwndbg/disasm/arch.py
  63. +5 −2 pwndbg/dt.py
  64. +160 −14 pwndbg/elf.py
  65. +50 −32 pwndbg/emu/emulator.py
  66. +4 −0 pwndbg/enhance.py
  67. +83 −15 pwndbg/events.py
  68. +16 −6 pwndbg/exception.py
  69. +10 −0 pwndbg/gdbutils/__init__.py
  70. +54 −0 pwndbg/gdbutils/functions.py
  71. +0 −28 pwndbg/gitver.py
  72. +2 −0 pwndbg/heap/__init__.py
  73. +9 −0 pwndbg/heap/heap.py
  74. +0 −1,878 pwndbg/heap/libheap.py
  75. +256 −36 pwndbg/heap/ptmalloc.py
  76. +7 −4 pwndbg/hexdump.py
  77. +71 −9 pwndbg/ida.py
  78. +7 −5 pwndbg/inthook.py
  79. +13 −0 pwndbg/memoize.py
  80. +13 −5 pwndbg/memory.py
  81. +41 −0 pwndbg/next.py
  82. +21 −1 pwndbg/proc.py
  83. +39 −4 pwndbg/prompt.py
  84. +3 −1 pwndbg/regs.py
  85. +13 −1 pwndbg/remote.py
  86. +13 −9 pwndbg/stack.py
  87. +0 −2 pwndbg/stdio.py
  88. +4 −1 pwndbg/symbol.py
  89. +15 −7 pwndbg/typeinfo.py
  90. +28 −4 pwndbg/ui.py
  91. +1 −1 pwndbg/version.py
  92. +31 −2 pwndbg/vmmap.py
  93. +0 −33 pwndbg/wrappers.py
  94. +35 −0 pwndbg/wrappers/__init__.py
  95. +42 −0 pwndbg/wrappers/checksec.py
  96. +36 −0 pwndbg/wrappers/readelf.py
  97. +36 −0 pytests_collect.py
  98. +31 −0 pytests_launcher.py
  99. +4 −1 requirements.txt
  100. +1 −1 tag_release.sh
  101. +33 −0 tests.sh
  102. +6 −2 tests/__init__.py
  103. +14 −0 tests/binaries/__init__.py
  104. +14 −0 tests/binaries/emulate_disasm.asm
  105. BIN tests/binaries/emulate_disasm.out
  106. +17 −0 tests/binaries/emulate_disasm_loop.asm
  107. BIN tests/binaries/emulate_disasm_loop.out
  108. +50 −0 tests/binaries/makefile
  109. +11 −0 tests/binaries/old_bash/__init__.py
  110. BIN tests/{corefiles/bash → binaries/old_bash}/binary
  111. BIN tests/{corefiles/bash → binaries/old_bash}/core
  112. +8 −0 tests/binaries/reference-binary.c
  113. BIN tests/binaries/reference-binary.out
  114. +0 −31 tests/common.py
  115. +30 −0 tests/conftest.py
  116. +0 −11 tests/testLoadsWithoutCrashing.py
  117. +95 −0 tests/test_emulate.py
  118. +129 −0 tests/test_loads.py
  119. +33 −0 tests/test_memory.py
  120. +33 −0 tests/test_misc.py
@@ -1,6 +1,6 @@
### Contributing

Contributions to Pwndbg are always welcome!
Contributions to Pwndbg are always welcome! If you want to get more familiar with project idea/structure/whatever - [here are some developer notes](./DEVELOPING.md). If something is not clear, feel free to ask in a github issue!

If you want to help, fork the project, hack your changes and create a pull request.

@@ -60,4 +60,8 @@ npm-debug.log
.gdb_history

# PyCharm project files
.idea/
.idea/

# PyTest files
.pytest_cache/
tests/.pytest_cache/
@@ -9,14 +9,14 @@ cache:
- capstone
- unicorn
install:
- sudo apt-get -y install gdb
- sudo apt-get -y install gdb nasm
- lsb_release -a
- pip install -r requirements.txt
- sudo ./setup.sh
script:
- futurize --all-imports --stage1 --print-function --write --unicode-literals pwndbg
- git diff-index --quiet HEAD -- pwndbg
- isort --check-only --diff --recursive pwndbg
- nosetests ./tests/
- futurize --all-imports --stage1 --print-function --write --unicode-literals pwndbg tests
- git diff-index --quiet HEAD -- pwndbg tests
- isort --check-only --diff --recursive pwndbg tests
- PWNDBG_TRAVIS_TEST_RUN=1 ./tests.sh
- python2.7 -m py_compile ida_script.py $(git ls-files 'pwndbg/*.py')
- python3 -m py_compile $(git ls-files 'pwndbg/*.py')
@@ -0,0 +1,39 @@
# Random developer notes

Feel free to update the list below!

* If you want to play with pwndbg functions under GDB, you can always use GDB's `pi` which launches python interpreter or just `py <some python line>`.

* If there is possibility, don't use `gdb.execute` as this requires us to parse the string and so on; there are some cases in which there is no other choice. Most of the time we try to wrap GDB's API to our own/easier API.

* We have our own `pwndbg.config.Parameter` (which extends `gdb.Parameter`) - all of our parameters can be seen using `config` or `theme` commands. If we want to do something when user changes config/theme - we can do it defining a function and decorating it with `pwndbg.config.Trigger`.

* The dashboard/display/context we are displaying is done by `pwndbg/commands/context.py` which is invoked through GDB's prompt hook (which we defined in `pwndbg/prompt.py` as `prompt_hook_on_stop`).

* All commands should be defined in `pwndbg/commands` - most of them lie in seperate files but some files contains many of them (e.g. commands corresponding to windbg debugger - in `windbg.py` or some misc commands in `misc.py`). We would also want to make all of them to use `ArgparsedCommand` (instead of `Command` or `ParsedCommand` decorators).

* We change a bit GDB settings - this can be seen in `pwndbg/__init__.py` - there are also imports for all pwndbg submodules

* We have a wrapper for GDB's events in `pwndbg/events.py` - thx to that we can e.g. invoke something based upon some event

* We have a caching mechanism (["memoization"](https://en.wikipedia.org/wiki/Memoization)) which we use through Python's decorators - those are defined in `pwndbg/memoize.py` - just check its usages

* To block a function before the first prompt was displayed use the `pwndbg.decorators.only_after_first_prompt` decorator.

* Memory accesses should be done through `pwndbg/memory.py` functions

* Process properties can be retrieved thx to `pwndbg/proc.py` - e.g. using `pwndbg.proc.pid` will give us current process pid

* We have an inthook to make it easier to work with Python 2 and gdb.Value objects - see the docstring in `pwndbg/inthook.py` . Specifically, it makes it so that you can call `int()` on a `gdb.Value` instance and get what you want.

* We have a wrapper for handling exceptions that are thrown by commands - defined in `pwndbg/exception.py` - current approach seems to work fine - by using `set exception-verbose on` - we get a stacktrace. If we want to debug stuff we can always do `set exception-debugger on`.

* Some of pwndbg's functionality - e.g. memory fetching - require us to have an instance of proper `gdb.Type` - the problem with that is that there is no way to define our own types - we have to ask gdb if it detected particular type in this particular binary (that sucks). We do it in `pwndbg/typeinfo.py` and it works most of the time. The known bug with that is that it might not work properly for Golang binaries compiled with debugging symbols.

* We would like to add proper tests for pwndbg - see tests framework PR if you want to help on that.

# Testing

Our tests are written using [pytest](https://docs.pytest.org/en/latest/). It uses some magic so that Python's `assert` can be used for asserting things in tests and it injects dependencies which are called fixtures, into test functions.

The fixtures should be defined in [tests/conftest.py](tests/conftest.py). If you need help with writing tests, feel free to reach out on gitub issues/pr or on our irc channel on freenode.
@@ -1,24 +1,29 @@
# pwndbg [![Build Status](https://travis-ci.org/pwndbg/pwndbg.svg?branch=master)](https://travis-ci.org/pwndbg/pwndbg) [![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)]()
# pwndbg [![Build Status](https://travis-ci.org/pwndbg/pwndbg.svg?branch=dev)](https://travis-ci.org/pwndbg/pwndbg) [![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)](https://github.com/pwndbg/pwndbg/blob/dev/LICENSE.md) [![Py2&3](https://img.shields.io/badge/Python-2%20%26%203-green.svg)]() [![IRC](https://img.shields.io/badge/freenode-%23pwndbg-red.svg)](https://webchat.freenode.net/?channels=#pwndbg)

`pwndbg` (/poʊndbæg/) is a GDB plug-in that makes debugging with GDB suck less, with a focus on features needed by low-level software developers, hardware hackers, reverse-engineers and exploit developers.

It has a boatload of features, see [FEATURES.md](FEATURES.md).

## Why?

Vanilla GDB is terrible to use for reverse engineering and exploit development. Typing `x/g30x $esp` is not fun, and does not confer much information. The year is 2016 and GDB still lacks a hexdump command. GDB's syntax is arcane and difficult to approach. Windbg users are completely lost when they occasionally need to bump into GDB.
Vanilla GDB is terrible to use for reverse engineering and exploit development. Typing `x/g30x $esp` is not fun, and does not confer much information. The year is 2017 and GDB still lacks a hexdump command. GDB's syntax is arcane and difficult to approach. Windbg users are completely lost when they occasionally need to bump into GDB.

## What?

Pwndbg is a Python module which is loaded directly into GDB, and provides a suite of utilities and crutches to hack around all of the cruft that is GDB and smooth out the rough edges.

Many other projects from the past (e.g., [gdbinit][gdbinit], [PEDA][PEDA]) and present (e.g. [GEF][GEF]) exist to fill some these gaps. Unfortunately, they're all either unmaintained, unmaintainable, or not well suited to easily navigating the code to hack in new features (respectively).
Many other projects from the past (e.g., [gdbinit][gdbinit], [PEDA][PEDA]) and present (e.g. [GEF][GEF]) exist to fill some these gaps. Each provides an excellent experience and great features -- but they're difficult to extend (some are unmaintained, and all are a single [100KB][gdbinit2], [200KB][peda.py], or [300KB][gef.py] file (respectively)).

Pwndbg exists not only to replace all of its predecessors, but also to have a clean implementation that runs quickly and is resilient against all the weird corner cases that come up.

[gdbinit]: https://github.com/gdbinit/Gdbinit
[gdbinit2]: https://github.com/gdbinit/Gdbinit/blob/master/gdbinit

[PEDA]: https://github.com/longld/peda
[peda.py]: https://github.com/longld/peda/blob/master/peda.py

[GEF]: https://github.com/hugsy/gef
[gef.py]: https://github.com/hugsy/gef/blob/master/gef.py

## How?

@@ -20,4 +20,3 @@ python-ptrace>=0.8
six
future
unicorn>=1.0.0
capstone

This file was deleted.

Oops, something went wrong.
@@ -6,6 +6,7 @@
import threading
import xmlrpclib
from SimpleXMLRPCServer import SimpleXMLRPCServer
from xml.sax.saxutils import escape

import idaapi
import idautils
@@ -20,13 +21,36 @@
dt = datetime.datetime.now().isoformat().replace(':', '-')

# Save the database so nothing gets lost.
idc.SaveBase(idc.GetIdbPath() + '.' + dt)
if idaapi.IDA_SDK_VERSION >= 700:
idaapi.save_database(idc.GetIdbPath() + '.' + dt)
else:
idc.SaveBase(idc.GetIdbPath() + '.' + dt)

xmlrpclib.Marshaller.dispatch[type(0L)] = lambda _, v, w: w("<value><i8>%d</i8></value>" % v)
xmlrpclib.Marshaller.dispatch[type(0)] = lambda _, v, w: w("<value><i8>%d</i8></value>" % v)

DEBUG_MARSHALLING = False

def create_marshaller(use_format=None, just_to_str=False):
assert use_format or just_to_str, 'Either pass format to use or make it converting the value to str.'

def wrapper(_marshaller, value, appender):
if use_format:
marshalled = use_format % value
elif just_to_str:
marshalled = '<value><string>%s</string></value>' % escape(str(value))

if DEBUG_MARSHALLING:
print("Marshalled: '%s'" % marshalled)

appender(marshalled)

return wrapper

xmlrpclib.Marshaller.dispatch[type(0L)] = create_marshaller("<value><i8>%d</i8></value>")
xmlrpclib.Marshaller.dispatch[type(0)] = create_marshaller("<value><i8>%d</i8></value>")
xmlrpclib.Marshaller.dispatch[idaapi.cfuncptr_t] = create_marshaller(just_to_str=True)

host = '127.0.0.1'
port = 8888
port = 31337
orig_LineA = idc.LineA


@@ -44,23 +68,30 @@ def LineA(*a, **kw):

def wrap(f):
def wrapper(*a, **kw):
try:
rv = []

def work():
rv.append(f(*a, **kw))

with mutex:
flags = idaapi.MFF_WRITE
if f == idc.SetColor:
flags |= idaapi.MFF_NOWAIT
rv.append(None)
idaapi.execute_sync(work, flags)
return rv[0]
except:
import traceback
traceback.print_exc()
raise
rv = []
error = []

def work():
try:
result = f(*a, **kw)
rv.append(result)
except Exception as e:
error.append(e)

with mutex:
flags = idaapi.MFF_WRITE
if f == idc.SetColor:
flags |= idaapi.MFF_NOWAIT
rv.append(None)
idaapi.execute_sync(work, flags)

if error:
msg = 'Failed on calling {}.{} with args: {}, kwargs: {}\nException: {}' \
.format(f.__module__, f.__name__, a, kw, str(error[0]))
print('[!!!] ERROR:', msg)
raise error[0]

return rv[0]

return wrapper

@@ -71,15 +102,50 @@ def register_module(module):
server.register_function(wrap(function), name)


def decompile(addr):
"""
Function that overwrites `idaapi.decompile` for xmlrpc so that instead
of throwing an exception on `idaapi.DecompilationFailure` it just returns `None`.
(so that we don't have to parse xmlrpc Fault's exception string on pwndbg side
as it differs between IDA versions).
"""
try:
return idaapi.decompile(addr)
except idaapi.DecompilationFailure:
return None


def versions():
"""Returns IDA & Python versions"""
import sys
return {
'python': sys.version,
'ida': idaapi.get_kernel_version(),
'hexrays': idaapi.get_hexrays_version() if idaapi.init_hexrays_plugin() else None
}


server = SimpleXMLRPCServer((host, port), logRequests=True, allow_none=True)
register_module(idc)
register_module(idautils)
register_module(idaapi)
server.register_function(lambda a: eval(a, globals(), locals()), 'eval')
server.register_function(decompile) # overwrites idaapi/ida_hexrays.decompie
server.register_function(versions)
server.register_introspection_functions()

print('Ida Pro xmlrpc hosted on http://%s:%s' % (host, port))
print('IDA Pro xmlrpc hosted on http://%s:%s' % (host, port))
print('Call `shutdown()` to shutdown the IDA Pro xmlrpc server.')

thread = threading.Thread(target=server.serve_forever)
thread.daemon = True
thread.start()


def shutdown():
global server
global thread
server.shutdown()
server.server_close()
del server
del thread
@@ -0,0 +1,3 @@
test
stats
stats.log
@@ -0,0 +1,13 @@
#!/bin/bash
# Benchmark context command
make test > /dev/null
git log --abbrev-commit --pretty=oneline HEAD^..HEAD
gdb ./test \
-ex "source ../gdbinit.py" \
-ex "b main" -ex "r" \
-ex "python import timeit; print(' 1ST RUN:', timeit.repeat('pwndbg.commands.context.context()', repeat=1, number=1, globals=globals())[0])" \
-ex "si" \
-ex "python import timeit; print(' 2ND RUN:', timeit.repeat('pwndbg.commands.context.context()', repeat=1, number=1, globals=globals())[0])" \
-ex "si" \
-ex "python import timeit; print('MULTIPLE RUNS:', timeit.repeat('pwndbg.commands.context.context()', repeat=1, number=10, globals=globals())[0] / 10)" \
-ex "quit" | grep 'RUNS*:'
@@ -0,0 +1,18 @@
#!/bin/bash
# Quick and dirty script to profile pwndbg using cProfile.
make test > /dev/null
git log --abbrev-commit --pretty=oneline HEAD^..HEAD
# To profile first run, remove -ex "context".
gdb ./test \
-ex "source ../gdbinit.py" \
-ex "b main" -ex "r" \
-ex "context" \
-ex "python import cProfile; cProfile.run('pwndbg.commands.context.context()', 'stats')" \
-ex "quit"

python3 -c "
import pstats
p = pstats.Stats('stats')
p.strip_dirs().sort_stats('tottime').print_stats(20)
"
[ -x /usr/local/bin/pyprof2calltree ] && command -v kcachegrind >/dev/null 2>&1 && /usr/local/bin/pyprof2calltree -k -i stats
@@ -0,0 +1,3 @@
int main() {
while(1);
}
Oops, something went wrong.

0 comments on commit 63820d2

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.