Search code examples
cdebugginggdbstdinfuzzing

How to find which function from program reads from stdin?


I am currently working on fuzzing a program, and the code base is huge. To improve the performance, I am using persistent mode by creating a loop around the necessary function or code that reads from stdin. Right now using gdb, I am able to enumerate all the functions being used by the program like this:

set logging on
set confirm off
rbreak ^[^@]*$
run the binary 
continue

This gives me all the functions that the program uses, but I think an easier way than reading hundreds of lines is by finding the function that reads from stdin. How would I be able to find the function that reads from stdin?


Solution

  • Since you're running Linux, virtually every function that reads from a stream (such as stdin) will ultimately do a read system call. (Less often, they will call readv.)

    The C prototype for the read function is

    ssize_t read(int fd, void *buf, size_t count);
    

    and like most Linux system calls, this is pretty much the prototype for the actual system call (all the integer and pointer types are put into registers.)

    On x86_64, the first argument to a system call will be in register rdi. (See Calling conventions.) A value of 0 means stdin.

    So first we will tell GDB to stop the process upon entering the read system call, adding a condition to stop only when its first argument is 0:

    (gdb) catch syscall read
    Catchpoint 1 (syscall 'read' [0])
    (gdb) condition 1 $rdi == 0
    (gdb) run
    Starting program: cat
    
    Catchpoint 1 (call to syscall read), 0x00007fffff13b910 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:84
    84      ../sysdeps/unix/syscall-template.S: No such file or directory.
    

    Now do a backtrace to see all the functions in the call stack:

    (gdb) bt
    #0  0x00007fffff13b910 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:84
    #1  0x00007fffff0d2a84 in __GI__IO_file_xsgetn (fp=0x7fffff3f98c0 <_IO_2_1_stdin_>, data=<optimized out>, n=4096)
        at fileops.c:1442
    #2  0x00007fffff0c7ad9 in __GI__IO_fread (buf=<optimized out>, size=1, count=4096, fp=0x7fffff3f98c0 <_IO_2_1_stdin_>)
        at iofread.c:38
    #3  0x00000000080007c2 in copy () at cat.c:6
    #4  0x00000000080007de in main () at cat.c:12
    (gdb) fr 3
    #3  0x00000000080007c2 in copy () at cat.c:6
    6               while ((n=fread(buf, 1, sizeof buf, stdin)) > 0)
    (gdb) fr 4
    #4  0x00000000080007de in main () at cat.c:12
    12              copy();