如果我运行一个程序,就像
#include <stdio.h>
int main(int argc, char *argv[], char *env[]) {
printf("My references are at %p, %p, %p\n", &argc, &argv, &env);
}
我们可以看到这些区域实际上在堆栈中。
但还有什么?如果我们对 Linux 3.5.3 中的所有值进行循环(例如,直到段错误),我们可以看到一些奇怪的数字,以及由一堆零分隔的两个区域,也许是为了防止覆盖环境变量偶然。
无论如何,在第一个区域中必须有很多数字,例如每个函数调用的所有帧。
我们如何区分每一帧的结尾、参数在哪里、金丝雀(如果编译器添加了金丝雀)、返回地址、CPU 状态等?
如果不了解叠加层,您只能看到位或数字。虽然某些区域受机器具体情况的影响,但大量细节是相当标准的。
如果您没有超出嵌套例程太远,您可能正在查看调用堆栈 http://en.wikipedia.org/wiki/Call_stack记忆的一部分。对于一些通常被认为“不安全”的 C,您可以编写一些有趣的函数,通过上面的几次“调用”来访问函数变量,即使这些变量没有像源代码中编写的那样“传递”给函数。
调用堆栈是一个很好的起点,因为第三方库必须可以由尚未编写的程序调用。因此,它是相当标准化的。
超出进程内存边界会给您带来可怕的分段违规,因为内存防护将检测到进程访问未经授权的内存的尝试。 Malloc 的作用不仅仅是“仅仅”返回一个指针,在具有内存分段功能的系统上,它还“标记”该进程可访问的内存,并检查所有内存访问是否违反了进程分配。
如果您继续遵循这条道路,迟早您会对内核或对象格式产生兴趣。如果有源代码,那么研究使用 Linux 完成任务的一种方法要容易得多。有了源代码,您就不必通过查看二进制文件来对数据结构进行逆向工程。开始时,最困难的部分是学习如何找到正确的标题。稍后它将学习如何探索并可能改变在非修补条件下你可能不应该改变的东西。
附言。您可能会将此内存视为“堆栈”,但过了一会儿,您会发现它实际上只是一大块可访问内存,其中一部分被视为堆栈......
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)