gdb showing different address than in code

10,080

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.

Share:
10,080
Kingamere
Author by

Kingamere

Updated on June 05, 2022

Comments

  • Kingamere
    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: 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 */

  • Kingamere
    Kingamere over 8 years
    Thanks, I'll look at this now.
  • Kingamere
    Kingamere over 8 years
    So 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
    ouah over 8 years
    You can try by yourself with your program. Run your program (without gdb) see the address. Then export BLA= with a long string and run your program again (still without gdb) you'll see the address is now different.
  • Kingamere
    Kingamere over 8 years
    Yes I did: "b main" and then "run", and then immediately did "p &buffer"
  • hdl
    hdl over 8 years
    @ouah but how could they be different when program is run in a single instance of gdb?
  • hdl
    hdl over 8 years
    It 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
    ouah over 8 years
    If 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
    ouah over 8 years
    If you are using gdb the status of ASLR can be different, you can disable it in gdb with set disable-randomization off.
  • Kingamere
    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
    Kingamere over 8 years
    The 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
    hdl over 8 years
    Thanks, but I still cannot reproduce @Ikshvaku 's results with ASLR disabled in gdb. It does not make sense to me that a printf and a print in gdb would return two different values.
  • ouah
    ouah over 8 years
    @Ikshvaku in that case my answer answers your question.
  • Kingamere
    Kingamere over 8 years
    Like 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
    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
    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
    Kingamere over 8 years
    @ouah, I know the addresses are different by just running them. I'm not sure what you mean
  • hdl
    hdl over 8 years
    @ouah can you explain how to reproduce inside gdb? I think the answer is way simpler than that.
  • ouah
    ouah over 8 years
    I'm sorry it is the answer to the question and I cannot do more if it is not understood after many comments.
  • hdl
    hdl over 8 years
    @Ikshvaku then did you execute the printfinstruction with next? (see updated answer)
  • Kingamere
    Kingamere over 8 years
    Yes 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
    Kingamere over 8 years
    Actually it could just be that my version of GDB is a lot older (6.8). What is your GDB version?
  • hdl
    hdl over 8 years
    mine 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
    hdl over 8 years
    @Ikshvaku Can you reproduce not using a buffer but, say, just a char?
  • Kingamere
    Kingamere over 8 years
    The 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
    hdl over 8 years
    Could you please share some reference(s)? How did you find out? :)
  • Kingamere
    Kingamere over 8 years
    My 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
    Kingamere over 8 years
    Ahh I see, thanks. This was bugging me for a while. What are the environment variables, lines and columns?
  • Mark Plotnick
    Mark Plotnick over 8 years
    Yeah, 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
    Kingamere over 8 years
    Good to know. Thanks again