c++ - 指向结构指针数组的指针

标签 c++ pointers assembly reverse-engineering cheat-engine

我什至没有提出问题我认为这是某种确认,我正确理解了这个主题。
我正在做一些逆向工程研究,这就是我所拥有的。 假设我们有结构/类,如下所示:

struct {
   char str[n]
   int x
   float a
}

我们正在查看的进程内存中有这些结构的数组。

所以,我拥有的是指向结构指针数组的指针。
如果我错了,现在请你纠正我。要读取此数组第一个元素的 x 值(实际结构,而不是指针),我必须遵循以下步骤:

  1. 读取指针指向的值(4字节)。
  2. 没有任何偏移量读取先前读取值指向的值,也是 4 个字节(这将引导我到结构开始的地址)
  3. 现在我必须添加等于 n 的偏移量。并从第2步的地址中读取值(step2result+n+1)。

我说的对吗?我会得到第一个结构包含的实际 X 吗?要从第二个中获取 X 值,我只需要在步骤 2 中添加偏移量(+4 字节)?

我认为我这样做是对的,但实际上我无法从指针访问结构。我会说指向数组的指针是 100% 正确的。

感谢阅读,期待答案。如果您需要更多信息,请提出要求。

附注不要为了教育目的而破解任何东西或任何东西

添加:
好的,我试图简化它只会让解释和理解变得更加困难。现在我要尝试修复它。
一种结构描述了游戏中的 NPC 参数。整个结构的大小为 0x1200。前 16 个字节只是 ID 信息,然后在这个信息变成 64 个字节的字符串之后,就是名称。然后是 X/Y/Z 的坐标。这些之后的一切都不重要。
并不难找,下面是截图:
structure /
所以我可以通过在该结构开始的地址上加上或减去 0x1200 来找到其他结构。
我搜索了结构开始的地址并找到了指向它的指针。 然后我扫描了对找到的指针的访问并得到了类似的东西:

mov [eax+edx*4+00320], ecx

然后我搜索了eax的值,找到了指向eax的指针
这就是为什么我认为这是指针数组。
希望我只是更具体地解释了这一点。

最佳答案

你的问题实际上充满了地雷,这将以不幸的方式证明为什么 assembly 的准确性如此重要。

So, what I have is ...

你展示了语法错误的匿名结构,突然间你有了一些指针?它不是那样工作的。您有匿名结构和一些语法错误,仅此而已。

现在我真的觉得可以停止回答了,因为如果没有数据的实际定义,你的问题的其余部分就毫无意义。但是假设您有这样的想法:

struct STRUCT_A {
   char     str[17];
   int      x;
   float    a;
};

STRUCT_A testA[3]{
  {"a1", 1111, 1.111},
  {"a2", 2222, 2.222},
  {"a3", 3333, 3.333}
};

int foo(unsigned index) {
  return testA[index].x;
}

所以,我这里有数组 testA。数组不仅仅是指针,它在编译期间在 C++ 中多了一点点,尽管它在使用时很乐意“退化”成指针,但它并不完全相同。

当我将使用 testA 作为指针时,它不指向任何进一步的指针,它直接指向数据。

因此您在 OP 中没有一层,而是两层额外的间接寻址。要读取第一个元素的 x,您只需执行 mov eax,[testA + 20]。未加载指针(示例来自 x86 32b 目标,在其他目标上 +20 可能不同)。

你会不会:

STRUCT_A* testA_alias = testA;  
   // now this ^^ alias is no more array, it's just pointer
   // (array silently decays into pointer during compilation, when asked to)
STRUCT_A** testA_indirect = &testA_alias;

然后获取第二个元素的x:

mov  eax,[testA_indirect]   ; eax = &testA_alias
mov  eax,[eax]              ; eax = testA (or &testA .. not sure how to write it, "address of data")
mov  eax,[eax + 28*1 + 20]  ; eax = testA[1].x

我设法创建了两个间接级别(实际上我不得不在这部分编辑答案,因为我错误地从 C++ 读取程序集,不完整的 Intel 语法让我感到困惑)。

我仍然不确定您从哪里获得所有这些指示以及为什么?它不是 Java,它是 C++,您只需将数据直接存储在内存中即可。如您所见,我不得不付出相当多的努力来获得两个间接级别。

现在您可能想知道为什么 x 位于 +20 而不是 +17。因为填充,C++ 会根据结构成员的类型对齐结构成员,int 喜欢对齐,所以它就是。

这也应该解释 28,它是该结构的大小。

在你的问题中你还有:

step2result+n+1

+1 从何而来?也许你对此感到困惑:

char str[]{"abc"};              // str[4]

但那是因为 "abc" 就像 db 'a', 'b', 'c', 0 = 定义了四个字节。当你只定义它像 a, b, c 三个字节时,数组将是 3 个字节:

char str2[]{'a', 'b', 'c'};     // str2[3]

当您通过 [n] 定义 char 数组时,不涉及 +1,该数组恰好有 n 个字符。如果将 C 字符串文字放入其中,它们最多可能有 (n-1) 个字符长,因为第 n 个字节将被零终止符占用。


您可以检查源代码在编译后的样子here .

这可能会以最好的方式回答您的问题。

您可能需要特别注意内存内容定义,我在 testA 数组定义的初始行添加了一些注释:

testA:
        .string "a1"       ; three bytes 'a', '1', 0 defined
        .zero   14         ; remaining 14 zeroed to have char[17]
        .zero   3          ; padding for "int x"
        .long   1111       ; int x
        .long   1066284351 ; float a
        .string "a2"       ; char[17] of second element
...

关于c++ - 指向结构指针数组的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41732727/

相关文章:

c++ - 没有 volatile 的互斥锁功能是否足够?

c++模板扣除头文件中指定模板的数组大小

c++ - 试图理解 C++ 指针和数据类型初始化

assembly - RESB、RESW、RESD、RESQ在NASM中分配了多少字节?

c++ - 来自数组 0 初始化的奇怪程序集

c++ - 在 std::map 中使用 std::reference_wrapper

c++ - 如何得到交点?光线三角形相交 C++

c - 用C将比特流写入文件

c - 为什么我的结构和数组不起作用?

assembly - 如何将字符串的第一个字符与 x86-64 汇编中的另一个字符进行比较?