【问题标题】:Memory hacking / memory allocation : why does this work and how?内存黑客/内存分配:为什么这样工作以及如何工作?
【发布时间】:2015-04-20 22:56:29
【问题描述】:

我所知道的是你在你试图操纵的软件中寻找一些变量的地址。一旦你找到它,你就会尝试为它找到“基指针”,所以无论进程在哪里,你仍然可以访问这些变量。我的意思是当进程重新启动时,变量会有不同的地址,但你仍然知道他们在哪里 。

现在我不明白为什么会这样?

假设我在 C++ 中这样做:

int *x = (int*)malloc(sizeOf(int));

这不是动态的吗?并且不应该将 x 放置在当时免费的“随机”地址中吗? 基本上我要问的是执行该代码时 x 到底在哪里?

编辑:我的意思是,像健康这样的变量通常存储在像 game.exe + 0000caff 这样的地址中,然后你总是可以在那里找到它们。

【问题讨论】:

  • 将依赖于操作系统。您没有提供足够的信息让我们告诉您如何“破解”您的目标可执行文件。您可能还需要稍微查看一下汇编程序的输出,以了解事物的存储方式。
  • " 一旦你找到它,你就会尝试找到它的“基指针”,所以无论进程在哪里,你仍然可以访问这些变量。” 可以请提供一个实际示例,x 的值对于重复运行您的过程是如何相同的,请。还要记住,进程的虚拟地址空间之类的概念取决于实际使用的操作系统的策略。
  • 编辑了问题,我的意思是为什么 x 地址与进程的偏移量相同,而它应该是动态的?
  • @vlatkozelka:我认为这里有点混乱。 x 似乎是一个全局指针,全局变量几乎总是每次都处于相同的偏移量。它指向“当时免费的随机地址”。即使x 是函数的局部变量,它们有时也可能每次都以相同的偏移量结束,具体取决于它的编程方式。我所说的一切都有一千个例外,比如Address Space Layout Randomization
  • “这不是动态的吗?不应该将 x 放置在当时空闲的“随机”地址中吗?” 是的,但是程序包含一个指针到它...实际上,*x 位于“随机”地址。不是x

标签: c++ c memory


【解决方案1】:

以下是从 32 位 x86 架构的角度出发,其他架构可能会做不同的事情。另外,我假设单行代码在一个函数中。

首先记住声明int* x的含义,大致可以理解为“变量x将包含一个整数的地址”

变量x 是一个本地(或自动变量),这意味着它的位置是在编译时确定的,它的存储空间是在函数激活时分配的(很可能在堆栈上)。

x 中包含的值是一个动态地址(并且可能位于堆上)。

所以你所拥有的是变量x 和函数激活框架中的某个位置之间的绑定。原谅可怜的 ASCII 艺术,比如 这个(地址是名义上的,还记得堆栈是向下增长的):

             ~            ~
             |            |
             +------------+
    0x04000  |            |<----   ebp
             +------------+
             |            |
             +------------+
    0x03ff8  |     x      | 
             +------------+
             |            |
             +------------+
    0x03ff0  |            |<----  esp
             +------------+

现在我们必须注册值 ebp(扩展基指针)和 esp(扩展堆栈指针),它们定义了激活帧的底部和顶部堆。所以在汇编中,如果你想定位x 的存储位置是基于基指针的偏移量。

另一种思考方式是变量名x 是内存位置epb-8 的别名。因为,这是编译器布局内存的方式,x 的存储位置将始终位于与基指针相同的偏移量处。

现在,在多次运行过程中,基指针的值可能会发生变化,只要我能找到激活帧的基指针,我就能找到x的存储位置并摆弄它。

【讨论】:

    【解决方案2】:

    x 是一个保存整数地址的变量。

    malloc 在堆上分配内存,但x 仍然位于堆栈上(如果您在函数中声明它)。

    但是,您的程序有不同的内存部分,一个用于全局变量和常量,一个用于源代码,一些用于资源,一个用于动态内容(堆)以及其他一些。

    假设您的x 位于全局变量部分并指向堆。那么x就有了一个静态地址。

    这个地址可以通过汇编指令在源代码部分找到,比如mov eax , [0x123]。 该汇编指令还具有相对于指令所在模块的地址。这些模块可以动态加载(例如通过 LoadLibrary),但是从模块基地址到指令的偏移量是固定的。

    获取x指向的数据:

    base = getModuleBaseAddress("modulename")
    addressOfX = base + offset
    valueOfX = *addressOfX
    

    大多数对象不在堆栈上,可以通过模块地址、固定偏移量来跳转到使用对象指针的指令以及一些偏移量来获取对象变量。

    要在内存中查找对象,您还可以使用模式扫描来扫描内存。

    【讨论】:

      【解决方案3】:

      “不应该将 x 放置在当时空闲的“随机”地址中吗?”

      如果您在操作系统中运行进程,则实际使用的指针值可能指向特定storage duration categories 可用的虚拟地址空间类型,这些虚拟地址空间与您的进程相关联,具有具体的 RAM 和 ROM 地址区域,并且由操作系统管理。

      因此,如果您按顺序具有相同的动态存储持续时间取消/分配,则这些可能会在每次运行程序时收到相同的(虚拟)地址。在这个级别上没有任何随机

      【讨论】:

        猜你喜欢
        • 2018-04-10
        • 2021-01-30
        • 1970-01-01
        • 2014-06-08
        • 2020-10-26
        • 1970-01-01
        • 2021-03-21
        • 2013-12-20
        • 2022-01-17
        相关资源
        最近更新 更多