Home > OS >  Examine environment variables on the stack
Examine environment variables on the stack

Time:04-24

I know that environment variables are above the stack in memory, and I want to list them or at least be able to see them through examining the stack using gdb. First I take the address of the stack pointer but since the variables are placed above the stack, how do I know by how much I should increment the address?

(gdb) info register rsp
rsp            0x7fffffffdf48      0x7fffffffdf48
(gdb) x/32s $rsp   0x(mmm..)

An example I saw while browsing the web was

x/32s $rsp   0x240 // Why 0x240, exactly?

I think I misunderstood smth.

CodePudding user response:

I know that environment variables are above the stack in memory,

In the stack memory of the main thread only.

how do I know by how much I should increment the address?

That may depend on options the code was compiled with and the current stacktrace.

Ask x to display a larger array to see the environment variables:

x/2048s $rsp

CodePudding user response:

Update:

I want to get the addresses of these variables in run-time with gdb.

That's trivial: step to the main level in GDB, print the value of the RBP register, and then use your understanding of stack layout (see below).

Example:

env -i FOO=ABC BAR=DEF HOME=/tmp gdb -q --args ./a.out foo bar baz
Reading symbols from ./a.out...
(gdb) start
Temporary breakpoint 1 at 0x11b8: file t.c, line 6.
Starting program: /tmp/a.out foo bar baz

Temporary breakpoint 1, main (argc=4, argv=0x7fffffffedb8) at t.c:6
6         printf("Argument vector:\n");

(gdb) p/x $rbp
$1 = 0x7fffffffecc0
(gdb) x/8gx $rbp
0x7fffffffecc0: 0x0000000000000000      0x00007ffff7df17fd
0x7fffffffecd0: 0x00007fffffffedb8      0x00000004f7fca000
0x7fffffffece0: 0x00005555555551a9      0x00007fffffffef79
0x7fffffffecf0: 0x00005555555552c0      0x9a3bd5580a4c103c

Above, you can see the &argv[0] == 0x00007fffffffedb8 as the 3rd word on the stack (the other two are the previous value of RBP and the return address). Use the first example code below to recover complete argv[] and envp[].


how do I know by how much I should increment the address?

If you are in main(), on Linux, you can know the exact layout of stack, and can examine argc, argv[] and envp[] using e.g. this code:

#include <stdio.h>

int main(int argc, char *argv[])
{
  int j;
  printf("Argument vector:\n");
  for (j = 0; ; j  ) {
    if (argv[j] == NULL) break;
    printf("-: %p %s\n", j, argv[j], argv[j]);
  }
  printf("Environment vector:\n");
  for (j  ; ; j  ) {
    if (argv[j] == NULL) break;
    printf("-: %p %s\n", j, argv[j], argv[j]);
  }
  return 0;
}
$ gcc -g t.c && env -i FOO=ABC BAR=DEF HOME=/tmp ./a.out foo bar baz
Argument vector:
 0: 0x7ffd39e05fc2 ./a.out
 1: 0x7ffd39e05fca foo
 2: 0x7ffd39e05fce bar
 3: 0x7ffd39e05fd2 baz
Environment vector:
 5: 0x7ffd39e05fd6 FOO=ABC
 6: 0x7ffd39e05fde BAR=DEF
 7: 0x7ffd39e05fe6 HOME=/tmp

You could also leverage the fact that GLIBC actually passes envp[] to main() as the 3rd argument:

#include <stdio.h>

int main(int argc, char *argv[], char *envp[])
{
  printf("Environment vector:\n");
  for (int j= 0; ; j  ) {
    if (envp[j] == NULL) break;
    printf("-: %p %s\n", j, envp[j], envp[j]);
  }
  return 0;
}
Environment vector:
 0: 0x7ffdef096fd6 FOO=ABC
 1: 0x7ffdef096fde BAR=DEF
 2: 0x7ffdef096fe6 HOME=/tmp

If you are not in main(), and can't have main() save &argv[0] in a global, then things get trickier.

You can parse /proc/self/maps to figure out stack boundaries, and examine the stack that way (see "stack set by kernel" section here).

  • Related