gdb showing different address than in code
Solution 1
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
Solution 2
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.
Kingamere
Updated on June 05, 2022Comments
-
Kingamere almost 2 years
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: 0xbffff320Then open in debugger like this:
gdb ./a.out
then enterb main
thenrun
thenp &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 */
-
Kingamere over 8 yearsThanks, I'll look at this now.
-
Kingamere over 8 yearsSo you are saying gdb displays a different environment, and the values displayed by GDB is much more accurate and complete than if I just did printf through the code?
-
ouah over 8 yearsYou can try by yourself with your program. Run your program (without
gdb
) see the address. Thenexport BLA=
with a long string and run your program again (still withoutgdb
) you'll see the address is now different. -
Kingamere over 8 yearsYes I did: "b main" and then "run", and then immediately did "p &buffer"
-
hdl over 8 years@ouah but how could they be different when program is run in a single instance of gdb?
-
hdl over 8 yearsIt doesn't mean anything to me. I don't have to export some environment variable to see addresses change run after run! They already change run after run. What's weird is that it's like doing twice the same printf and getting different results.
-
ouah over 8 yearsIf they change run after run without gdb, why even mentioning gdb? If they change run after run it simply means ASLR is not correctly disabled.
-
ouah over 8 yearsIf you are using
gdb
the status of ASLR can be different, you can disable it in gdb withset disable-randomization off
. -
Kingamere over 8 years@ouah, the addresses aren't changing run after run per se. The two addresses are different (one printed through gdb and the other through printf), and are consistent every run.
-
Kingamere over 8 yearsThe address printed through gdb is the same every run, and the address printed through printf is the same every run. However, the two addresses are different from each other.
-
hdl over 8 yearsThanks, but I still cannot reproduce @Ikshvaku 's results with ASLR disabled in gdb. It does not make sense to me that a
printf
and aprint
in gdb would return two different values. -
ouah over 8 years@Ikshvaku in that case my answer answers your question.
-
Kingamere over 8 yearsLike I said, it has nothing to do with ASLR (it is already disabled in my case), because the addresses aren't changing from RUN TO RUN, they are consistent from run to run, but different from each other.
-
ouah over 8 years@hdl if the var env values are different it totally makes sense, you too try my test with setting a long env var as explained above.
-
Kingamere over 8 years@ouah, probably so. It may just be how the environment is set up. Can you elaborate on this a bit?
-
Kingamere over 8 years@ouah, I know the addresses are different by just running them. I'm not sure what you mean
-
hdl over 8 years@ouah can you explain how to reproduce inside gdb? I think the answer is way simpler than that.
-
ouah over 8 yearsI'm sorry it is the answer to the question and I cannot do more if it is not understood after many comments.
-
hdl over 8 years@Ikshvaku then did you execute the
printf
instruction withnext
? (see updated answer) -
Kingamere over 8 yearsYes I did that. Also my professor just responded and said that GDB adds some stuff to the bottom of the stack to help it debug properly. But that still doesn't explain why you don't see different addresses.
-
Kingamere over 8 yearsActually it could just be that my version of GDB is a lot older (6.8). What is your GDB version?
-
hdl over 8 yearsmine is 7.7.1, maybe a bug report was filed about it, and it has been fixed since then. Even though it's pretty strange, considering the overall quality of gdb...
-
hdl over 8 years@Ikshvaku Can you reproduce not using a buffer but, say, just a
char
? -
Kingamere over 8 yearsThe addresses are still different this time. I was actually able to solve my buffer overflow problem despite this disparity in addresses. It is very minor and won't affect the attack much. I believe, as my professor said, it's just GDB that is giving this behavior. Therefore, I'll mark the question as answered.
-
hdl over 8 yearsCould you please share some reference(s)? How did you find out? :)
-
Kingamere over 8 yearsMy only reference is my professor telling me that gdb adds some instructions to the bottom of the stack so it can debug properly. My point is that in the context of performing a buffer overflow attack, this address disparity shouldn't affect the attack too much, and you can still manage to do it.
-
Kingamere over 8 yearsAhh I see, thanks. This was bugging me for a while. What are the environment variables, lines and columns?
-
Mark Plotnick over 8 yearsYeah, the
readline
package that gdb uses sets them. They're the dimensions of your terminal window. I haven't looked into why it does that. It probably uses the values internally so it can properly display a command line that's so long that it takes more than one physical line of the terminal. -
Kingamere over 8 yearsGood to know. Thanks again