Skip to content

Commit

Permalink
Allow using GDB Python API (#1617) (#1695)
Browse files Browse the repository at this point in the history
Co-authored-by: Arusekk <[email protected]>
  • Loading branch information
mephi42 and Arusekk authored Nov 16, 2020
1 parent 0b1f430 commit d466fa9
Show file tree
Hide file tree
Showing 10 changed files with 492 additions and 19 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ jobs:
libc6-dbg \
$ANDROID_JRE
- name: Install RPyC for GDB
run: |
sudo apt-get install -y python3-pip
/usr/bin/python3 -m pip install rpyc
- name: Testing Corefiles
run: |
ulimit -a
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
run: |
set -x
pip install pylint
pip install --upgrade -r requirements.txt
pylint --exit-zero --errors-only pwnlib > current.txt
git fetch origin
git checkout origin/"$GITHUB_BASE_REF"
Expand Down
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ addons:
- binutils-s390x-linux-gnu
- binutils-sparc64-linux-gnu
- bash-static
- python3-pip
cache:
- pip
- directories:
Expand All @@ -42,6 +43,7 @@ before_install:
- source travis/ssh_setup.sh
- echo $-
install:
- /usr/bin/python3 -m pip install rpyc # for GDB
- pip install --upgrade pip
- pip install --upgrade flake8 appdirs # https://github.com/ActiveState/appdirs/issues/89#issuecomment-282326570
- python setup.py egg_info # pypa/pip#6275
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ The table below shows which release corresponds to each branch, and what date th
## 4.5.0 (`dev`)

- [#1261][1261] Misc `run_in_new_terminal` improvements (notably gdb terminated by default)
- [#1695][1695] Allow using GDB Python API

[1261]: https://github.com/Gallopsled/pwntools/pull/1261
[1695]: https://github.com/Gallopsled/pwntools/pull/1695

## 4.4.0 (`beta`)

Expand Down
112 changes: 112 additions & 0 deletions examples/gdb_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/usr/bin/env python3
"""An example of using GDB Python API with Pwntools."""
from pwn import *


def check_write(gdb, exp_buf):
"""Check that write() was called with the expected arguments."""
fd = gdb.parse_and_eval('$rdi').cast(gdb.lookup_type('int'))
assert fd == 1, fd
buf_addr = gdb.parse_and_eval('$rsi').cast(gdb.lookup_type('long'))
count = gdb.parse_and_eval('$rdx').cast(gdb.lookup_type('long'))
buf = gdb.selected_inferior().read_memory(buf_addr, count).tobytes()
assert buf == exp_buf, buf


def demo_sync_breakpoint(cat, gdb, txt):
"""Demonstrate a synchronous breakpoint."""
# set the synchronous breakpoint on ``write``
gdb.Breakpoint('write', temporary=True)

# resume the program
gdb.continue_nowait()

# send the line
cat.sendline(txt)

# wait until we hit the breakpoint
gdb.wait()

# inspect program state
check_write(gdb, (txt + '\n').encode())

# resume the program
gdb.continue_nowait()

# expect to observe the line we just sent
cat.recvuntil(txt)


def demo_async_breakpoint(cat, gdb, txt):
"""Demonstrate asynchronous breakpoint."""
# set the asynchronous breakpoint on ``write``
class WriteBp(gdb.Breakpoint):
def __init__(self):
super().__init__('write')
self.count = 0

def stop(self):
# called in a separate thread
check_write(gdb, (txt + '\n').encode())
self.count += 1

bp = WriteBp()

# resume the program
gdb.continue_nowait()

# send the line and immediately expect to observe it
cat.sendline(txt)
cat.recvuntil(txt)

# check that we hit the breakpoint
assert bp.count == 1, bp.count

# interrupt the program
gdb.interrupt_and_wait()

# delete the breakpoint
bp.delete()

# resume the program
gdb.continue_nowait()


def main():
# start ``cat`` under GDB
with gdb.debug('cat', gdbscript='''
set logging on
set pagination off
''', api=True) as cat:

# the process is stopped
# set the synchronous breakpoint on ``read``
cat.gdb.Breakpoint('read', temporary=True)

# resume and wait until we hit it
cat.gdb.continue_and_wait()

# demonstrate a more interesting synchronous breakpoint
demo_sync_breakpoint(cat, cat.gdb, 'foo')

# terminate GDB
cat.gdb.quit()

# now start ``cat`` normally
with process('cat') as cat:
# attach GDB
_, cat_gdb = gdb.attach(cat, gdbscript='''
set logging on
set pagination off
''', api=True)

# the process is stopped
# demonstrate asynchronous breakpoint
demo_async_breakpoint(cat, cat_gdb, 'bar')

# terminate GDB
cat_gdb.quit()


if __name__ == '__main__':
main()
Loading

0 comments on commit d466fa9

Please sign in to comment.