Module: PWN::Plugins::GDBMI

Defined in:
lib/pwn/plugins/gdbmi.rb

Overview

GDB machine-interface bridge: breakpoints, stepping, registers, memory, backtraces, checksec. Pairs with ProcessTube for interactive sessions.

Class Method Summary collapse

Class Method Details

.authorsObject



63
64
65
# File 'lib/pwn/plugins/gdbmi.rb', line 63

public_class_method def self.authors
  "AUTHOR(S):\n  0day Inc. <[email protected]>\n"
end

.backtrace(opts = {}) ⇒ Object



43
44
45
# File 'lib/pwn/plugins/gdbmi.rb', line 43

public_class_method def self.backtrace(opts = {})
  mi(opts.merge(cmd: '-stack-list-frames'))
end

.break(opts = {}) ⇒ Object



20
21
22
23
24
25
# File 'lib/pwn/plugins/gdbmi.rb', line 20

public_class_method def self.break(opts = {})
  loc = (opts[:location] || opts[:addr] || opts[:symbol]).to_s
  raise 'ERROR: location is required' if loc.empty?

  mi(opts.merge(cmd: "-break-insert #{loc}"))
end

.checksec(opts = {}) ⇒ Object



47
48
49
# File 'lib/pwn/plugins/gdbmi.rb', line 47

public_class_method def self.checksec(opts = {})
  PWN::Plugins::GDB.mitigations(opts)
end

.helpObject



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
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/pwn/plugins/gdbmi.rb', line 67

public_class_method def self.help
  puts "USAGE:
    # List host binaries this module expects to be installed.
    #{self}.required_bins

    # Open gdb --interpreter=mi2 via ProcessTube.
    #{self}.open(
      binary: 'optional - filesystem path of the binary to debug'
    )

    # Insert a breakpoint (MI -break-insert).
    #{self}.break(
      location: 'required - symbol or address',
      addr: 'optional - alias for location',
      symbol: 'optional - alias for location',
      id: 'optional - ProcessTube id from #open'
    )

    # Step (into when into: true, otherwise next).
    #{self}.step(
      into: 'optional - true to step into (defaults to next)',
      id: 'optional - ProcessTube id from #open'
    )

    # Read registers via MI.
    #{self}.registers(
      id: 'optional - ProcessTube id from #open'
    )

    # Read memory bytes at addr.
    #{self}.read_memory(
      addr: 'required - address to read',
      address: 'optional - alias for addr',
      length: 'optional - byte count (defaults to 64)',
      id: 'optional - ProcessTube id from #open'
    )

    # Backtrace via MI -stack-list-frames.
    #{self}.backtrace(
      id: 'optional - ProcessTube id from #open'
    )

    # checksec / mitigations via GDB.mitigations.
    #{self}.checksec(
      binary: 'optional - filesystem path of the binary'
    )

    # Send a raw MI command.
    #{self}.mi(
      cmd: 'required - MI command string',
      id: 'optional - ProcessTube id from #open',
      timeout: 'optional - seconds to wait for a reply'
    )

    # Print the AUTHOR(S) string for this module.
    #{self}.authors
  "
  constants.sort
end

.mi(opts = {}) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
# File 'lib/pwn/plugins/gdbmi.rb', line 51

public_class_method def self.mi(opts = {})
  cmd = opts[:cmd].to_s
  raise 'ERROR: cmd is required' if cmd.empty?

  if opts[:id]
    PWN::Plugins::ProcessTube.write_line(id: opts[:id], line: cmd)
    PWN::Plugins::ProcessTube.recvuntil(id: opts[:id], until: "\n", timeout: opts[:timeout] || 5)
  else
    PWN::Plugins::GDB.batch(opts.merge(commands: [cmd.sub(/\A-/, '')]))
  end
end

.open(opts = {}) ⇒ Object



15
16
17
18
# File 'lib/pwn/plugins/gdbmi.rb', line 15

public_class_method def self.open(opts = {})
  binary = opts[:binary].to_s
  PWN::Plugins::ProcessTube.spawn(cmd: ['gdb', '--interpreter=mi2', '--quiet', binary].reject(&:empty?))
end

.read_memory(opts = {}) ⇒ Object



35
36
37
38
39
40
41
# File 'lib/pwn/plugins/gdbmi.rb', line 35

public_class_method def self.read_memory(opts = {})
  addr = (opts[:addr] || opts[:address]).to_s
  raise 'ERROR: addr is required' if addr.empty?

  n = (opts[:length] || 64).to_i
  mi(opts.merge(cmd: "-data-read-memory-bytes #{addr} #{n}"))
end

.registers(opts = {}) ⇒ Object



31
32
33
# File 'lib/pwn/plugins/gdbmi.rb', line 31

public_class_method def self.registers(opts = {})
  mi(opts.merge(cmd: '-data-list-register-values x'))
end

.required_binsObject



11
12
13
# File 'lib/pwn/plugins/gdbmi.rb', line 11

public_class_method def self.required_bins
  %w[gdb]
end

.step(opts = {}) ⇒ Object



27
28
29
# File 'lib/pwn/plugins/gdbmi.rb', line 27

public_class_method def self.step(opts = {})
  mi(opts.merge(cmd: (opts[:into] ? '-exec-step' : '-exec-next')))
end