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.
- create the struct (go to Structures view, press Ins and specify a name);
- 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
- create the struct (go to Structures view, press Ins and specify a name);
- create a byte field (press D);
- add a gap (Ctrl–E or “Expand struct type..” in context menu) and enter the size minus 1;
- (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 anotherfield_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
- create the struct (go to Structures view, press Ins and specify a name);
- create one dummy field (e.g. a dword);
- 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:
- select all instructions using
rbx
; - from context menu, choose “Structure offset” (or press T);
- 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); - 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.