Struct Layout
and Offset Analysis in Reverse Engineering
It is much easier to understand Struct when we have the Source Code
For example:
struct User {
int id;
int age;
char *name;
};
Here we know exactly what each Field is and where it is located.
But in Reverse Engineering, this code is usually not mentioned
The compiler converts Struct into Machine Code and Assembly instructions and what we see may be just this:
mov eax, [rdi+0x4]
mov rax, [rdi+0x8]
Here, the compiler no longer tells us:
+0x04 = age
+0x08 = name
So we have to figure out what Field each Offset probably belongs to based on how Memory is used
This is one of the important parts of reconstructing unknown structures
What exactly is Offset?
Suppose the starting address of an Object is:
0x1000
Now in Assembly we have:
mov eax, [rdi+0x4]
If RDI is 0x1000, the CPU goes to:
0x1000 + 0x4 = 0x1004
That is:
Object Base
|
v
0x1000
+0x00
+0x04 <-- accessed
+0x08
+0x10
That +0x4 is the Offset
So when you see in RE:
[Register + Offset]
One of the first questions is:
Where does this Register point to?
What Field does this Offset indicate?
In many cases, what we are looking for is this:
Base Address + Offset
|
v
Field
Now let's look at a simple Struct
For example:
struct User {
int id;
int age;
char *name;
};
In a typical 64-bit environment where int is four bytes and pointer is eight bytes, the conceptual layout can be like this:
Offset Size Field
+0x00 4 bytes id
+0x04 4 bytes age
+0x08 8 bytes name
So when the Compiler wants to read age:
mov eax, [rdi+0x4]
And to read name:
mov rax, [rdi+0x8]
We can gradually rebuild the Layout Struct based on these Offsets
Of course, this Layout also depends on ABI and Alignment, so we should not always assume a definitive Layout for all Binaries
Distinguish Read and Write
This command:
mov eax, [rdi+0x4]
means the value in Object + 0x4 is read
So:
read field at +0x4
But this:
mov [rdi+0x4], eax
means a new value in Object + 0x4 is written
So:
write field at +0x4
This difference is very important in RE
For example, if we see in several places of the program:
mov eax, [rdi+0x4]
And in another place:
add dword ptr [rdi+0x4], 1
We can guess that +0x4 is probably a numeric value or something with numeric behavior
Why?
Because the program is directly operating on that Memory as a 32-bit value
The size of the Memory Access also gives a clue
For example:
mov eax, [rdi+0x4]
Here we are reading a 4-byte value.
In contrast:
mov rax, [rdi+0x8]
An 8-byte value is read
In a 64-bit binary this value can be a Pointer or a 64-bit value
Now if we see later:
mov rax, [rdi+0x8]
mov rcx, [rax]
Here we have an important clue
The value we read from:
Object + 0x8
was later used as an Address
So it is more likely to be a Pointer:
+0x8 = pointer ?
But keep the question mark for now 😁
In Reverse Engineering, it is better not to draw a definitive conclusion with a quick instruction
Assembly
alone does not tell much, we need to see the Context
Look for duplicate Offsets
One of the very good methods is to check an Offset in several different functions
For example:
Function A:
mov eax, [rdi+0x4]
And:
Function B:
cmp dword ptr [rdi+0x4], 0
And:
Function C:
add dword ptr [rdi+0x4], 1
If RDI in these functions really points to the same Object, there is a high probability that:
+0x4
is a common Field of the same Struct
Now, for example, we see:
mov rax, [rdi+0x8]
And elsewhere:
call [rdi+0x8]
Here we need to check more
Maybe +0x8 is a Pointer Okay
It could be a Function Pointer
Or it could be part of a specific Object Layout
So don't just name it by Offset
Check the behavior of that Field too
Find the Base Pointer
Before we go into Offsets, we need to understand what the Base Register actually points to
For example:
mov eax, [rdi+0x4]
RDI could be pointing to a Struct
But just because it's called RDI, we can't conclude that
We need to follow the value path
For example:
mov rdi, rbx
call process_user
Post #1846
34
ReverseEngineering Struct Layout و Offset Analysis در Reverse Engineering وقتی Source Code رو داشته باشیم فهمیدن Struct خیلی راحت تره مثلا: struct User { int id; int age; char *name; }; اینجا دقیقا میدونیم هر Field چیه و کجا قرار گرفته. ولی توی Reverse Engineering…
- ❤ 1