How to make IDA properly generate array offsets?

Assuming I am reversing a 32bit c++ structure that has an array at some offset. I have the data layout filled up in the Local Types, and for the most part it is working great when generating the pseudocode:

element = myClass→array[stide * index];

But very often (in the same subroutine) it also does this:

element = myClass→gap0[stride * index]
actualElement = element + the array offset;

Both land at the same pointer, but the second variant is unreadable and make me falsely think that there is an array at the 0 offset (which I did believe at first and messed up my layouts :sweat_smile: ).

Is there a way to force or help IDA to prefer the proper indexing? It’s not that the layout is filled up wrong, since it does figure out 2 out of 4 structure fields.

Here is an actual example:

struct Render_Service

{

00090178 TextureBuffer textures_info[2048];

}

00000000 struct TextureBuffer // sizeof=0x10
00000000 { // XREF: Render_Service/r
00000000 _DWORD *data;
00000004 int width;
00000008 int height;
0000000C int flags;
00000010 };

and a subroutine:

int __thiscall sub_40B850(Render_Service *this, int a2, int *a3, int *a4, int *a5)
{
int width; // esi
char *v6; // eax
int v7; // ecx
int result; // eax

width = this->textures_info[a2].width;
v6 = &this->gap0[16 * a2];
*a4 = this->textures_info[a2].height;
v7 = *((_DWORD *)v6 + 147553); // ->textures_info[a2][3] = ->flags
result = *((_DWORD *)v6 + 147550); // ->textures_info[a2][0] = ->data
*a3 = width;
*a5 = v7;
return result;

}

set type of var “v6” as “Render_Service *”

1 Like

nice, thanks @revs ! worked out like a charm

I think there’s indeed another array at +0 offset.

i used to think that way, but then i would get conflicting data layout that overlaps and impossible to work out

the thing is though is that v6 (or similar pre-calculated variables) would never be used to directly access anything. It always used as an offset to an address, that just happens to be an array

it still is a bit annoying, it maps correctly to the structure field, but instead of using the index, it just points to [0].

v8 = (Render_Service *)((char *)this + 16 * slot_idx);
width = v21;
height = v22;
v8->textures_info[0].width = v21;
this->textures_info[slot_idx].height = height;
v12 = mip_level;
v11 = mip_level == 0;
pixel_count = 0;
v8->textures_info[0].mip_level = mip_level;

without structure layout

v8 = &this[4 * slot_idx];
width = v21;
height = v22;
v8[147551] = v21;
this[4 * slot_idx + 147552] = height;
v12 = mip_level;
v11 = mip_level == 0;
pixel_count = 0;
v8[147553] = mip_level;

it looks like it can do this[4 * slot_idx + 147552]

but v8[147551] is confusing IDA

the code is so much readable tho, so its not that critical