You can start gdb and initialize it with a python script using -x
command line flag. This can be launched using subprocess
in another python instance. This can give you a way to bruteforce.
Some code. The driver file driver.py
import subprocess
import sys
rax = sys.argv[1]
d = subprocess.Popen("gdb -q -ex 'py rax = " + str(rax) + "' -x ./gdb_attach.py ", shell=True, stdout=subprocess.PIPE).stdout.read().strip()
print "Breakpoint hit ::: ", "HIT" in d
print d
Python script evaluated in gdb gdb_attach.py
with some predefined example offsets. Note that my gdb was built with python3 support.
import gdb
class MyBreakpoint(gdb.Breakpoint):
def stop (self):
print("HIT")
return True
gdb.execute('file ./x')
# gdb.execute("set environment LD_PRELOAD /home/sudhakar/tools/preeny/x86_64-linux-gnu/desleep.so")
MyBreakpoint("*0x40050b")
gdb.execute("run")
gdb.execute('set $rax=0x%x' % rax)
gdb.execute("continue")
gdb.execute('quit')
The binary is a simple yes/no check.
#include <stdio.h>
int dum(){
return 0;
}
int main(int argc, char **argv)
{
if(dum()) puts("Yeaa!");
else puts("No!");
return 0;
}
The offsets look like this.
[0x00400400]> pdf @ main
┌ (fcn) main 58
│ main (int argc, char **argv, char **envp);
│ ; var char **local_10h @ rbp-0x10
│ ; var int local_4h @ rbp-0x4
│ ; arg int argc @ rdi
│ ; arg char **argv @ rsi
│ ; DATA XREF from entry0 (0x40041d)
│ 0x004004f2 55 push rbp
│ 0x004004f3 4889e5 mov rbp, rsp
│ 0x004004f6 4883ec10 sub rsp, 0x10
│ 0x004004fa 897dfc mov dword [local_4h], edi ; argc
│ 0x004004fd 488975f0 mov qword [local_10h], rsi ; argv
│ 0x00400501 b800000000 mov eax, 0
│ 0x00400506 e8dcffffff call sym.dum
│ 0x0040050b 85c0 test eax, eax
│ ┌─< 0x0040050d 740c je 0x40051b
│ │ 0x0040050f bfb4054000 mov edi, str.Yeaa ; 0x4005b4 ; "Yeaa!" ; const char *s
│ │ 0x00400514 e8d7feffff call sym.imp.puts ; int puts(const char *s)
│ ┌──< 0x00400519 eb0a jmp 0x400525
│ ││ ; CODE XREF from main (0x40050d)
│ │└─> 0x0040051b bfba054000 mov edi, 0x4005ba ; const char *s
│ │ 0x00400520 e8cbfeffff call sym.imp.puts ; int puts(const char *s)
│ │ ; CODE XREF from main (0x400519)
│ └──> 0x00400525 b800000000 mov eax, 0
│ 0x0040052a c9 leave
└ 0x0040052b c3 ret
The driver file launches a gdb instance with gdb_attach.py
. Additional python variables can be passed using -ex
flag. gdb_attach.py
sets a breakpoint at an offset and changes some value. You can print values when a bp is hit and parse them in the main driver script. This is quite hackish but it does the job.
Here's how it looks
$ python driver.py 0
Breakpoint hit ::: True
Breakpoint 1 at 0x40050b
HIT
Breakpoint 1, 0x000000000040050b in main ()
No!
[Inferior 1 (process 3874) exited normally]
$ python driver.py 1
Breakpoint hit ::: True
Breakpoint 1 at 0x40050b
HIT
Breakpoint 1, 0x000000000040050b in main ()
Yeaa!
[Inferior 1 (process 3947) exited normally]
See how I was able to print/detect hit breakpoints and change the flow of the binary using another python script. Hope this helps.