How can we access varargs in GDB? [duplicate] - c

I as using the bt command to view the stacktrace. The output is
(gdb) bt
#0 0x001ae4cd in Debugger (message=0x1 "???\a") at /SourceCache/xnu/xnu-1228.7.58/osfmk/i386/AT386/model_dep.c:705
#1 0x3bf97000 in ?? ()
#2 0x0012b0fa in panic (str=0x5ef "") at /SourceCache/xnu/xnu-1228.7.58/osfmk/kern/debug.c:274
#3 0x001a8cd4 in kernel_trap (state=0x51a67c80) at /SourceCache/xnu/xnu-1228.7.58/osfmk/i386/trap.c:680
#4 0x0019ede5 in return_from_trap () at pmap.h:176
#5 0x00132bea in __doprnt (fmt=<value temporarily unavailable, due to optimizations>, argp=0x51a67e6c, putc=0x38ad24 <kvprintf+33>, arg=0x51a67e48, radix=10) at /SourceCache/xnu/xnu-1228.7.58/osfmk/kern/printf.c:439
#6 0x0038ad11 in kvprintf (fmt=0x1 "???\a", func=0x1, arg=0x1, radix=1, ap=0x51a67e84 "\\?\034I\"") at /SourceCache/xnu/xnu-1228.7.58/bsd/kern/subr_prf.c:525
#7 0x491b5dac in com_my_drv_Log (format=0x491cbff8 "%s::%s:%n\n") at Logger.cpp:37
#8 0x491b3d36 in MyDrv::init (this=0x5c1f200, properties=0x58a8040) at MyDrv.cpp:34
#9 0x00412887 in IOService::probeCandidates (this=0x599a980, matches=0x58ade80) at /SourceCache/xnu/xnu-1228.7.58/iokit/Kernel/IOService.cpp:2512
#10 0x004124ab in IOService::doServiceMatch (this=0x534180, options=8) at /SourceCache/xnu/xnu-1228.7.58/iokit/Kernel/IOService.cpp:2921
#11 0x00411127 in _IOConfigThread::main (self=0x58c6790) at /SourceCache/xnu/xnu-1228.7.58/iokit/Kernel/IOService.cpp:3125
(gdb)
In frame
#7 0x491b5dac in com_my_drv_Log
how could I view the parameters passed to my com_my_drv_Log with signature
void com_my_drv_Log (const char* format, ...);
/* with the variable argument list */
?

Looks like this is possible to do it for a simple program like this:
#include <stdarg.h>
#include <stdio.h>
void myfunc(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
return;
}
int main(int argc, char *argv[])
{
myfunc("test 1: %s %s\n", "one", "two");
myfunc("test 2: %s %d %c\n", "apple", 222, 'y');
return 0;
}
Here is sample gdb session:
$ gdb testprog
GNU gdb (GDB) 7.1-debian
[snip]
Reading symbols from /home/user/testprog...done.
(gdb) break myfunc
Breakpoint 1 at 0x400552: file testprog.c, line 7.
(gdb) run
Starting program: /home/user/testprog
Breakpoint 1, myfunc (fmt=0x4006f4 "test 1: %s %s\n") at testprog.c:7
7 va_start(args, fmt);
(gdb) # initialize args to hold correct values:
(gdb) step
8 vprintf(fmt, args);
(gdb) # print first argument in "..." list which we know is a char*:
(gdb) p *(char **)(((char *)args[0].reg_save_area)+args[0].gp_offset)
$1 = 0x4006f0 "one"
I have not tested all of this, look this link for full solution. This blog will be useful also.

(gdb) frame 8
will put you in the frame of the caller. Examine the arguments that are being passed.

Related

If I dereference an illegal address in C I get SIGSEGV with valid gdb backtrace. But if I pass it to snprintf backtrace is trashed

