我甚至没有一个问题,我认为这是某种确认,我正确理解了这个主题 我正在进行一些反向改造研究,这就是我所拥有的。 假设我们有结构/类,看起来像这样:
struct {
char str[n]
int x
float a
}
在我们正在研究的流程的内存中,我们有一系列这些结构。
所以,我所拥有的是指向结构指针数组的指针 如果我错了,现在可以请你纠正我。要读取此数组的第一个元素的x值(实际结构,而不是指针),我必须按照以下步骤操作:
我是对的吗?我会得到第一个结构包含的实际X吗?要从第二个中获取X值,我只需要在步骤2中添加偏移量(+4个字节)?
我认为我这样做是正确的,但我实际上无法从指针到达结构。我会说,指向数组的指针是100%正确的。
感谢阅读,会等待答案。如果您需要更多信息,请提出要求。
P.S。没有得到任何破解或任何一切只是为了教育目的
增加:
好吧,我试图简化这个只是让它更难以解释和理解。现在我要尝试解决它。
一种结构描述了游戏中的NPC参数。整个结构的大小为0x1200。前16个字节只是ID信息,然后在此信息之后是64字节的字符串,它就是名称。然后去X / Y / Z的坐标。这些之后的一切都无关紧要
它不是很难找到,这是截图如何:
/
所以我可以找到其他结构,只需将0x1200加到或减去该结构开始的地址即可
我搜索了结构开始的地址,并找到了指向它的指针。
然后我扫描了对找到的指针的访问并获得了类似的东西:
mov [eax+edx*4+00320], ecx
然后我搜索eax
值并找到指向eax
的指针
这就是我认为这是指针数组的原因
希望我能更具体地解释一下这一点。
答案 0 :(得分:3)
你的问题实际上充满了地雷,这将以不幸的方式证明为什么装配的准确性如此重要。
所以,我拥有的是......
你显示语法不正确的匿名结构,突然你有一些指针?它没有这样的工作。你有匿名结构和几个语法错误,仅此而已。
现在,我真的很乐意停下来回答,因为如果没有实际的数据定义,你的问题的其余部分就没有意义了。但是,让我们说你有这样的事情:
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 ++中更多一点,尽管它很乐意“衰退”#34;当使用这样的指针时,它并不完全相同。
当我使用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]
当您按char
定义[n]
数组时,没有涉及+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
...
答案 1 :(得分:0)
Hahahahaha ....... 对不起,但我无法阻止我的笑声,因为这是我在Stackoverflow上的第二天,我问问题是哪个回答这个困境。我不太明白你要做什么,但我很确定你没有考虑填充。我昨天学会了填充,所以我会尽力帮助你。
好吧,每个数组都有一个指向其第一个元素的指针作为数组的名称。所以你有默认指针,或者你可以创建自己的指针。在指针数组中对结构进行derefrence非常容易。您面临的主要问题是访问结构成员。
//This answer is architecture and compiler dependent
//My settings are TDM GCC 4.9.2 64bit and Windows 10
const int n = 5;
#pragma pack(push, 1)
struct A{
char str[n];
int x;
float a;
};
#pragma pack(pop)
struct B{
char str[n];
int x;
float a;
};
int main(){
printf("Size of A is %d\n", sizeof(A));
printf("Size of B is %d\n", sizeof(B));
B k;
for(int i=0; i<n; i++)
printf("Address of str[%d] in k is %x\n",i, &(k.str[0]));
printf("Address of int x in k is %x\n", &(k.x));
printf("Address of float a in k is %x\n", &(k.a));
}
/*
Result -
Size of A is 13
Size of B is 16
Address of str[0] in k is 9ffe30 Address of array
Address of str[1] in k is 9ffe30 Address of str[1] in k is 9ffe31
Address of str[2] in k is 9ffe30 Address of str[2] in k is 9ffe32
Address of str[3] in k is 9ffe30 And so on..
Address of str[4] in k is 9ffe30
Address of int x in k is 9ffe38 Address of Array + 8Bytes
Address of float a in k is 9ffe3c //Address of Array + 2*8Bytes
n -- padding
4k+1 -- 3
4k+2 -- 2
4k+3 -- 1
4k -- 0 */
查看code.Structure A已打包,因此不会执行填充。结构B是A的填充版本.B是你正在使用的。随着n的变化,padding会有所不同。
这里我对大多数填充采用n = 5.这前5个字节分配给数组str。现在接下来的3个字节用于填充。这样做是为了RAM可以一次访问8个字节而不是一次一个字节,就像打包的strcuture一样。这提高了性能。填充没有标准,因此它随架构和编译器而变化。在64位架构上,一次访问8个字节。这就是为什么64位比32位更快,而游戏不支持32位。 为了访问int x,你需要将数组的地址偏移8字节而不是5.要再次访问float,增加偏移量为8Bytes。 注 - 这里只输出数组的地址,而不是单独的数组成员。您可以通过递增1来实现相同目的。
如果你没有读到C ++中的内存对齐。