如何从注入进程的内存空间重建数据结构?

时间:2009-09-09 08:21:49

标签: c++ memory code-injection

我已经制作了这个DLL。它被注入另一个进程。在其他过程中, 我使用以下函数从它的内存空间进行搜索:


void MyDump(const void *m, unsigned int n)
{
        const char *p = reinterpret_cast(m);

        for (unsigned int i = 0; i < n; ++i) {
                // Do something with p[i]...
        }
}

现在我的问题。如果目标进程使用数据结构,那么就说

struct S
{
        unsigned char a;
        unsigned char b;
        unsigned char c;
};

在进程的记忆中它总是以相同的方式呈现吗?我的意思是,如果S.a = 2(总是跟随b = 3,c = 4),那么结构呈现在进程'内存空间的连续行中,如

Offset
---------------------
0x0000 | 0x02 0x03 0x04

或者那些变量可以在那里的不同位置,例如

Offset
---------------------
0x0000 | 0x00 0x02 0x00
0x03fc | 0x00 0x03 0x04

如果是后者,如何从内存中的各个点重建数据结构?

非常感谢提前,
nhaa123

4 个答案:

答案 0 :(得分:1)

如果您的受害者是用C或C ++编写的,并且所使用的数据类型真的很简单,那么您将始终将它们视为内存中的单个字节块。

但是只要你拥有像std::string这样的C ++类型,观察就不再适用了。对于初学者来说,C ++编译器之间的确切布局会有所不同,甚至是同一编译器的不同版本。 std :: string的字节可能不在连续的数组中,但有时它们是。如果他们被分成两半,找到下半场可能无法帮助你找到上半场。

不要像JIT运行Java应用程序的JVM那样投入更复杂的环境。你在记忆中遇到的类型非常复杂;人们可以写一本关于解码它们的书。

答案 1 :(得分:0)

成员的顺序将始终相同,结构将占用连续的内存块。

根据编译器的填充,可能会在成员之间添加,但如果使用相同的编译器和相同的设置重新编译程序,它仍然是相同的。如果添加了填充并且您不知道它,则无法在运行时可靠地检测到它 - 编译器所具有的所有信息都会丢失到那一刻,您只需分析模式并进行猜测。

答案 2 :(得分:0)

这取决于结构的对齐方式。

如果你有这样的事情:

struct A
{
  int16_t a;
  char    b;
  int32_t c;
  char    d;
}

然后默认在32位平台上(我不知道64位是否为真),c的偏移量为4,因为在b之后填充了一个字节,在d之后还有3个bytess填充在末尾(如果我记得没错。

如果结构具有指定的对齐方式,则会有所不同。

答案 3 :(得分:0)

  

现在我的问题。如果目标进程使用数据结构,那么它在进程内存中总是以相同的方式呈现吗?我的意思是,如果S.a = 2(总是跟随b = 3,c = 4),那么结构是否在过程'存储空间中的连续行中呈现?

是的,但是它通常会被填充以便以您可能不期望的方式对齐成员。因此,只需重新创建数据结构,以便通过代码注入与它进行交互。

我强烈建议使用ReClassExReClass.NET两个专门用于从内存重建数据结构并生成可用C ++代码的开源程序!看一下截图:

Screenshot of ReClass.NET