classification of structural bodies
A notable feature of structs is that data fields in structs are accessed by name rather than indexed as arrays. The bad thing is that the field name is converted to a numeric offset by the compiler. As a result, the way the struct fields are accessed in the Disassembly code list looks very similar to the way you access array elements using a constant index.
Note that there is a memory alignment rule in the struct, so do not assume that the compiler will use the minimum space required to allocate the struct. By default, the compiler will try to align the struct field with the memory address to most efficiently read and write these fields 1. Globally allocated structure
As with the globally allocated array, the compiler learns the address of the globally allocated struct at compile time. This allows the compiler to calculate the address of each member in the struct at compile time without having to perform any calculations at run time.
The following code:
struct sttest
{
int F1;
Short F2;
Char f3;
int f4;
Double f5;
};
Sttest G_st;
void Fun ()
{
g_st.f1 = ten;
G_ST.F2 =;
G_ST.F3 = +;
G_ST.F4 = +;
G_st.f5 = 50.0;
}
The corresponding assembly is: it can be seen that in this disassembly code list, access to struct members does not require any arithmetic calculations, if there is no source code, you simply cannot conclude that the program uses the structure.
Push EBP
mov EBP, esp
mov dword_403018, ten; int f1 = ten
mov eax,
mov word_ 40301C, Ax; Word F2 = "
mov byte_40301e", "byte" = "F3" = "
mov dword_403020", "int f4 = " FLD Ds:dbl _4020e0 ; f5 = dbl_403028 = 50.0
fstp dbl_403028
pop ebp
retn
2. Stack allocation structure
Similarly, it is also difficult to identify the structure of a stack allocation based solely on the stack layout.
void Fun ()
{
sttest l_st;
L_ST.F1 = ten;
L_ST.F2 =;
L_ST.F3 = +;
L_ST.F4 = +;
L_st.f5 = 50.0;
}
The corresponding assembly is: Similarly, accessing a field in a struct does not require any arithmetic calculations, because at compile time, the compiler is able to determine the relative offset of each field within the stack frame
$ push EBP
004 mov EBP, esp
004 Sub ESP, 18h
01C mov [ebp+var_18],
01C mov eax, 14h
01C mov [ebp+var_14], ax
01C mov [Ebp+var_12],
01C mov [ebp+var_
01C fld ds:dbl_4020e0
01C fstp [ebp+var_8]
01C mov ESP, EBP
004 Pop EBP
RETN
3. Structure of the heap allocation
Because the address of the struct is not known at compile time, the compiler has no choice but to generate code to calculate the correct offset for each field in the struct.
If a struct is allocated in the heap, the only clue to the compiler that references the struct is a pointer to the start address of the struct.
void Fun ()
{
sttest* PST = new Sttest;
PST->F1 = ten;
PST->F2 =;
PST->F3 = +;
Pst->f4 = +;
Pst->f5 = 50.0;
}
The corresponding assembly is:
Push EBP
mov EBP, esp
Sub ESP, 8
push , unsigned int call ?? 2@yapaxi@z ; operator new (UINT)
add ESP, 4
mov [ebp+var_8], eax; EAX as PST pointer, Var_8 is also
mov eax, [ebp+var_8]
mov [ebp+var_4], eax
mov ecx, [ebp+var_4]; ecx = PST
mov DWORD ptr [ECX], 10; (int*) PST = ten
mov edx, a
mov eax, [ebp+var_4]; eax = PST
mov [eax+4], DX ; (word*) (pst+4) =
a mov ecx, [ebp+var_4]; ecx = PST
mov byte ptr [ecx+6], 30; (byte*) (pst+6) = 30, verified that the second is word byte
mov edx, [ebp+var_4]; edx = PST
mov dword ptr [edx+8], 40; (int*) (pst+8) =
EAX mov , [ebp+var_4]; eax = PST
fld ds:dbl_4020f0 fstp qword ptr [eax+10h]; (DQ) (pst+16) =50.0
mov ESP, ebp
pop ebp
retn
4. Structure Array
void Fun ()
{
sttest* PST = new sttest[2];
PST[1].F1 = ten;
PST[1].F2 =;
PST[1].F3 = +;
PST[1].F4 = +;
Pst[1].f5 = 50.0;
}
Disassembly is no different: compared with the above, each item adds 24
Push EBP
mov EBP, esp
Sub ESP, 8
push ; 48/2 = Call ?? 2@yapaxi@z ; operator new (UINT)
add ESP, 4
mov [ebp+var_8], eax
mov eax, [ebp+ Var_8]
mov [ebp+var_4], eax
mov ecx, [ebp+var_4]
mov dword ptr [ecx+24], ten; pst+24, note +24
mov edx,
eax mov , [ebp+var_4]
mov [eax+1ch], DX
mov ecx, [ebp+var_4 ]
mov byte ptr [ecx+30], pst+24+6
mov edx, [ebp+var_4]
mov dword ptr [edx+32], Max; PS T+24+8
mov eax, [ebp+var_4]
fld ds:dbl_4020f0
fstp qword ptr [eax+40]; pst+14+16
mov ESP, ebp
pop ebp
retn
Create a struct body
Ida's inability to identify structures in the analysis phase can be attributed to two reasons. First, although Ida understands the layout of a struct, it does not have enough information to judge that the program actually uses the struct. Second, the structure of the program may be a non-standard structure that Ida knows nothing about. In both cases, the problem can be resolved, starting with the Structures window 1. Add struct
The first 4 lines of text in the Structures window are used to alert the user to possible actions in that window.
Use hotkey INSERT to start
When you specify the name of the struct and click the OK button, Ida creates an empty struct definition in the structures window
2. Edit struct Members
(1) To add a new field to the struct, place the cursor on the last line defined by the struct (the row containing the ends) and press the D key. The size of the new field depends on the first size you select on the data carousel
(2) If you need to modify the size of the field, first place the cursor on the name of the new field, and then press the D key repeatedly to start the data type on the data carousel Loop, so that the correct data size is selected for the new field. Alternatively, you can use Options▶setup data types to specify a size that does not exist on the data carousel. If the new field is an array, right-click its name and select array from the context menu
(3) To change the name of a struct field, click the field name and press the N key, or right-click the name and select Rename in the context menu and enter a name in the input box.
Here are the help instructions:
• The byte offset of a field is displayed on the left side of the structures window.
• The new size of the structure is updated in a timely manner on the first line of the structure definition.
• You can add comments to a struct field just as you would add a comment to any disassembly line.
• Use the U key to delete a field only if it is the last field in the struct. For other fields, pressing the U key just becomes undefined and can be restored by the D key
Ida does not differentiate between compressed and uncompressed structures. To align the fields appropriately, if you need to fill in the bytes, then you have to be responsible for adding those bytes. The padding byte is best added as a dummy field of the appropriate size. After you add additional fields, you can choose to cancel or retain the definitions for those fields.
• The bytes assigned to the middle of the struct can delete the undefined byte only after the definition of the associated field is canceled (the state of the struct), and the Edit▶shrink struct type (which shrinks the structure).
• You can also add a new byte in the middle of the struct: Select a field after the new byte, and then insert a certain number of bytes in front of the selected field using the Edit▶expand struct type, which expands the struct types.
• If you know the size of a struct without knowing its layout, you need to create two fields. The first field is an array whose size subtracts 1 bytes (size-1) from the size of the structure, and the second field should be 1 bytes. After you create the second field, the definition of the first (array) field is canceled. In this way, the size of the struct is preserved, and then, after you have a closer look at the structure's layout, you can go back and define its field and its size.
After creation is complete as follows:
3. Collapse Open Structure
You can select any field in the structure and press the minus key in the numeric keypad to collapse the definition of the structure into a single line of summaries, or you can double-click the struct name to open the definition. (or ctrl+/ctrl-)
working with structural body templates
1. Right-click, you can see the structure offset option on the context menu: it is clearly stated that it can be sttest.f5+24 (pst[1].f5 = 50.0;)
2. Another way, you can format stacks and global variables into the entire structure, double-click the variable, open the detailed stack frame view, and then use the Edit▶struct Var (alt+q) command to display a set of known structures
After the assembly of the above structure becomes: After reformatting, Ida realizes that any memory reference to the 24-byte block allocated to Var_8 must refer to a field in that struct. If Ida finds such a reference, it makes every effort to associate the memory reference with a defined field in the struct variable
var_8= sttest ptr-8
push ebp
mov EBP, esp
Sub ESP, 8
push , unsigned int
Call ?? 2@yapaxi@z ; operator new (UINT)
add ESP, 4
mov [ebp+var_8.f1], eax
mov eax, [EBP +VAR_8.F1]
mov dword ptr [EBP+VAR_8.F2], eax
mov ecx, DWORD ptr [EBP+VAR_8.F2]
mov DWORD ptr [ecx+ (size sttest)], ten
mov edx,
mov eax, DWORD ptr [EBP+VAR_8.F2]
mov [eax +1CH], DX
mov ecx, DWORD ptr [EBP+VAR_8.F2]
mov byte ptr [ecx+30], the
mov edx, DWORD ptr [ EBP+VAR_8.F2]
mov [edx+ (sttest.f4+18h)], +
mov eax, DWORD ptr [EBP+VAR_8.F2]
fld ds :d bl_4020f0
FSTP [eax+ (sttest.f5+18h)]
mov ESP, ebp
pop ebp
retn
The process of formatting a global variable into a struct is almost identical to the process used to format the stack variable to import a new struct
Ida does offer some shortcuts in creating new structures. Ida is able to parse C (rather than C + +) data declarations, as well as the entire C header file, and automatically create the corresponding Ida struct for the struct defined in those declarations or header files. If you happen to have the source code of the binary file you are reversing, or at least a header file, you can save a lot of time by allowing Ida to extract the relevant struct directly from the source code.
Using the View▶open subviews▶local Types (see ▶ Open Subwindow ▶ Local type) command, you can open the local Types subwindow, which lists all the types resolved to the current database.
Resolve by using the Insert option in the Insert key or the context menu:
------------->
parsing C header file
To parse the header file, you can use File▶load file▶parse C headerfile (▶ Load File ▶ Parse C header file) to select the header file you want to parse. If everything is OK, Ida will notify you compilation successful (compile complete). If the parser encounters any problems, IDA will display an error message in the Output window
Ida adds all successfully parsed structures to the list of standard structures in the current database (specifically, at the end of the list). If the name of the new struct is the same as the name of an existing struct, Ida overrides the original structure definition with the new struct layout. Unless you explicitly choose to add a new struct, the new struct will not appear in the Structures window
• By default, the parser creates a 4-byte aligned struct, and of course you can change it using pack
• The parser can only understand the C standard data type. However, the parser can also understand preprocessor define directives and C typedef statements. Therefore, if the parser has encountered the appropriate typedef before, it will be able to correctly parse types such as unit32_t.
• If you do not have source code, then you will find that using a text editor to quickly define a struct layout in C notation and parse the resulting header file or paste the declaration into a new local type is more convenient than using IDA's cumbersome manual structure definition tool.
The simplest way to add data types to the local Types window is not immediately in structures (struct), right-click on the type and select Synchronize to IDB. use of standard structural bodies
Ida is able to identify a large number of data structures related to various libraries and API functions. When Ida manipulates a struct in the Disassembly code list, it adds the corresponding struct definition in the structures window. Therefore, the structures window displays a subset of the known structures that are applied to the current binary. In addition to creating a custom structure, you can also extract other standard structures from the list of known struct bodies in Ida and add them to the structures window.
First, press the In-sert key in the Structures window. In the Create Structure/union dialog box, there is an Add standard structure (add normal structure) button. By clicking this button, IDA will display the structure master list associated with the current compiler (detected in the analysis phase) and the file format. The structure master list also contains structures that are added to the database by parsing the C header file.
Example: (Parsing file header)
By default, the file header is not immediately loaded into the database after it is created. However, if you select the manual load (manual load) option when you initially create the database, you can load the file header into the database. Loading a file header ensures that only the data types associated with these headers appear in the database. In most cases, file headers are not formatted in any way, because the program does not normally refer to their own header directly. Therefore, it is not necessary for the parser to apply a struct template to the file header.
After a study of a PE binary file, you will find that the first part of the PE file is an MS-DOS header structure named Image_dos_header. In addition, the data in the Image_dos_header points to the location of a im-age_ne_header struct.
The first step is to add a standard image_dos_header struct (you can add the struct at the same time you open the Image_nt_header structure).
The second step is to use Edit▶struct Var (alt+q) to convert bytes starting from _image-base to a image_dos_header struct