代码之家  ›  专栏  ›  技术社区  ›  Mask

为什么每次都从相同的内存地址执行一个函数?

  •  10
  • Mask  · 技术社区  · 16 年前

    我正在分解一个可执行文件:

    (gdb) disas main
    Dump of assembler code for function main:
    0x004012d0 <main+0>:    push   %ebp
    0x004012d1 <main+1>:    mov    %esp,%ebp
    ...
    

    每次内存地址相同时: 0x004012d0 .

    内存地址不是由操作系统动态分配的吗?

    使现代化

    现在我看到的是虚拟空间,它可以在一些平台上随机化。

    有人能发布一个gdb转储文件来改变吗?

    8 回复  |  直到 16 年前
        1
  •  3
  •   rook    16 年前

    这取决于操作系统。大多数情况下,二进制文件的地址保持不变。这对于利用内存操作错误非常重要,例如 缓冲区溢出 .由于ASLR,Linux下链接库的地址将始终不同。在Windows Vista和Windows 7下,二进制文件的虚拟内存空间也会在每次执行时随机化,因此每次运行的函数地址都会不同。

        2
  •  3
  •   Community Mohan Dere    6 年前

    我认为这里的问题(至少在Linux上)可能是gdb试图从文档中提供帮助:

    设置禁用随机化

    将禁用随机化设置为on

    此选项(在gdb中默认启用)将关闭 已启动程序的虚拟地址空间。此选项对于多次调试非常有用 会话,以使执行更具可重复性,并使内存地址可在多个应用程序中重复使用 调试会话。

    此功能仅在gnu/Linux上实现。你可以通过使用

             (gdb) set exec-wrapper setarch `uname -m` -R
    

    http://sourceware.org/gdb/current/onlinedocs/gdb/Starting.html

    更新:我现在已经检查过了,对我来说似乎确实如此(运行Linux 2.6.28)。编译一个简单的Hello World程序,在没有命令行参数的情况下启动gdb(我们不希望在覆盖禁用随机化设置之前加载该程序),然后输入:

    (gdb) set disable-randomization off
    (gdb) file ./a.out
    (gdb) break main
    (gdb) run
    (gdb) disas printf
    

    每次运行程序时,printf的地址都不同。

        3
  •  2
  •   tloach    16 年前

    是和否。物理内存由操作系统分配,只有操作系统知道程序在物理RAM中的位置。您的程序只会看到虚拟地址,如果所有内容都以相同的顺序加载,则虚拟地址将始终相同。

        4
  •  2
  •   Community Mohan Dere    6 年前

    可执行重定位

    一些可执行文件被设置为总是在同一地址加载。有些设置为“可重新定位”。在VisualStudio链接器中控制此操作的选项称为/FIXED。即使是这样的可执行文件,也通常在首选地址加载。较新的操作系统(Win7,Vista)将一些可执行文件的加载地址随机化,以提高安全性(攻击未知地址加载的进程比较困难)——这称为 ASLR 注:即使标记为/FIXED:NO的可执行文件也不适用于ASLR。开发者需要 allow ASLR explicitly 对于可执行文件。

    虚拟地址空间

    注意:了解进程拥有整个地址空间是很重要的。多个进程都有各自的地址空间,因此如果多次启动同一个可执行文件,没有理由每次都不能在同一地址加载。

        5
  •  1
  •   mrjoltcola    16 年前

    这是一个虚拟地址。操作系统知道物理地址,但每个进程都有自己的虚拟地址空间。可重新定位的映像可能每次都会得到相同的映射,尤其是主可执行文件。但这并不能保证。DLL就是一个例子。DLL可能以不同的顺序加载,导致运行之间的虚拟地址不同,因为加载DLL 1时,DLL 2无法加载到该虚拟地址中,必须获得自己的地址。

        6
  •  0
  •   Paul R    16 年前

    这取决于操作系统。在大多数具有虚拟内存的现代操作系统中,不需要重新定位可执行代码,但在较旧的操作系统中,以及在一些专门的操作系统(例如实时嵌入式)中,代码覆盖可以与位置无关的代码和跳转表结合使用。在这种情况下,函数的地址可能会发生变化,例如,如果它的代码段被调出,然后在不同的地址被调回。

        7
  •  0
  •   Peter Teoh    15 年前

    这些是来自计算机安全的术语。在过去,它是固定地址(根据《纽约时报》报道,是1996年) LKML ,但直到最近,Executable才开始被编译为可重新定位的,以便实现 ASLR (但在很久以前,所有库都被编译为可重新定位的,这样库就可以在必要时重新加载到不同的地址——读取) dynamic relocation 但由于加载顺序,这些主系统调用API通常加载到固定地址。)即使在今天,

    做一个gdb/bin/ls,然后按“run”,你会发现默认地址没有改变:

    (gdb)拆开 函数open的汇编程序代码转储: 0xb7f017f0<+0>:cmpl$0x0,%gs:0xc 0xb7f017f8<+8>:jne 0xb7f0181c

    总之,ASLR起源于 PaX -阅读维基,它涵盖了很多关于实现ASLR的需求。

    为什么是ASLR?要防止两种类型的攻击: http://en.wikipedia.org/wiki/Return-to-libc_attack 和 http://en.wikipedia.org/wiki/Return-oriented_programming ,因为如果在内存中修复,这两种攻击都会占用您的代码区域。

        8
  •  -3
  •   Anon    16 年前

    为什么操作系统会选择不同的地址?

    当操作系统执行一个进程时,它会将一个可执行文件加载到虚拟内存空间中。在此过程中,它将解析任何相对和/或符号引用。假设您有相同的可执行文件和相同的共享库,并以与上次相同的方式启动它,那么操作系统决定在 不同的 方法

    推荐文章