内存黑客/内存分配:为什么这样做以及如何工作?
Memory hacking / memory allocation : why does this work and how?
我所知道的是,您在试图操纵的软件中寻找某些变量的地址。一旦你找到它,你就会尝试为它找到 "base pointer" 所以无论进程在哪里,你仍然可以访问那些 variables.I 意味着当进程重新启动时变量会有不同的地址,但是你仍然知道他们在哪里。
现在我不明白为什么这可能?
假设我在 C++ 中这样做:
int *x = (int*)malloc(sizeOf(int));
这不是动态的吗?难道 x 不应该放在当时空闲的 "random" 地址中吗?
基本上我要问的是执行该代码时 x 到底在哪里?
编辑:我的意思是像健康这样的变量通常存储在像 game.exe + 0000caff 这样的地址中,然后你总能在那里找到它们。
"and shouldn't x be placed in a "random" address that was free at the time ?"
如果您 运行 操作系统中的一个进程,实际使用的指针值可能会寻址特定 storage duration categories 可用的虚拟地址空间类型,这些空间与您的进程相关联RAM 和 ROM 地址的具体区域,它们由操作系统管理。
因此,如果您在序列中具有相同的动态存储持续时间 de-/allocations,则这些程序的每个 运行 可能会收到相同的(虚拟)地址。这个级别没有什么随机。
x
是一个保存整数地址的变量。
malloc
在堆上分配内存,但 x
仍然位于堆栈上(如果您在函数中声明它)。
然而,您的程序有不同的内存部分,一个用于全局变量和常量,一个用于源代码,一些用于资源,一个用于动态内容(堆)和其他一些。
假设您的 x
位于全局变量部分并指向堆。那么x
就有了一个静态地址。
这个地址可以通过mov eax , [0x123]
这样的汇编指令在源代码部分找到。
该汇编程序指令还有一个地址,该地址与指令所在的模块相关。这些模块可以动态加载(例如通过 LoadLibrary),但是从模块基地址到指令的偏移量是固定的。
获取 x
指向的数据:
base = getModuleBaseAddress("modulename")
addressOfX = base + offset
valueOfX = *addressOfX
大多数对象不在堆栈上,可以通过模块地址、固定偏移量以跳转到使用对象指针的指令以及一些偏移量以获取对象变量来引用。
要查找内存中的对象,您还可以使用模式扫描来扫描内存。
以下是从32位x86架构来看的,其他架构可能做的不一样。另外,我假设单行代码在一个函数中。
首先记住声明int* x
的意思,大体上可以读作"the variable x will contain the address of an integer"
变量x
是一个局部变量(或自动变量),这意味着它的位置是在编译时确定的,它的存储space是在函数被激活时分配的(很可能是在堆栈)。
x
中包含的值是一个动态地址(可能位于堆上)。
因此,您拥有的是变量 x
与函数激活帧中某个位置之间的绑定。请原谅糟糕的 ASCII 艺术,比如
这个(地址是概念性的,还要记住堆栈向下增长):
~ ~
| |
+------------+
0x04000 | |<---- ebp
+------------+
| |
+------------+
0x03ff8 | x |
+------------+
| |
+------------+
0x03ff0 | |<---- esp
+------------+
现在我们必须注册定义底部的值ebp(扩展基指针)和esp(扩展堆栈指针)和堆栈上激活帧的顶部。所以在汇编中,如果你想定位 x
的存储位置是基于基指针的偏移量。
另一种思考方式,即变量名 x
是内存位置 epb-8
的别名。因为,这就是编译器布局内存的方式 x
的存储位置将始终位于距基指针相同的偏移量处。
现在,在多次运行中基指针的值可能会改变,只要我能找到激活帧的基指针,我就能找到x
和[=41=的存储位置]用它。
我所知道的是,您在试图操纵的软件中寻找某些变量的地址。一旦你找到它,你就会尝试为它找到 "base pointer" 所以无论进程在哪里,你仍然可以访问那些 variables.I 意味着当进程重新启动时变量会有不同的地址,但是你仍然知道他们在哪里。
现在我不明白为什么这可能?
假设我在 C++ 中这样做:
int *x = (int*)malloc(sizeOf(int));
这不是动态的吗?难道 x 不应该放在当时空闲的 "random" 地址中吗? 基本上我要问的是执行该代码时 x 到底在哪里?
编辑:我的意思是像健康这样的变量通常存储在像 game.exe + 0000caff 这样的地址中,然后你总能在那里找到它们。
"and shouldn't x be placed in a "random" address that was free at the time ?"
如果您 运行 操作系统中的一个进程,实际使用的指针值可能会寻址特定 storage duration categories 可用的虚拟地址空间类型,这些空间与您的进程相关联RAM 和 ROM 地址的具体区域,它们由操作系统管理。
因此,如果您在序列中具有相同的动态存储持续时间 de-/allocations,则这些程序的每个 运行 可能会收到相同的(虚拟)地址。这个级别没有什么随机。
x
是一个保存整数地址的变量。
malloc
在堆上分配内存,但 x
仍然位于堆栈上(如果您在函数中声明它)。
然而,您的程序有不同的内存部分,一个用于全局变量和常量,一个用于源代码,一些用于资源,一个用于动态内容(堆)和其他一些。
假设您的 x
位于全局变量部分并指向堆。那么x
就有了一个静态地址。
这个地址可以通过mov eax , [0x123]
这样的汇编指令在源代码部分找到。
该汇编程序指令还有一个地址,该地址与指令所在的模块相关。这些模块可以动态加载(例如通过 LoadLibrary),但是从模块基地址到指令的偏移量是固定的。
获取 x
指向的数据:
base = getModuleBaseAddress("modulename")
addressOfX = base + offset
valueOfX = *addressOfX
大多数对象不在堆栈上,可以通过模块地址、固定偏移量以跳转到使用对象指针的指令以及一些偏移量以获取对象变量来引用。
要查找内存中的对象,您还可以使用模式扫描来扫描内存。
以下是从32位x86架构来看的,其他架构可能做的不一样。另外,我假设单行代码在一个函数中。
首先记住声明int* x
的意思,大体上可以读作"the variable x will contain the address of an integer"
变量x
是一个局部变量(或自动变量),这意味着它的位置是在编译时确定的,它的存储space是在函数被激活时分配的(很可能是在堆栈)。
x
中包含的值是一个动态地址(可能位于堆上)。
因此,您拥有的是变量 x
与函数激活帧中某个位置之间的绑定。请原谅糟糕的 ASCII 艺术,比如
这个(地址是概念性的,还要记住堆栈向下增长):
~ ~
| |
+------------+
0x04000 | |<---- ebp
+------------+
| |
+------------+
0x03ff8 | x |
+------------+
| |
+------------+
0x03ff0 | |<---- esp
+------------+
现在我们必须注册定义底部的值ebp(扩展基指针)和esp(扩展堆栈指针)和堆栈上激活帧的顶部。所以在汇编中,如果你想定位 x
的存储位置是基于基指针的偏移量。
另一种思考方式,即变量名 x
是内存位置 epb-8
的别名。因为,这就是编译器布局内存的方式 x
的存储位置将始终位于距基指针相同的偏移量处。
现在,在多次运行中基指针的值可能会改变,只要我能找到激活帧的基指针,我就能找到x
和[=41=的存储位置]用它。