Question
I have a test program called scan (see code section) that I run in one terminal. The program starts running and asks the user to enter a letter:
$ ./scan
Enter a letter
In another terminal window, I run gdb and attach to the scan process:
$ sudo gdb -p `pidof scan`
(gdb)
I would like to send contents of a binary file called payload as input to the scan process. How can I accomplish this in gdb while the process is attached? Is this possible?
Background
I want to attach to the scan process because I want to examine the program's ASLR address space while running. If I run the process directly with gdb ($ gdb scan), gdb turns off ASLR and I get consistent addressing.
For example, running scan directly with gdb (please note that ... is truncated output):
$ gdb scan
(gdb) info functions
...
0x00000000000005a8 _init
0x00000000000005d0 __stack_chk_fail#plt
0x00000000000005e0 printf#plt
0x00000000000005f0 __isoc99_scanf#plt
...
The addresses shown above are the same every time I run gdb this way, which indicates that gdb turns off ASLR. However, when attaching to a process, the addresses always change. On one run:
$ sudo gdb -p `pidof scan`
(gdb) info functions
...
0x00005598706305a8 _init
0x00005598706305d0 __stack_chk_fail#plt
0x00005598706305e0 printf#plt
0x00005598706305f0 __isoc99_scanf#plt
On another run:
0x000055813ccf65a8 _init
0x000055813ccf65d0 __stack_chk_fail#plt
0x000055813ccf65e0 printf#plt
0x000055813ccf65f0 __isoc99_scanf#plt
The file payload contains a binary payload. I know how to send file contents as input when running gdb normally (e.g. (gdb) run < payload), but not when running with an attached process.
I do not want to copy/paste these file contents into the terminal that is runningscan. I also do not want to turn off ASLR.
Things I have tried/read
I have read the gdb manual and gdb help commands:
(gdb) help
(gdb) help target
(gdb) help attach
(gdb) help obscure
Other StackOverflow questions do not ask about sending input to an attached process:
Pass File Input and Stdin to gdb
How to debug a program that takes user input from stdin with GDB?
How to passing input data in GDB mode for programming C. Already passed parameters and run program
Code
My entire scan program is this:
#include <stdio.h>
int main(int argc, char **argv)
{
char letter[1];
char buffer[8];
printf("Enter a letter: ");
int result = scanf("%s", letter);
printf("You entered: %s\n", letter);
}
Related
Here is my very simple program that I am trying to debug with cgdb. Problem is once I get to the "scanf" line, it prompts for an input, but once I press enter after entering the input (2 in the example below) it seems to enter into an infinite loop. It works fine in gdb though.
#include <cstdio>
using namespace std;
int main()
{
int n;
scanf("%d", &n);
printf("%d\n", n);
return 0;
}
Here is the execution trace in terminal:
Type "apropos word" to search for commands related to "word"...
Reading symbols from test...done.
(gdb) start
Temporary breakpoint 1 at 0x400585: file test.cpp, line 7.
Starting program: /home/Alex/Desktop/test
Temporary breakpoint 1, main () at test.cpp:7
(gdb) next
2 (this is my input)
Infinite loop starts here.
According to the info page of cgdb, you need to either:
start the program on one terminal, and attach to it with CGDB from another terminal
or pass arguments using the tty window
To invoke the tty window, hit 'T' in command mode (escape)
Extracted from the info page:
Sending I/O to the program being debugged
This technique is similar to getting in and out of "GDB mode". The tty window is not
visible by default. This is because it is only needed if the user
wishes to send data to the program being debugged. To display the tty
window, hit `T' while in command mode.
We're learning to use GDB in my Computer Architecture class. To do this we do most of our work by using SSH to connect to a raspberry pi. When running GDB on some code he gave us to debug though it ends with an error message on how it can't find raise.c
I've tried:
installing libc6, libc6-dbg (says they're already up-to-date)
apt-get source glibc (gives me: "You must put some 'source' URIs in your sources.list")
https://stackoverflow.com/a/48287761/12015458 (apt source returns same thing as the apt-get source above, the "find $PWD" command the user gave returns nothing)
I've tried looking for it manually where told it may be? (/lib/libc doesn't exist for me)
This is the code he gave us to try debugging on GDB:
#include <stdio.h>
main()
{
int x,y;
y=54389;
for (x=10; x>=0; x--)
y=y/x;
printf("%d\n",y);
}
However, whenever I run the code in GDB I get the following error:
Program received signal SIGFPE, Arithmetic exception.
__GI_raise (sig=8) at ../sysdeps/unix/sysv/linux/raise.c:50
50 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
I asked him about it and he didn't really have any ideas on how to fix it.
It does not really matter that the source for raise() is not found. It would only show you the line where the exception is finally raised, but not the place where the error is triggered.
Run the erroneous program again in GDB. And when the exception is raised, investigate the call stack and the stackframes with GBDs commands. This is the point in your task, so I won't give you more than this hint.
If you're clever you can see the error in the given source just by looking at it. ;-)
When GDB does not know any symbol, you need to compile with the option -g to get debugger support.
EDIT
Now on a Windows system this is my log (please excuse the colouring, I didn't found a language selector for pure text):
D:\tmp\StackOverflow\so_027 > type crash1.c
#include <stdio.h>
main()
{
int x,y;
y=54389;
for (x=10; x>=0; x--)
y=y/x;
printf("%d\n",y);
}
D:\tmp\StackOverflow\so_027 > gcc crash1.c -g -o crash1.out
crash1.c:2:1: warning: return type defaults to 'int' [-Wimplicit-int]
main()
^~~~
D:\tmp\StackOverflow\so_027 > dir
[...cut...]
04.09.2019 08:33 144 crash1.c
04.09.2019 08:40 54.716 crash1.out
D:\tmp\StackOverflow\so_027 > gdb crash1.out
GNU gdb (GDB) 8.1
[...cut...]
This GDB was configured as "x86_64-w64-mingw32".
[...cut...]
Reading symbols from crash1.out...done.
(gdb) run
Starting program: D:\tmp\StackOverflow\so_027\crash1.out
[New Thread 4520.0x28b8]
[New Thread 4520.0x33f0]
Thread 1 received signal SIGFPE, Arithmetic exception.
0x0000000000401571 in main () at crash1.c:7
7 y=y/x;
(gdb) backtrace
#0 0x0000000000401571 in main () at crash1.c:7
(gdb) help stack
Examining the stack.
The stack is made up of stack frames. Gdb assigns numbers to stack frames
counting from zero for the innermost (currently executing) frame.
At any time gdb identifies one frame as the "selected" frame.
Variable lookups are done with respect to the selected frame.
When the program being debugged stops, gdb selects the innermost frame.
The commands below can be used to select other frames by number or address.
List of commands:
backtrace -- Print backtrace of all stack frames
bt -- Print backtrace of all stack frames
down -- Select and print stack frame called by this one
frame -- Select and print a stack frame
return -- Make selected stack frame return to its caller
select-frame -- Select a stack frame without printing anything
up -- Select and print stack frame that called this one
Type "help" followed by command name for full documentation.
Type "apropos word" to search for commands related to "word".
Command name abbreviations are allowed if unambiguous.
(gdb) next
Thread 1 received signal SIGFPE, Arithmetic exception.
0x0000000000401571 in main () at crash1.c:7
7 y=y/x;
(gdb) next
[Inferior 1 (process 4520) exited with code 030000000224]
(gdb) next
The program is not being run.
(gdb) quit
D:\tmp\StackOverflow\so_027 >
Well, it marks directly the erroneous source line. That is different to your environment as you use a Raspi. However, it shows you some GDB commands to try.
Concerning your video:
It is clear that inside raise() you can't access x. That's why GDB moans about it.
If an exception is raised usually the program is about to quit. So there is no value in stepping forward.
Instead, as shown in my log, use GDB commands to investigate the stack frames. I think this is the issue you are about to learn.
BTW, do you know that you should be able to copy the screen content? This will make reading so much easier for us.
From a practical standpoint the other answer is correct, but if you do want the libc sources:
apt-get source is the right way to get the sources of libc, but yes, you do need to have source repositories configured in /etc/apt/sources.list.
If you're using Ubuntu, see the deb-src lines in https://help.ubuntu.com/community/Repositories/CommandLine
For debian, see https://wiki.debian.org/SourcesList#Example_sources.list
Then apt-get source should work. Remember to tell GDB where those sources are using the "directory" command.
Say with this simple code:
#include<stdio.h>
int main(int argc, char** argv){
printf("Hello World!\n");
return 0;
}
After stepping printf("Hello World!\n”); perhaps there’s a command to print that “Hellow World!\n” has been written to STDOUT.
And after return 0 perhaps there’s a command to see the exit codes generated and it will show 0.
Are there such commands or similar in lldb?
LLDB prints the exit status when a process exits:
(lldb) run
Process 76186 launched: '/tmp/a.out' (x86_64)
Process 76186 exited with status = 10 (0x0000000a)
and you can also access it with the SB API's:
(lldb) script lldb.process.GetExitStatus()
10
lldb doesn't have any special knowledge about all the ways a program might read or write data to a pipe, file handle, pty, etc... It also doesn't know how to interpose on file handles and tee-off the output. There's no particular reason it couldn't, but nobody has added that to date.
So you would have to build this yourself. If you know the API your code is using to read and write, you could use breakpoints to observe that - though that might get slow if you are observing a program that reads and writes a lot.
I have a simple C program:
#include <stdlib.h>
int main(int argc, char** argv){
execve(argv[1], &argv[1], NULL);
return 0;
}
If i run gdb --tui myprogram and spawn a shell with the command run "/bin/sh" then gdb will freeze, and i can only terminate it with CTRL-C.
My purpose is to execute shell commands from within gdb (I have a buffer overflow homework)
Is there a way to use the shell from within gdb?
EDIT
I solved the problem removing the --tui option.
Look into using gdbserver. This helpfully disassociates the gdb session from the binary. I use it to debug ncurses text UIs for instance.
On term1:
$ gdbserver :2345 /path/to/my/program
On term2:
$ gdb -q /path/to/my/program
> target remote localhost:2345
> break ......
> continue
When you run gdb in term2, do it from the directory where the source lives.
Also, once you know how to do this you can debug machines over the network. You can also debug from a x86 box a process running on a remote arm if you have the right tools in place. So this is another tool to add to the toolbox.
Good luck.
I use a debugging script that runs several related processes in succession with the debugger. I'm currently using -x to execute several commands automatically (such as run). How can I make gdb quit automatically when the debugged process successfully terminates? Adding a quit command to the command file will cause that command to be handled not just on successful termination, but when errors occur also (when I'd rather take over at that point).
Here's an extract of what's going on:
+ gdb -return-child-result -x gdbbatch --args ./mkfs.cpfs /dev/loop0
GNU gdb (GDB) 7.1-ubuntu
Reading symbols from /home/matt/cpfs/mkfs.cpfs...done.
Program exited normally.
Breakpoint 2 at 0x805224f: file log.c, line 32.
(gdb)
Contents of gdbbatch:
start
b cpfs_log if level >= WARNING
I think I have found a complete solution to your question in connection to looking for something similar in How to make gdb send an external notification on receiving a signal?. None of the other guys here seem to have mentioned or discovered gdb hooks.
Based on Matthew's tip about $_exitcode, this is now my app/.gdbinit that achieves exactly the behavior wanted; normal quit on successful termination and drop to gdb prompt, send email, whatnot on everything else:
set $_exitcode = -999
set height 0
handle SIGTERM nostop print pass
handle SIGPIPE nostop
define hook-stop
if $_exitcode != -999
quit
else
shell echo | mail -s "NOTICE: app has stopped on unhandled signal" root
end
end
echo .gdbinit: running app\n
run
gdb sets $_exitcode when the program successfully terminates. You can make use of that - set it to an unlikely value at the start of your script, and only quit at the end if it has changed:
set $_exitcode = -999
# ...
run
# ...
if $_exitcode != -999
quit
end
(Setting $_exitcode to an unlikely value is a bit ugly, but it will otherwise not be defined at all if the program doesn't terminate, and there doesn't seem to be any obvious way of asking "is this variable defined?" in a conditional.)
GDB has a different "language" for interacting with automated programs called GDB/MI (detailed here), but unfortunately, it doesn't look like it supports conditionals, and is expected to run from other programs with parsing and branching. So, it looks like Expect is the easiest (or at least a working) solution:
$ cat gdbrunner
#!/usr/bin/expect -f
#spawn gdb -return-child-result --args ./mkfs.cpfs /dev/loop0
spawn gdb -return-child-result --args [lindex $argv 0]
#send "start\n"
#send "b cpfs_log if level >= WARNING"
send "run\n"
expect {
normally\. { send "quit\n" }
"exited with code" { interact -nobuffer }
}
I tested this with the simple programs:
$ cat prog1.c
int main(void) { return 0; }
$ cat prog2.c
int main(void) { return 1; }
With the following results:
$ ./gdbrunner ./prog1
spawn gdb -return-child-result --args ./prog1
run
(gdb) run
Starting program: /home/foo/prog1
Program exited normally.
(gdb) quit
$ ./gdbrunner ./prog2
spawn gdb -return-child-result --args ./prog2
run
(gdb) run
Starting program: /home/foo/prog2
Program exited with code 01.
(gdb)
Essentially, you have to parse the output and branch using something else. This would of course work with any other program capable of handling input/output of another process, but the above expect script should get you started, if you don't mind Tcl. It should be a little better, and expect the first (gdb) prompt, but works due to stdin buffering.
You can also modify it to use that GDB/MI interface with the -i command-line argument to GDB; its commands and output are a bit more readily parsable, if you will expand to need more advanced features, as you can see in the previously linked documentation.