Указатель на массив указателей на структуры

У меня даже нет вопроса, я думаю, что это какое-то подтверждение, что я правильно понимаю предмет.
Я занимаюсь обратным инженерным изучением и вот что у меня есть.
Допустим, у нас есть структура / класс, который выглядит следующим образом:

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 байтов — это просто идентификационная информация, затем после этой информации идет строка, которая составляет 64 байта, это имя. Затем идет координата для X / Y / Z. Все после этого не имеет значения.
Это было не так сложно найти, вот скриншот, как это выглядит:
состав
/
Поэтому я могу найти другие структуры, просто добавив или вычтя 0x1200 по адресу, с которого начинается эта структура.
Я искал адрес, с которого начинается структура, и нашел указатель на это.
Затем я просканировал доступ к указанному указателю и получил что-то вроде этого:

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

Затем я искал eax значение и нашел указатель, который указывает на eax
Вот почему я подумал, что это массив указателей.
Надеюсь, я объяснил это немного более конкретно.

0

Решение

Ваш вопрос на самом деле полон наземных мин, что продемонстрирует, почему точность сборки очень важна, к несчастью.

Итак, что у меня есть …

Вы показываете синтаксически неправильную анонимную структуру, и вдруг у вас есть какой-то указатель? Это не работает так. У вас анонимная структура и пара синтаксических ошибок, не более того.

Теперь здесь я действительно чувствую себя хорошо, чтобы остановиться на ответе, потому что остальная часть вашего вопроса не имеет смысла без фактического определения данных. Но допустим, вы имели в виду что-то вроде этого:

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 как указатель, он не указывает на дальнейшие указатели, он указывает непосредственно на данные.

Таким образом, у вас есть не один уровень, а два уровня дополнительной косвенности в ОП. Читать 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 + п + 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-й байт будет занят нулевым ограничителем.


Вы можете проверить, как этот источник выглядит после компиляции Вот.

Который, вероятно, ответит на ваш вопрос наилучшим образом.

Вы можете обратить особое внимание на определение содержимого памяти, я добавил некоторые комментарии к начальным строкам 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
...
3

Другие решения

Hahahahaha …….
Извините, но я не могу остановить свой смех, так как это мой второй день на Stackoverflow, и я задал вопрос, который ответит на эту дилемму. Я не совсем понимаю, что ты пытаешься сделать, но я совершенно уверен, что ты не учел паддинг. Ну, вчера я научился паддингу, поэтому постараюсь помочь тебе здесь.

Ну, у каждого массива есть указатель на его первый элемент в виде имени массива. Так что у вас есть указатель по умолчанию или вы можете создать свой собственный. Это очень простая задача — разыменовать структуру в массиве указателей. Основная проблема, с которой вы сталкиваетесь, — это доступ к членам структуры.

//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 */

Посмотрите на код. Структура A упакована, поэтому заполнение не выполняется. Структура B является дополненной версией A. B — та, которую вы используете. Padding варьируется в зависимости от n.

Здесь я взял n = 5 для большей части заполнения. Здесь первые 5 байтов выделены массиву str. Теперь следующие 3 байта выделены для заполнения. Это сделано для того, чтобы ОЗУ могло обращаться к 8 байтам одновременно, а не к одному байту за раз, как это делается в случае упакованного strcuture. Это повышает производительность. Стандартов для заполнения нет, поэтому он зависит от архитектуры и компилятора. В 64-битной архитектуре доступ к 8 байтам осуществляется одновременно. Вот почему 64-битная версия быстрее 32-битной, а игры не поддерживают 32-битную.
Чтобы получить доступ к int x, вам нужно сместить адрес массива на 8 байтов, а не на 5. Для доступа к float снова увеличьте смещение на 8 байтов.
Примечание. Здесь выводится только адрес массива, а не отдельный элемент массива. Вы можете достичь того же, увеличивая на единицу.

Если вы не получили его, прочитайте выравнивание памяти в C ++.

https://en.wikipedia.org/wiki/Data_structure_alignment

0