I'm currently printing the contents of a variable from gdb like this:
(gdb) call printf("%s",buffer)
The buffer contains a large string and I want to redirect it to a file rather than screen.
Enabling logging feature in gdb will not help here. And I'm not able to use > command to redirect either. Ofcourse I can create a file in the program and write the buffer to this file and invoke the write to file through gdb. But is there a easier way out?
This will redirect the target's stdout to a file of your choice, call printf, then restore stdout to its previous setting. fflush is called right before changing the file descriptor, so that output gets sent to the correct place.
$ gdb f
...
(gdb) list
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4
5 main()
6 {
7 char buf[] = "test";
8
9 printf("%p ", (void *)buf);
10 printf("%d\n", strlen(buf));
11 }
(gdb) break 10
Breakpoint 1 at 0x80484d3: file f.c, line 10.
(gdb) run
Starting program: f
Breakpoint 1, main () at f.c:10
10 printf("%d\n", strlen(buf));
(gdb) call fflush(stdout)
0xbffff117 $1 = 0
(gdb) call dup(1)
$2 = 3
(gdb) call creat("/tmp/outputfile",0644)
$3 = 4
(gdb) call dup2(4,1)
$4 = 1
(gdb) call printf("%s\n", buf)
$5 = 5
(gdb) call fflush(stdout)
$6 = 0
(gdb) call dup2(3,1)
$7 = 1
(gdb) call close(3)
$8 = 0
(gdb) call close(4)
$9 = 0
(gdb) cont
Continuing.
4
[Inferior 1 (process 3214) exited with code 02]
(gdb) shell cat /tmp/outputfile
test
You aren't able to use > or you did not know how to use it in gdb? You can redirect output from inside of gdb. Try:
(gdb) run > out.txt
(gdb) run > /dev/null
Related
I have this simple script written in C:
#include <stdio.h>
void usage(char *program_name) {
printf("Usage: %s <message> <# of times to repeat>\n", program_name);
exit(1);
}
int main(int argc, char *argv[]) {
int i, count;
// if(argc < 3) // If less than 3 arguments are used,
// usage(argv[0]); // display usage message and exit.
count = atoi(argv[2]); // convert the 2nd arg into an integer
printf("Repeating %d times..\n", count);
for(i=0; i < count; i++)
printf("%3d - %s\n", i, argv[1]); // print the 1st arg
}
And I'm making some test with GDB.
I did this:
(gdb) run test
Starting program: /home/user/Desktop/booksrc/convert2 test
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a56e56 in ____strtoll_l_internal () from /usr/lib/libc.so.6
Obviusly it goes in segmentation fault because to work the program needs three argv. And I commented the lines that do the control. So it goes in error.
(gdb) where
#0 0x00007ffff7a56e56 in ____strtoll_l_internal () from /usr/lib/libc.so.6
#1 0x00007ffff7a53a80 in atoi () from /usr/lib/libc.so.6
#2 0x00005555555546ea in main (argc=2, argv=0x7fffffffe958) at convert2.c:14
(gdb) break main
Breakpoint 1 at 0x5555555546d2: file convert2.c, line 14.
(gdb) run test
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user/Desktop/booksrc/convert2 test
Breakpoint 1, main (argc=2, argv=0x7fffffffe958) at convert2.c:14
14 count = atoi(argv[2]); // convert the 2nd arg into an integer
(gdb) cont
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a56e56 in ____strtoll_l_internal () from /usr/lib/libc.so.6
(gdb) x/3xw 0x7fffffffe958 // this is memory of the "argv" some line before
0x7fffffffe958: 0xffffebfe 0x00007fff 0xffffec22
(gdb) x/s 0xffffebfe
0xffffebfe: <error: Cannot access memory at address 0xffffebfe>
(gdb) x/s 0x00007fff
0x7fff: <error: Cannot access memory at address 0x7fff>
(gdb) x/s 0xffffec22
0xffffec22: <error: Cannot access memory at address 0xffffec22>
In theory, with "x/s" I should have seen the commandline in the first address and "test" in the second address and the null in the third. But nothing. If I copy paste that address to a ascii to string converter, it gives me data without any sense. What am I doing wrong?
Your platform uses 64bit pointers, so try :
(gdb) x/3xg 0x7fffffffe958
to display the 64bit pointers in the argv array, and then :
(gdb) x/s 0x00007fffffffebfe
or just :
(gdb) p argv[0]
First of all always check if the command line is correct
Uncomment the check from your code.
Then in the gdb set the arguments (before running it)
(gdb) set args "hello world" 12
In my program, I open a file and write "Hello world" in it. I am using snprintf() to populate 'fname' variable. After this I put gdb on a.out and print the string 'fname'. I see that there are lots of extra character in string 'fname' which I did not assign. Where are these extra characters coming from? Could anyone help please?
3 int main(void)
4 {
5 FILE *debug_fp = NULL;
6 char fname[100];
7
8 snprintf(fname, 100, "./my_debug_%d", getpid());
9 debug_fp = fopen(fname, "w");
10 fprintf(debug_fp, "%s", "Hello world");
11 return 0;
12 }
gdb output:
(gdb) b test.c:10
Breakpoint 1 at 0x4005be: file test.c, line 10.
Breakpoint 1, main () at test.c:10
10 fprintf(debug_fp, "%s", "Hello world");
(gdb) p fname
$1 = "./my_debug_16178\000\000\000\000\000\000\000\000\300\313Ab:\000\000\000\360\005#\000\000\000\000\000\063\004#\000\000\000\000\000\001\000\000\000\000\000\301\000'\006#", '\000' <repeats 13 times>"\300, \313Ab:\000\000\000\360\005#", '\000' <repeats 13 times>"\260, \343\377\377"
(gdb) q
Thank you.
In this case gdb doesn't care about your 0-terminator in the string and just prints the array, i.e. the full 100 characters in fname.
You can also use printf "%s" or p /s if you want gdb to treat your array as a C-string.
As your question is about seeing a lot of extra characters that you didnt assign, it is always the best practice to initialize the memory (simple variables, arrays or pointers) you define, so that you always see what you expect.
In your case, you could do:
char fname[100] = {0};
The response I get from gdb is more predictable thus:
(gdb) b 9
Breakpoint 1 at 0x400610: file st_fname.c, line 9.
(gdb) run
Starting program: /home/gops/data/samples/st_fname.o
Breakpoint 1, main () at st_fname.c:9
9 fprintf(debug_fp, "%s", "Hello world");
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.166.el6_7.7.x86_64
(gdb) p fname
$1 = "./my_debug_26808", '\000' <repeats 83 times>
(gdb)
Now you should see what you expect. Hope it helps.
I'm experimenting with python-interactive mode in gdb, and I can't figure out how to change a variable from inside it. I know how to do it without python - set variable a = 10.
I'm using this test program:
#include <stdio.h>
int main(int argc, char *argv) {
int a;
printf("Enter a: ");
scanf("%d", &a);
printf("You entered: %d\n", a);
}
I've placed a breakpoint after the scanf(), and when it's hit I enter python interactive mode. Now I want to change the variable a to some other value. I tried using a = 10, but it wasn't changed, and the same value I entered in the scanf() (in this case it's 5) was printed instead.
(gdb) b main.c:6
Breakpoint 1 at 0x8048503: file main.c, line 6.
(gdb) r
Starting program: /home/sashoalm/Desktop/test/a.out
Enter a: 5
Breakpoint 1, main (argc=1, argv=0xbffff1d4 "\214\363\377\277") at main.c:6
6 printf("You entered: %d\n", a);
(gdb) python-interactive
>>> a = 10
>>>
(gdb) c
Continuing.
You entered: 5
[Inferior 1 (process 26133) exited normally]
So what is the correct way to do it?
After some searching through the Python API documentation I found the answer. I needed to use gdb.execute('set var a = 10'), which allows python scripts to execute gdb commands, and the commands are evaluated as if the user has written them.
I used this code to read a, add 5 to it and then set it:
symbol = gdb.lookup_symbol('a')[0]
frame = gdb.selected_frame()
value = symbol.value(frame)
gdb.execute('set var a = %d' % (int(value)+5))
I am reading a book titled Hacking: The Art of Exploitation, and I have a problem with the section Stack-Based Buffer Overflow Vulnerabilities.
I am following the instructions given by the author, but I don't get the expected results.
First, here is the program auth_overflow2.c, copied from the book:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int check_authentication(char *password) {
char password_buffer[16];
int auth_flag = 0;
strcpy(password_buffer, password);
if(strcmp(password_buffer, "brillig") == 0)
auth_flag = 1;
if(strcmp(password_buffer, "outgrabe") == 0)
auth_flag = 1;
return auth_flag;
}
int main(int argc, char *argv[]) {
if(argc < 2) {
printf("Usage: %s <password>\n", argv[0]);
exit(0);
}
if(check_authentication(argv[1])) {
printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
printf(" Access Granted.\n");
printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
} else {
printf("\nAccess Denied.\n");
}
}
This is a copy of my Ubuntu terminal:
(gdb) break 19
Breakpoint 1 at 0x40077b: file auth_overflow.c, line 19.
(gdb) break 7
Breakpoint 2 at 0x4006df: file auth_overflow.c, line 7.
(gdb) break 12
Breakpoint 3 at 0x40072a: file auth_overflow.c, line 12.
(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Starting program: /home/test/a.out AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Breakpoint 1, main (argc=2, argv=0x7fffffffdf08) at auth_overflow.c:19
19 if(check_authentication(argv[1])) {
(gdb) i r esp
esp 0xffffde10 -8688
(gdb) x/32xw $esp
0xffffffffffffde10: Cannot access memory at address 0xffffffffffffde10
(gdb) c
Continuing.
Breakpoint 2, check_authentication (password=0x7fffffffe2cc 'A' <repeats 30 times>) at auth_overflow.c:7
7 strcpy(password_buffer, password);
(gdb) i r esp
esp 0xffffddc0 -8768
(gdb) x/32xw $esp
0xffffffffffffddc0: Cannot access memory at address 0xffffffffffffddc0
(gdb) p 0xffffde10 - 0xffffddc0
$1 = 80
(gdb) x/s password_buffer
0x7fffffffdde0: "\001"
(gdb) x/x &auth_flag
0x7fffffffdddc: 0x00
(gdb)
When i try x/32xw $esp i get:
0xffffffffffffde10: cannot access memory at address 0xffffffffffffde10
Same thing happens when i continue to the second break point.
When author types x/s password_buffer the output is:
0xbffff7c0: "?o??\200????????o???G??\020\205\004\b?????\204\004\b????\020\205\004\bH???????\002"
but my output looks like this:
0x7fffffffdde0: "\001"
My i r esp result is also different from the book.
in the book there are two hexadecimal numbers:
esp 0xbffff7e0 0xbffff7e0
I am using Ubuntu and GCC and GDB.
I think I might have the answer - your argv[ 1 ] is pointing to the 30 'A's - and you have a password buffer of 16. The strcpy() will just fill the buffer and beyond.
I would increase the buffer size to a larger size (say 255 bytes).
In practise, you should review your code, even examples, and make them more robust (example: allowing for larger passwords then 16 )
Please less the number of As try A(17) times it will work
Why is the output of the printf is not show when stepping out the line? But at some point it did print line 16.
c file:
#include<stdio.h>
void nextfunc(){
int ctr;
for(ctr = 0; ctr<3; ctr++){
printf("print ctr = %d",ctr);
}
printf("last print");
}
void main(){
int x;
printf("input x: ");
scanf("%d",&x);
printf("\nprint 2");
printf("\nprint 3");
nextfunc();
}
GDB:
(gdb) break main
Breakpoint 1 at 0x8048479: file file5.c, line 14.
(gdb) break nextfunc
Breakpoint 2 at 0x804843a: file file5.c, line 6.
(gdb) run
Starting program: /home/charmae/workspace/AVT/file5
Breakpoint 1, main () at file5.c:14
14 printf("input x: ");
(gdb) s
15 scanf("%d",&x);
(gdb) s
input x: 4
16 printf("\nprint 2");
(gdb) s
17 printf("\nprint 3");
(gdb) s
print 2
18 nextfunc();
(gdb) s
Breakpoint 2, nextfunc () at file5.c:6
6 for(ctr = 0; ctr<3; ctr++){
(gdb) s
7 printf("print ctr = %d",ctr);
(gdb) s
6 for(ctr = 0; ctr<3; ctr++){
(gdb) s
7 printf("print ctr = %d",ctr);
(gdb) s
6 for(ctr = 0; ctr<3; ctr++){
(gdb) s
7 printf("print ctr = %d",ctr);
(gdb) s
6 for(ctr = 0; ctr<3; ctr++){
(gdb) s
9 printf("last print");
(gdb) s
10 }
(gdb) s
main () at file5.c:19
19 }
(gdb) s
0x0014a113 in __libc_start_main () from /lib/i386-linux-gnu/libc.so.6
(gdb) s
Single stepping until exit from function __libc_start_main,
which has no line number information.
print 3print ctr = 0print ctr = 1print ctr = 2last print[Inferior 1 (process 2578) exited with code 012]
Output though stdout is buffered. That means it is saved in a temporary buffer either until the buffer is full, there is a newline being printed or the function fflush(stdout) is called. stdout is flushed automatically also when the program ends.
The reason your output is printed "on the wrong place" in GDB is because of this buffering. you should either add newlines to the end of the printf format string, or explicitly call fflush.
stdio functions like printf are buffered, so it outputs only when it encounters newline.
If you want immediate print use newline character \n or fflush(stdout); after every printf
edit:
Why does printf not flush after the call unless a newline is in the format string?
The trick is that you didn't put in a newline:
printf("last print");
The standard IO library is going to buffer the output until it sees a newline to print. Output to terminals is usually line-buffered; probably gdb runs the program as if it is connected to a terminal, so it prints the previous lines with the \n character in them as they are printed.
The output actually is in the output you've got:
... ctr = 2last print[In ...
The standard IO library flushes all its input streams just before exiting -- via an atexit(3) exit handler -- so the output gets flushed just before the program asks the operating system to tear down its memory and inform its parent that it is dead.