confusion with dereferencing argv - c

I have this small program:
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[]) {
printf("argv[1] -> %s\n", argv[1]);
}
Which I analyzed in gdb with the following commands:
$ gdb -q --args foo hello
Reading symbols from foo...
(gdb) break main
Breakpoint 1 at 0x1148: file foo.c, line 5.
(gdb) run
Starting program: /tmp/foo/foo hello
Breakpoint 1, main (argc=2, argv=0x7fffffffea68) at foo.c:5
5 printf("argv[1] -> %s\n", argv[1]);
(gdb) print argv#2
$1 = {0x7fffffffea68, 0x200000000}
(gdb) print *argv#2
$2 = {0x7fffffffecd8 "/tmp/foo/foo", 0x7fffffffece5 "hello"}
I don't understand how argv[1] can yield the string "hello" when the content of argv[1] is
0x200000000 and not 0x7fffffffece5 which is the actual address of the string "hello".

print argv#2 doesn't do what you think it does. Instead of printing argv[0] and argv[1], it appears to print (&argv)[0] and (&argv)[1].
Here's what I got when I tried debugging your program:
(gdb) p argv
$1 = (char **) 0x7fffffffecd8
(gdb) p argv[0]
$2 = 0x7fffffffeeb8 "/home/a.out"
(gdb) p argv[1]
$3 = 0x0
(gdb) p argv#2
$4 = {0x7fffffffecd8, 0x100000000}
(gdb) p (&argv)[1]
$5 = (char **) 0x100000000

I used the examine command in gdb and now things make sense:
(gdb) x/2xg argv
0x7fffffffea58: 0x00007fffffffecc2 0x00007fffffffecd5
(gdb) x/1s 0x00007fffffffecc2
0x7fffffffecc2: "/tmp/foo/foo"
(gdb) x/1s 0x00007fffffffecd5
0x7fffffffecd5: "hello"
(gdb)

Related

C code to access environment variables

I created an environment variable SHELLCODE which contains a 200-byte long NOP sled and a shellcode. It is stored at 0x7fffffffe285, but I'll try to access 0x7fffffffe2e5, which is around the middle of the NOP sled.
Then I wrote the following code to try to access the variable.
#include <stdlib.h>
int main() {
char *pointer = 0x00007fffffffe2e5;
printf("%s\n", *pointer);
}
I used gdb to see the memory
(gdb) list 1
1 #include <stdio.h>
2
3 int main() {
4 char *pointer = (char *) 0x00007fffffffe2e5;
5 printf("%s\n", *pointer);
6 }
(gdb) break 5
(gdb) run
(gdb) p pointer
$1 = 0x7fffffffe2e5 '\220' <repeats 119 times>, "\061\300\061\333\061ə\260\244̀j\vXQh//shh/bin\211\343Q\211\342S\211\341̀"
(gdb) p *pointer
$2 = -112 '\220'
(gdb) p/x *pointer
$3 = 0x90
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a5bcc0 in _IO_vfprintf_internal (
s=0x7ffff7dd2620 <_IO_2_1_stdout_>, format=<optimized out>,
ap=ap#entry=0x7fffffffdc58) at vfprintf.c:1632
1632 vfprintf.c: No such file or directory.
The pointer was clearly pointing to the middle of the NOP sled, and gdb could access and see what was at that address. But I keep getting this Segmentation fault error.
Is this because C programs are not allowed to access memory where environment variables are stored? If so, is there a way to allow it to access the memory?
I'm using Ubuntu 16.04 and gcc 5.4.0.
Thanks in advance.
The getenv function is used to retrieve the values of environment variables:
const char *shellcode = getenv("SHELLCODE");

GDB misses to display const qualifier?

Give the following source (main.c):
void foo(const char (*pa)[4])
{
}
int main(void)
{
const char a[4] = "bar";
foo(&a);
}
... compiled with GCC (gcc (Debian 4.9.2-10) 4.9.2) and run under GDB (GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1) ...
(gdb) b main
Breakpoint 1 at 0x4004c8: file main.c, line 7.
(gdb) b foo
Breakpoint 2 at 0x4004be: file main.c, line 3.
(gdb) r
Breakpoint 1, main () at main.c:7
7 const char a[4] = "bar";
(gdb) p &a
$1 = (const char (*)[4]) 0x7fffffffe1a0
(gdb) c
Continuing.
Breakpoint 2, foo (pa=0x7fffffffe1a0) at main.c:3
3 }
(gdb) p pa
$2 = (char (*)[4]) 0x7fffffffe1a0
... why does GDB show me (char (*)[4]) instead of (const char (*)[4]) as type for foo()'s parameter pa? What happened to the const qualifier? Or am I missing something essential? :-S
Update:
pa behaves as expected. If for example doing
char (*t)[4] = pa;
inside foo() the compiler complains:
warning: initialization from incompatible pointer type
Whereas doing
const char (*t)[4] = pa;
works fine.

