Gtzzy
Gtzzy

Reputation: 572

Pointer to the array of pointers to structures

I've got not even a question I think that this is some kind of confirmation, that I understand the subject correctly.
I'm doing some reverse engeneering study and here is what I have. Let's say we have structure/class, which looks like this:

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

And we have an array of these structures in the memory of process we are looking at.

So, what I have is Pointer to the array of pointers to structures.
And now could you please correct me if I'm wrong. To read the x value of the first element of this array(actual structure, not the pointer), I have to follow these steps:

  1. Read the value that pointer points at(4 bytes).
  2. Without any offsets read the value that previously read value points at, also 4 bytes(this will lead me to the address where the structure starts)
  3. Now I have to add the offset to this which is equal to n. And read the value from the address from step 2(step2result+n+1).

Am I right? Will I get the actual X that the first structure contains? To get the X value from the second I just have to add the offset in step2(+4 bytes)?

I think that I'm doing this right but I actually cant reach the structures from the pointers. Pointer to the array is 100% right I'd say.

Thanks for reading, would be waiting for an answers. If you need any more information just ask for that.

p.s. not getting anything cracked or whatever everything just for educational purposes

Addition:
OK, my try to simplify this just only made it harder to explain and understand. Now I'm gonna try to fix it.
One structure describes the NPC parameters in the game. The whole structure has a size of 0x1200. The first 16 bytes is just ID info, then after this information goes string which is 64 bytes, it's the name. Then goes coordinate for X/Y/Z. Everything after these doesnt matter.
It wasnt so hard to find, here's a screenshot how it looks like:
structure /
So I can find the other structures just with adding or subtracting the 0x1200 to the address where that structure starts.
I searched for the address where the structure starts and found a pointer to that. Then I scanned for accesses to that found pointer and got something like that:

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

Then I searched for the eax value and found the pointer which points at eax
That's why I thought that this is the array of the pointers.
Hope I just explained this a bit more specifically.

Upvotes: 0

Views: 314

Answers (2)

Ped7g
Ped7g

Reputation: 16596

Your question is actually full of landmines, which will demonstrate why accuracy with assembly is so important, in unfortunate way.

So, what I have is ...

You show syntactically incorrect anonymous struct, and suddenly you have some pointer? It doesn't work like that. You have anonymous structure and couple of syntax errors, nothing more.

Now here I would actually feel fine to stop with the answer, because rest of your question makes little sense without the actual definition of data. But let's say you had on mind something like this:

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;
}

So, what I have here is array testA. Array is not just pointer, it's a tiny bit more in C++ during compilation, although it will gladly "decay" into pointer when used as such, it's not completely the same.

When I will use testA as pointer, it doesn't point to any further pointers, it points directly at data.

So you have not one level, but two levels of extra indirection in OP. To read x for first element you simply do mov eax,[testA + 20]. No pointer loaded (example is from x86 32b target, on other targets the +20 may differ).

Would you had:

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;

Then to fetch x of second element:

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

I managed to create two levels of indirection (actually I had to edit answer in this part, as I read the assembly from C++ wrong, the incomplete Intel syntax confused me).

Still I'm not sure where do you get all those pointers and why? It's not Java, it's C++, you simply have your data in memory directly. As you can see I had to put quite some effort into getting two indirection levels.

Now you may wonder why x is at +20 and not at +17. Because padding, C++ will align the structure members according to their type, int loves to be aligned, so it is.

That should also explain the 28, which is size of that struct.

Also in your question you have:

step2result+n+1

Where did that +1 come from? Maybe you are confused by this:

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

But that's because "abc" is like db 'a', 'b', 'c', 0 = four bytes defined. When you define it only like a, b, c as three bytes, the array will be 3 bytes:

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

As you define that char array by [n], there's no +1 involved, that array has exactly n chars. If you put C-string literals into it, they may be at most (n-1) characters long, because the n-th byte will be occupied by zero terminator.


You can check how that source looks after compilation here.

Which will probably answer your question in best way.

You may want to pay extra attention to the memory content definition, I added some comment to the initial lines of testA array definition:

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
...

Upvotes: 3

Sourabh Mittal
Sourabh Mittal

Reputation: 311

Hahahahaha....... Sorry but I can't stop my laughter as this is my second day on Stackoverflow and I asked question which answer this dilema. I can't quite understand what you're trying to do but i'm quite sure that you didn't account for padding.Well I learned padding yesterday so i will try to help you out here.

Well, every array has a pointer to its first element as name of array.So you have default pointer or you can make your own.It's very easy task to derefrence to struct in array of pointers. Main problem you are facing is to access the struct members.

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

Look at code.Structure A is packed so no padding is done. Structure B is padded version of A. B is the one you are using.padding varies as n varies.

Here i've taken n=5 for most padding.Here first 5 bytes are alloted to array str. Now next 3 bytes are alloted for padding. This is done so that RAM can access 8 bytes at once rather than one byte at a time as done in case of packed strcuture. This increases performance.There is no standard for padding so it varies with architecture and compiler. On 64bit architecture 8 bytes are accessed at a time. This is why 64bit is more fast than 32bit and games don't support 32bit. In order to access int x you need to offset address of array by 8bytes rather than 5.To access float again increment offset by 8Bytes. Note - Here only address of array is output not for seperate member of array. You can achieve same by incrementing by one.

If you don't get it read Memory alignment in C++.

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

Upvotes: 0

Related Questions