Read/write a variable/symbol from inside GDB's python-interactive mode - c

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))

Related

Buffer overflow attack without changing the return address

I need to call the login function in the below sample code. We can achieve this by changing the return address to the login function directly using buffer overflow attack. But I need to keep the return address as the same. Is there any other way to print logged in message without changing the return address?
char getPass()
{
int flag = 'F';
char pass[10];
gets(pass);
return (char) flag;
}
void login()
{
printf("Logged in");
exit(0);
}
void main()
{
printf("Enter Passwd");
if(getPass() == 'T')
{
login();
}else{
print("Failed");
exit(1);
}
}
Getting this to work depends on how the compiler decided to arrange the variables. If flag appears in memory after pass, then entering in more characters than pass will hold results in flag getting overwritten.
When I ran this program in a debugger and printed the addresses of these variables, I got the following:
(gdb) start
Temporary breakpoint 1 at 0x40060e: file x1.c, line 19.
Starting program: /home/dbush/./x1
Temporary breakpoint 1, main () at x1.c:19
19 printf("Enter Passwd");
Missing separate debuginfos, use: debuginfo-install glibc-2.17-292.el7.x86_64
(gdb) step
20 if(getPass() == 'T')
(gdb)
getPass () at x1.c:6
6 int flag = 'F';
(gdb)
8 gets(pass);
(gdb) p pass
$1 = "\000\000\000\000\000\000\000\000", <incomplete sequence \341>
(gdb) p &pass
$2 = (char (*)[10]) 0x7fffffffdec0
(gdb) p &flag
$3 = (int *) 0x7fffffffdecc
We can see that in this particular instance that flag is 12 bytes past the start of pass. My machine is also little-endian, meaning that the first of the 4 bytes of flag contain the value to be overwritten.
So we can exploit the buffer overflow vulnerability by entering in 13 characters, the last of which is T. This results in 10 characters being written to pass, two more to the padding bytes between pass and flag, the character T in the first byte of flag, and a 0 for the terminated null byte in the second byte of flag. Now the variable flag contains 'T' which is what gets returned from the function.
Note also that doing so doesn't write past flag into the function's return value. This is possible because flag is an int and little endian byte ordering is used.
Sample input/output:
[dbush#db-centos7 ~]$ ./x1
Enter Passwd1234567890TTT
Logged in[dbush#db-centos7 ~]$

GCC based SIGSEGV error?

So I have been writing a handful of C libraries for my own personal use and I have been doing swell until my latest library, which just contains a bunch of string functions. As you can probably tell by the question title, I am getting a SIGSEGV signal. The problem is this: my research indicates that about 99% of all SIGSEGV errors are due to stack overflow, itself due to bad recursion, but as you will see, I am not using any recursion. Furthermore, there are a few odd problems that occur. For one, printf is exhibiting a lot of funky behavior. GDB encounters printf calls but does not actually seem to execute them until a few lines of code later. Likewise, one of my printf statements is being broken up somehow, and only a part is being called, with another part being chopped off apparently.
Here are the key code snippets, some stuff is named funny because I suspected name clashing may be the cause at one point and may have gone a little overboard...
"firstIndexOf" function (finds the first index of a character in a string, if that character is in said string), found at line 31:
int firstIndexOfFUNCTION(char thisChar, char* inThisString)
{
int lengthABC = strlen(inThisString);
printf("\nLength of %s is %d",inThisString,lengthABC);
int thisFunctionsIndex;
for (thisFunctionsIndex=0;thisFunctionsIndex<lengthABC;thisFunctionsIndex++)
{
printf("\n%dth iteration:\n-char 1 is %c\n-char2 is %c",thisFunctionsIndex,inThisString[thisFunctionsIndex],thisChar);
if (inThisString[thisFunctionsIndex] == thisChar)
{
printf("\nMatch found on iteration %d!",thisFunctionsIndex);
return thisFunctionsIndex;
}
}
printf("\nNo matches detected...");
return -3;
}
The "string_functions_test" function (a function just meant to test the other functions) at line 62:
int string_functions_test()
{
printf("PROGRAM INITIALIZED!\n\n");
char* sft_string;
int sft_index;
sft_string = malloc(sizeof(char)*100);
sft_string = "B um sbm. Sbm B bm.";
printf("2nd BREAKPOINT");
sft_index = firstIndexOfFUNCTION('B',sft_string);
sft_string[sft_index] = 'I';
return 0;
}
and last but not least, good ol' main, at line 107:
int main(int argc, char* argv[])
{
string_functions_test();
return 0;
}
Here is the gdb output for a step-through of my code:
(gdb) b 105
Breakpoint 1 at 0x400970: file string_functions.c, line 105.
(gdb) run
Starting program: /home/user/Development/projects/c/string_functions/source/c/a.out
Breakpoint 1, main (argc=1, argv=0x7fffffffde98) at string_functions.c:109
109 string_functions_test();
(gdb) step
string_functions_test () at string_functions.c:64
64 printf("PROGRAM INITIALIZED!\n\n");
(gdb) next
PROGRAM INITIALIZED!
68 sft_string = malloc(sizeof(char)*100);
(gdb) next
69 sft_string = "B um sbm. Sbm B bm.";
(gdb) next
71 printf("2nd BREAKPOINT");
(gdb) next
73 sft_index = firstIndexOfFUNCTION('B',sft_string);
(gdb) step
firstIndexOfFUNCTION (thisChar=66 'B', inThisString=0x400ab9 "B um sbm. Sbm B bm.") at string_functions.c:33
33 int lengthABC = strlen(inThisString);
(gdb) next
34 printf("\nLength of %s is %d",inThisString,lengthABC);
(gdb) next
2nd BREAKPOINT
36 for (thisFunctionsIndex=0;thisFunctionsIndex<lengthABC;thisFunctionsIndex++)
(gdb) next
38 printf("\n%dth iteration:\n-char 1 is %c\n-char2 is %c",thisFunctionsIndex,inThisString[thisFunctionsIndex],thisChar);
(gdb) next
Length of B um sbm. Sbm B bm. is 19
0th iteration:
-char 1 is B
39 if (inThisString[thisFunctionsIndex] == thisChar)
(gdb) next
41 printf("\nMatch found on iteration %d!",thisFunctionsIndex);
(gdb) next
-char2 is B
42 return thisFunctionsIndex;
(gdb) next
47 }
(gdb) next
string_functions_test () at string_functions.c:75
75 sft_string[sft_index] = 'I';
(gdb) next
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400883 in string_functions_test () at string_functions.c:75
75 sft_string[sft_index] = 'I';
(gdb) next
Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
(gdb) quit
You may notice that the printf which prints "2nd Breakpoint" is called, and then the program steps into a different function before the results are seen. I am assuming this is some whacky behavior on the part of the gcc compiler meant to serve as a cpu optimization, but it is sort of messing me up right now obviously. Likewise, the printf in my for loop is being broken up after the first formatted char. These two things are making it super hard to detect what exactly is happening. Has anyone experienced similar behavior?
In case it matters, I am including:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
You are first pointing the pointer sft_string to what is returned from malloc. In the next line you make it point to a literal string. You need to copy it. A literal is built into the source code and cannot be changed during execution. Otherwise it raises a segment fault, which means that an area of memory that has code is being changed. Use strcpy.

redirect output to a file from gdb

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

using getopt with gdb

have just incorporated getopt into my main() func
getopt sets the global variable optarg for each call
stepping through main() with gdb, after getopt() call optarg is always NULL (e.g. (gdb) p optarg) yet printf("%s\n", optarg) outputs the cmd line arg as expected
whats going on? why are the two not the same?
Is this an isue with gdb and how it trys to inspect globals or is something else going on?
Probably related: Bug 13800 - gdb does not print right values of getopt-related values
Also notice ie:
(gdb) n
opt: 111, arg,
0x804a040
0x804a034
0x804a020
0x804a030
(gdb) printf "%p\n%p\n%p\n%p\n", &optarg, &opterr, &optind, &optopt
0x2ae760
0x2ab0f4
0x2ab0f8
0x2ab0f0
Where:
(gdb) l
6 int main(int argc, char *argv[])
7 {
8 int c;
9 while ((c = getopt(argc, argv, ":abf:o:")) != -1) {
10 printf("opt: %d, %s, \n"
11 "%p\n%p\n%p\n%p\n",
12 c, optarg,
13 &optarg, &opterr, &optind, &optopt);

GDB printf strange output when debugging

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.

Resources