File: gdb_api.py

package info (click to toggle)
pwntools 4.14.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 18,436 kB
  • sloc: python: 59,156; ansic: 48,063; asm: 45,030; sh: 396; makefile: 256
file content (112 lines) | stat: -rw-r--r-- 2,811 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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()