It's time for Ruby lovers to use Ruby in gdb and gdb in Ruby!
Achieve two things in one gem:
- Launching Ruby interactive shell (pry) in gdb.
- gdb Ruby-binding, i.e. communicate with gdb in Ruby scripts.
We provide a binary gdb-ruby
(a Ruby script actually) with usage exactly the same as a normal gdb,
while has two extra commands: ruby
and pry
!
See examples below:
$ gdb-ruby -q bash
Reading symbols from bash...(no debugging symbols found)...done.
(gdb) help ruby
Evaluate a Ruby command.
There's an instance 'gdb' for you. See examples.
Syntax: ruby <ruby code>
Examples:
ruby p 'abcd'
# "abcd"
Use gdb:
ruby puts gdb.break('main')
# Breakpoint 1 at 0x41eed0
Method defined will remain in context:
ruby def a(b); b * b; end
ruby p a(9)
# 81
(gdb) help pry
Enter Ruby interactive shell.
Everything works like a charm!
Syntax: pry
Example:
pry
# [1] pry(#<GDB::EvalContext>)>
Completely NO effort if you want to use gdb-ruby with other gdb extensions.
For example, I usually use the plugin gef with gdb. Everything works as usual when integrated with gdb-ruby:
Launching with $ gdb-ruby -q bash
Communicate with gdb in your Ruby script.
Basic usage is use execute
to do anything you want to execute inside gdb,
while gdb-ruby provides some useful methods listed as following:
break
: Set break points. Alias:b
run
: Run. Alias:r
register
: Get value by register's name. Alias:reg
text_base
: Get current running program's text base, useful for a PIE binary.pid
: Get the process id of running process.read_memory
: Read process's memory, with friendly type casting. Alias:readm
write_memory
: Write process's memory, useful for dynamic analysis. Alias:writem
interact
: Back to normal gdb interactive mode.
All of these methods are fully documented at online doc, go for it!
Play with argv using gdb-ruby.
This script does:
- Set a break point at
main
. - Get argv using
register
andread_memory
. - Change argv using
write_memory
.
require 'gdb'
# launch a gdb instance
gdb = GDB::GDB.new('bash')
# 1. set breakpoint
gdb.break('main')
#=> "Breakpoint 1 at 0x41eed0"
gdb.run('-c "echo cat"')
# 2. get argv pointers
rdi = gdb.reg(:rdi)
#=> 3
rsi = gdb.reg(:rsi)
argv = gdb.readm(rsi, rdi, as: :u64)
argv.map { |c| '0x%x' % c }
#=> ['0x7fffffffe61b', '0x7fffffffe625', '0x7fffffffe628']
# 3. overwrite argv[2]'s 'cat' to 'FAT'
gdb.writem(argv[2] + 5, 'FAT') # echo FAT
puts gdb.execute('continue')
# Continuing.
# FAT
# [Inferior 1 (process 32217) exited normally]
Set a break point, run it, and back to gdb interactive mode.
require 'gdb'
# launch a gdb instance
gdb = GDB::GDB.new('bash')
# set breakpoints
gdb.break('main')
gdb.run
# to show the process do stop at the breakpoint
gdb.execute('info reg rip')
#=> "rip 0x41eed0\t0x41eed0 <main>"
# interaction like normal gdb!
gdb.interact
Available on RubyGems.org!
$ gem install gdb
git clone https://github.com/david942j/gdb-ruby
cd gdb-ruby
bundle
bundle exec rake
Feel free to file an issue if you find any bugs. Any feature requests and suggestions are welcome! 😬
gdb-ruby is under developing, give it a star and watch for latest updates!