In my x86-64 Linux program I deliberately do:
char *ptr = 0x3e8;
int x = *(int *)ptr;
When I run it in gdb the process crashes due to SIGSEGV and prints a valid backtrace. If I do instead:
char s[16];
snprintf(s, 16, "%s\n", ptr);
The process still crashes but the backtrace is trash:
(gdb) bt
#0 0x00007ffff5da15c7 in ?? ()
#1 0x00007ffff5c704d3 in ?? ()
#2 0x0000000000000000 in ?? ()
My example may look contrived but my production code is crashing in snprintf() in exactly the same way. I've compiled with -g -O0.
The process still crashes but the backtrace is trash
When I build this test:
#include <stdio.h>
int main()
{
char *ptr = (char *)0x3e8;
char s[16];
snprintf(s, 16, "%s\n", ptr);
return 0;
}
Using gcc (Debian 9.3.0-3) 9.3.0 and GNU C Library (Debian GLIBC 2.30-4) stable release version 2.30., with libc6-dbg installed, I get:
Program received signal SIGSEGV, Segmentation fault.
__strlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:96
96 ../sysdeps/x86_64/multiarch/strlen-avx2.S: No such file or directory.
(gdb) bt
#0 __strlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:96
#1 0x00007ffff7e48756 in __vfprintf_internal (s=s#entry=0x7fffffffd8b0, format=format#entry=0x555555556004 "%s\n", ap=ap#entry=0x7fffffffda30, mode_flags=mode_flags#entry=0) at vfprintf-internal.c:1688
#2 0x00007ffff7e5a1f6 in __vsnprintf_internal (string=0x7fffffffdb10 "", maxlen=<optimized out>, format=0x555555556004 "%s\n", args=args#entry=0x7fffffffda30, mode_flags=mode_flags#entry=0) at vsnprintf.c:114
#3 0x00007ffff7e335a2 in __GI___snprintf (s=<optimized out>, maxlen=<optimized out>, format=<optimized out>) at snprintf.c:31
#4 0x0000555555555169 in main () at t.c:7
I suspect that you'll get similar result from this test case on a standard x86 Ubuntu 18.04, in which case you are not telling us the whole story, and an MCVE would help a lot to get you the real answer.

confusion with dereferencing argv

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)

Interposing library functions via linker script: other functions cause segfault

I'm currently utilizing the LD_PRELOAD trick and am utilizing a linker version script as detailed in an article on another website. My MCVE code is included below.
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#define BUFFER_SIZE (1024)
int __printf__(const char *fmt, ...)
{
char buf[BUFFER_SIZE] = { 0 };
int ret;
int len;
va_list args;
va_start(args, fmt);
vsnprintf(buf, BUFFER_SIZE - 1, fmt, args);
#if 1
//typeof(vsnprintf) *real_func = dlsym(RTLD_NEXT, "vsnprintf");
//(*real_func)(buf, BUFFER_SIZE - 1, fmt, args);
#endif
len = strlen(buf);
ret = write(STDOUT_FILENO, buf, len);
va_end(args);
return ret;
}
asm(".symver __printf__, __printf_chk#GLIBC_2.3.4");
If I modify my custom printf function to simply write a static string, no problems. However, I want to modify the data being sent to the console via printf (add a prefix, suffix, and set certain character to UPPERCASE, etc). It seems that whenever I attempt to use any other printf-family functions to generate a copy of the user-provided string, I get a segfault, as shown below.
Program received signal SIGSEGV, Segmentation fault.
strchrnul () at ../sysdeps/x86_64/strchr.S:32
32 ../sysdeps/x86_64/strchr.S: No such file or directory.
(gdb) bt
#0 strchrnul () at ../sysdeps/x86_64/strchr.S:32
#1 0x00007ffff78591c8 in __find_specmb (format=0x1 <error: Cannot access memory at address 0x1>) at printf-parse.h:108
#2 _IO_vfprintf_internal (s=s#entry=0x7fffffffc380, format=format#entry=0x1 <error: Cannot access memory at address 0x1>, ap=ap#entry=0x7fffffffc4f8) at vfprintf.c:1312
#3 0x00007ffff7882989 in _IO_vsnprintf (string=0x7fffffffc510 "", maxlen=<optimized out>, format=0x1 <error: Cannot access memory at address 0x1>, args=0x7fffffffc4f8)
at vsnprintf.c:114
#4 0x00007ffff7bd58a1 in __printf__ (fmt=0x1 <error: Cannot access memory at address 0x1>) at libfakeprintf.c:19
#5 0x00000000004004aa in printf (__fmt=0x400644 "%s received %d args\n") at /usr/include/x86_64-linux-gnu/bits/stdio2.h:104
#6 main (argc=<optimized out>, argv=<optimized out>) at print_args.c:5
(gdb) quit
What is causing this crash?
Thank you.
You have overridden the glibc internal function __printf_chk , however this function does not have a prototype that matches printf. It's prototype is:
int __printf_chk(int flag, const char * format, ...);
So make sure your own __printf__ function has that prototype too.
There's a brief description of __printf_chk here

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