I am trying to implement a buffer overflow attack and I need to know the address of my buffer that I am trying to overflow.
The address that is displayed using GDB is different than if I just did this in the code:
Exact code:
#include<stdio.h>
int main() {
char buffer[20];
printf("%p\n", buffer); // 0xbffff320
return 0;
}
However, in gdb if I do:
p &buffer
I get: 0xbffff330
Why is there a difference and will it mess up my buffer overflow attack?
I have ALSR and stack guard disabled.
Thanks.
EDIT 1: Even when I step through gdb and it encounters the print line, I get 0xbffff320 as the address
EDIT 2:
Environment: Ubuntu Linux 9 image running in virtual box on windows 7.
The gdb version: 6.8-debian
Compiled using GCC such as: gcc -g -fno-stack-protector filename.c
execute immediately: ./a.out
address printed: 0xbffff320
Then open in debugger like this: gdb ./a.out
then enter b main
then run
then p &buffer
Then address is 0xbffff330
Edit 3:
This is the gdb log to reproduce behavior:
$ gdb ./a.out
b main
run
p &buffer /* address here is different than what is shown if I run executable */
step through program to printf statement /* address here is same as p &buffer but different than what is printed when program is ran */
The question, as I understand it, is why the address of a local variable in main
is different when the program is started from the shell versus when it is started from gdb.
Here's a sample program to show the difference:
mp@ubuntu:~$ cat s.c
#include<stdio.h>
int main(int argc, char **argv) {
char buffer[20];
system("env");
printf("%s %p\n", argv[0], buffer);
return 0;
}
We'll run it in a clean environment. (I also disabled ASLR).
mp@ubuntu:~$ env -i sh
$ ./s
PWD=/home/mp
./s 0xbffffe48
$ gdb ./s
(gdb) run
Starting program: /home/mp/s
COLUMNS=80
PWD=/home/mp
LINES=42
/home/mp/s 0xbffffe08
The output from gdb's print &buffer
command is the same as the program's idea of the address, but they're both different from when the program was run in the shell.
(gdb) b 6
Breakpoint 1 at 0x804849c: file s.c, line 6.
(gdb) run
Starting program: /home/mp/s
COLUMNS=80
PWD=/home/mp
LINES=42
Breakpoint 1, main (argc=1, argv=0xbffffed4) at s.c:6
6 printf("%s %p\n", argv[0], buffer);
(gdb) p &buffer
$1 = (char (*)[20]) 0xbffffe08
(gdb) n
/home/mp/s 0xbffffe08
8 return 0;
There are a couple of things contributing to the difference:
- gdb is invoking the program with an absolute pathname, so the argv array is bigger.
- gdb sets (or in this case, adds) two environment variables. This is done in
readline/shell.c:sh_set_lines_and_columns()
. So the environ array is bigger.
To remove those two variables from the environment, you can use unset environment, or set exec-wrapper to run env -u ...
. That way, the program's addresses under gdb are the same as when it's run in the shell (if we use an absolute pathname).
$ `pwd`/s
PWD=/home/mp
/home/mp/s 0xbffffe28
$ gdb `pwd`/s
(gdb) set exec-wrapper env -u LINES -u COLUMNS
(gdb) run
Starting program: /home/mp/s
PWD=/home/mp
/home/mp/s 0xbffffe28
Your array object in your system is stored in the stack. At the top of your stack there is, among other, the environment. When you run your program with gdb
, gdb
will provide a different environment (the env var and their value) which explains the addresses difference.
You can check the difference by running show environment
in gdb
and by comparing the output with set
command in your shell.
Found out that this is expected behavior in old versions of GDB (mine is 6.8-debian), and if you construct your buffer overflow attack properly you can work around this behavior and it won't be a problem.
For the moment, the only reasons I can imagine are :
- you tried to
print &buffer
after your program terminated. Solution: try setting a breakpoint on main
, run
, next
to execute printf
, and print &buffer
.
- you first ran your program outside gdb, then ran it inside gdb but forgot to execute the
printf
line with next
.
- a bug in your version of gdb
- a bug in your version of gcc (gcc might produce incorrect debug info: see 1 and 2)