检查堆栈上的环境变量

发布于 2025-01-23 20:51:56 字数 346 浏览 0 评论 0原文

我知道环境变量在内存中的堆栈上方,我想列出它们,或者至少能够使用gdb来检查它们。首先,我将堆栈指针的地址放置,但是由于变量放置在堆栈上方,我该如何知道我应该增加地址的数量?

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

我浏览网络时看到的一个例子是

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

我认为我误解了SMTH。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小瓶盖 2025-01-30 20:51:56

我知道环境变量在内存中的堆栈上方,

是Linux实现细节,envp vector(以及argv),其元素存储在堆栈内存中 main 线程(仅)。 nofollow noreferrer“> system v Application v Application v Application二进制二进制界面AMD64 amd64 at lp64 and ILP322222222222222222222222222222222222222222。编程模型(请参见图3.9:初始过程堆栈)要求可执行的输入点_start get %rsp 指向argc,然后是argv向量,然后是envp向量,都在 main thread堆栈中。 _start(通常由您的语言/编译器运行时实现)消耗多少堆栈时运行时间的供应商,ABI仅与入口点有关_start

高级后卫可以从主线程启动其他线程,然后终止主线程而无需终止过程。这样,没有线程堆栈包含环境。它还可以擦除其argvenvp和/或向量指向的元素,以使它们在过程地址空间中变得无法使用。但是,后者不会影响/proc/proc/self/code>或/proc/proc/proc/self/cmdline由内核维护。

确切的位置在envp参数为main中。 C标准不需要任何东西,例如,线程堆栈是实现细节。

我怎么知道我应该增加地址?

这可能取决于选项,并与当前的堆栈一起编译了代码。

询问x显示一个较大的数组以查看环境变量:

x/2048s $rsp

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

It is Linux implementation detail that envp vector (along with argv) and its elements are stored in the stack memory of the main thread (only). System V Application Binary Interface AMD64 with LP64 and ILP32 Programming Models (see Figure 3.9: Initial Process Stack) requires that executable entry point _start gets %rsp which points to argc, followed by argv vector, followed by envp vector, all in the main thread stack. How much of the stack is consumed by _start (normally implemented by your language/compiler run-time) when it invokes main is an implementation detail which depends on the version and the vendor of the run-time, the ABI is only concerned with entry point _start.

An advanced defender can start other threads from the main thread and then terminate the main thread without terminating the process. This way, no thread stack contains the environment. It can also wipe its argv and envp and/or the elements the vectors point to, so that they become unavailable in the process address space. The latter, however, doesn't affect /proc/self/environ or /proc/self/cmdline maintained by the kernel.

The exact location is in envp argument to main. The C standard doesn't require anything beyond that, e.g. the thread stack is an implementation detail.

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
一百个冬季 2025-01-30 20:51:56

更新:

我想用GDB在运行时获得这些变量的地址。

那是微不足道的:到GDB中的main级别的步骤,打印rbp注册的值,然后使用您对堆栈布局的理解(请参见下文)。

示例:

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

上面,您可以将& argv [0] == 0x00007fffffffedb8作为堆栈上的第三个字(其他两个是rbp和返回地址)。使用下面的第一个示例代码恢复完整的argv []envp []


我怎么知道我应该增加地址?

如果您在main()中,在Linux上,您可以知道 Exact 堆栈的布局,并且可以检查argcargv []envp []使用例如,此代码:

#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("%2d: %p %s\n", j, argv[j], argv[j]);
  }
  printf("Environment vector:\n");
  for (j++; ; j++) {
    if (argv[j] == NULL) break;
    printf("%2d: %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

您还可以利用GLIBC实际将envp []转换为main()作为第三参数的事实:

#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("%2d: %p %s\n", j, envp[j], envp[j]);
  }
  return 0;
}
Environment vector:
 0: 0x7ffdef096fd6 FOO=ABC
 1: 0x7ffdef096fde BAR=DEF
 2: 0x7ffdef096fe6 HOME=/tmp

如果您是而不是main(Main()中,并且不能具有main()保存&amp; argv [0]在全局中,那么事情变得更棘手。

您可以分析/proc/proc/self/maps以找出堆栈边界,并以这种方式检查堆栈(请参阅“ kernel设置的堆栈” e节在这里)。

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("%2d: %p %s\n", j, argv[j], argv[j]);
  }
  printf("Environment vector:\n");
  for (j++; ; j++) {
    if (argv[j] == NULL) break;
    printf("%2d: %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("%2d: %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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文