Hex-Rays' blog

Igor’s tip of the week #12: Creating structures with known size – Hex Rays

Written by Igor Skochinsky | Oct 22, 2020

Sometimes you know the structure size but not the actual layout yet. For example, when the size of memory being allocated for the structure is fixed:

In such cases, you can quickly make a dummy structure and then modify it as you analyze code which works with it. There are several approaches which can be used here.

Fixed-size structure 1: single array

This is the fastest option but makes struct modification a little awkward.

  1. create the struct (go to Structures view, press Ins and specify a name);
  2. create the array (position cursor at the start of the struct, press * and enter the size (decimal or hex)

When you need to create a field in the middle, press * to resize the array so it ends before the field, create the field, then create another array after it to pad the struct to the full size again.

Fixed-size structure 2: big gap in the middle

  1. create the struct (go to Structures view, press Ins and specify a name);
  2. create a byte field (press D);
  3. add a gap (Ctrl–E or “Expand struct type..” in context menu) and enter the size minus 1;
  4. (optional but recommended) On field_0 which is now at the end of the struct, press N, Del, Enter. This will reset the name to match the actual offset and will not hinder creation of another field_0 at offset 0 if needed.

To create fields in the middle of the gap, go to the specific offset in the struct (G can be used for big structs).

Fixed-size structure 3: fill with dummy fields

  1. create the struct (go to Structures view, press Ins and specify a name);
  2. create one dummy field (e.g. a dword);
  3. press * and enter the size (divided by the field size if different from byte). Uncheck “Create as array” and click OK.

Automatically create fields from code

Using a structure with a gap in the middle (option 2 above) is especially useful when analyzing functions that work with it using a fixed register base. For example, this function uses rbx as the base for the structure:

ATI6000Controller::initializeProjectDependentResources(void) proc near
  push    rbp
  mov     rbp, rsp
  push    rbx
  sub     rsp, 8
  mov     rbx, rdi
  lea     rax, `vtable for'NI40SharedController
  mov     rdi, rbx        ; this
  call    qword ptr [rax+0C30h]
  test    eax, eax
  jnz     loc_25CD
  mov     rax, [rbx+168h]
  mov     [rbx+4B8h], rax
  mov     rax, [rbx+178h]
  mov     [rbx+4C0h], rax
  mov     rax, [rbx+150h]
  mov     [rbx+4C8h], rax
  mov     [rbx+4B0h], rbx
  mov     rax, [rbx+448h]
  mov     [rbx+4D0h], rax
  mov     rcx, [rbx+170h]
  mov     [rbx+4D8h], rcx
  mov     rcx, [rax]
  mov     [rbx+4E0h], rcx
  mov     eax, [rax+8]
  mov     [rbx+4E8h], rax
  call    NI40PowerPlayManager::createPowerPlayManager(void)
  mov     [rbx+450h], rax
  test    rax, rax
  jnz     short loc_2585
  mov     eax, 0E00002BDh
  jmp     short loc_25CD
---------------------------------------------------------------

loc_2585:
  mov     rcx, [rax]
  lea     rsi, [rbx+4B0h]
  ...

To automatically create fields for all rbx-based accesses:

  1. select all instructions using rbx;
  2. from context menu, choose “Structure offset” (or press T);
  3. in the dialog, make sure Register is set to rbx, select the created struct (a red cross simply means that it has no fields at the matching offsets currently);
  4. from the right pane’s context menu, choose “Add missing fields”.

You can then repeat this for all other functions working with the structure to create other missing fields.