Why doesn't gdb see when `stdio` is changed?

According to the GNU C library it's allowed to assign to stdio just as if they were ordinary variables (I know this is an extension). I tried following program:
#include <stdio.h>
int main()
{
stdout = NULL;
printf("Crash and %s\n", "burn");
return 0;
}
When running the program it will segfault as expected, but when I run it in gdb the value of stdout is still not NULL:
_IO_vfprintf_internal (s=0x0, format=0x400631 "Crash and %s\n", ap=0x7fffffffe210) at vfprintf.c:1297
1297 vfprintf.c: No such file or directory.
(gdb) print stdout
$1 = (struct _IO_FILE *) 0x7ffff7dd77a0
(gdb)
Why doesn't gdb report the correct value of stdout?
Investigating this further I see that it seem to store stdout at address 0x600940, looking for a struct _IO_FILE* there I'd find a pointer that's the same as gdb reports as stdio:
(gdb) print stdout
$1 = (struct _IO_FILE *) 0x7ffff7dd77a0
(gdb) print (void*)0x600940
$2 = (void *) 0x600940
(gdb) print (struct _IO_FILE*)0x600940
$3 = (struct _IO_FILE *) 0x600940
(gdb) print *(struct _IO_FILE**)0x600940
$4 = (struct _IO_FILE *) 0x7ffff7dd77a0
(gdb) n
7 puts("Crash and burn");
(gdb) print *(struct _IO_FILE**)0x600940
$5 = (struct _IO_FILE *) 0x0
(gdb) print &stdio
No symbol "stdio" in current context.
(gdb) print &stdout
$6 = (struct _IO_FILE **) 0x7ffff7dd7d90
Here it looks like gdb think that stdout is located at 0x7ffff7dd7d90, but in reality it's located at 0x600940.
I'm using GNU gdb (GDB) 7.4.1-debian and gcc version 4.7.2 (Debian 4.7.2-5) (x86-64).
I think that your gdb is functioning correctly. Look at these lines you quoted:
_IO_vfprintf_internal (s=0x0, format=0x400631 "Crash and %s\n", ap=0x7fffffffe210) at vfprintf.c:1297
1297 vfprintf.c: No such file or directory.
(gdb) print stdout
$1 = (struct _IO_FILE *) 0x7ffff7dd77a0
(gdb)
The signature of _IO_vfprintf_internal() has the destination stream s as the first parameter. Because you are in a different level of your stack and stdout is not a global variable, it get re-assigned. But you can see that your assignment took hold because s=0x0.

strcpy-sse2-unaligned.S not found

I am compiling the simple code below, and run it in gdb. I set a break point at the strcpy line, as soon as I run it for the input for instance abc, and then press s, I get the following error:
Breakpoint 1, main (argc=2, argv=0x7fffffffdd98) at ExploitMe.c:9
9 strcpy(buffer, argv[1]);
(gdb) s
__strcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:48
48 ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: No such file or directory.
I am using ubuntu 12.04 AMD64 and gcc 2.15. Any idea?
main(int argc, char *argv[]) {
char buffer[80];
strcpy(buffer, argv[1]);
return 0;
}
It is completely harmless to ignore these "errors" when debugging.
The error is simply because GDB is looking for the source of the strcpy function. Any function in libc that you don't have the source for will you give a similar error, e.g.:
int *p = malloc(sizeof *p);
Then...
(gdb) s
5 int *p = malloc(sizeof *p);
(gdb) s
__GI___libc_malloc (bytes=4) at malloc.c:2910
2910 malloc.c: No such file or directory.
You can always download GNU libc's source and link it with GDB:
git clone https://github.com/jeremie-koenig/glibc /opt/src/glibc
Then...
(gdb) dir /opt/src/glibc/malloc
(gdb) s
5 int *p = malloc(sizeof *p);
(gdb) s
__GI___libc_malloc (bytes=4) at malloc.c:2910
2910 }
(gdb) s
2915 } else if (!in_smallbin_range(size))
... which will let you step through malloc's source code. It's not particularly useful, but it can come in handy sometimes.

accessing command-line arguments with gdb

I am on linux using gdb version 6.8-debian. I have been curious about how the main function in a c-program gets executed and playing around and looking in different places, I learned that the function __libc_start_main is responsiple for this. The arguments to __libc_start_main are, among others: The address of main (like we know from c, the path is always given as argv[0]), next argc which should reside in the register ESI, and next address of argv which should be in ECX.
To play around I made the following simple program, cmdargs.c, which simply outputs the first command-line argument given at start:
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
printf("%s: %s\n", "argv[1]", *++argv);
return EXIT_SUCCESS;
}
Now I start to debug cmdargs and set a breakpoint on main and __libc_start_main (info from starting gdb removed):
gdb cmdargs
(gdb) b main
Breakpoint 1 at 0x80483d2
(gdb) b __libc_start_main
Breakpoint 2 at 0xb7f3f5a8
(gdb) r qwerty
Here i hit the Breakpoint 2 in __libc_start_main and can view argc and argv[0] with
(gdb) p $esi
and
(gdb) x/s *($ecx)
This works as expected, but how do I access the first non-implicit commandline-argument "qwerty" ? I have tried continuing to the breakpoint at main and stepping in, but argc and argv are not recognised (Why?). Can someone tell me whats going on ?
Breakpoint 1, 0x080483d2 in main ()
(gdb) stepi
0x080483d5 in main ()
(gdb) p argc
No symbol "argc" in current context.
(gdb) p argv
No symbol "argv" in current context.
(gdb)
Yep, your problem is the lack of symbols, not included at compilation time.
To compile with debugging information:
$ gcc -g3 cmdargs.c -o cmdargs
Then:
$ gdb ./cmdargs
...
Reading symbols from ./cmdargs...done.
(gdb) b main
Breakpoint 1 at 0x400545: file cmdargs.c, line 6.
(gdb) r
Starting program: cmdargs
Breakpoint 1, main (argc=1, argv=0x7fffffffdc28) at cmdargs.c:6
6 printf("%s: %s\n", "argv[1]", *++argv);
(gdb) p argc
$1 = 1
(gdb) p argv
$2 = (char **) 0x7fffffffdc28
(gdb) p *argv
$3 = 0x7fffffffe00c "/home/jcgonzalez/cmdargs"
See, now you get access to the symbols (they are recognized), as well as to the line numbers. As shown by Let_Me_Be, you can access single array elements with array[n] notation, but you can also show all the command line arguments at once (including the [0]-ed one) with the *array#times notation. Note that the first argument in the following example is a quoted string:
(gdb) set args "this is an argument" these are four more
(gdb) r
Starting program: cmdargs "this is an argument" these are four more
Breakpoint 1, main (argc=6, argv=0x7fffffffdbd8) at cmdargs.c:6
6 printf("%s: %s\n", "argv[1]", *++argv);
(gdb) p argc
$4 = 6
(gdb) p *argv#argc
$5 = {0x7fffffffdfe6 "/home/jcgonzalez/cmdargs", 0x7fffffffdfff "this is an argument", 0x7fffffffe012 "these", 0x7fffffffe017 "are", 0x7fffffffe01b "four",
0x7fffffffe020 "more"}
(gdb) p argv[1]
$6 = 0x7fffffffdfff "this is an argument"
(gdb) p argv[2]
$7 = 0x7fffffffe012 "these"
The output looks as if you don't have enough debuging information. GDB shouldn't print only addresses but line numbers as well.
(gdb) b main
Breakpoint 1 at 0x400543: file test.c, line 3.
(gdb) r test1 test2
Starting program: /home/simon/a.out test1 test2
Breakpoint 1, main (argc=3, argv=0x7fffffffdca8) at test.c:3
3 puts("blabla");
(gdb) print argc
$1 = 3
(gdb) print argv
$2 = (char **) 0x7fffffffdca8
(gdb) print argv[0]
$3 = 0x7fffffffe120 "/home/simon/a.out"
(gdb) print argv[1]
$4 = 0x7fffffffe132 "test1"
(gdb) print argv[2]
$5 = 0x7fffffffe138 "test2"
(gdb)
you should add the -g options to gcc, which tells it to build debug info too..

Resources