structs lab

x86 reverse engineering - last updated 2026-05-19

overview

Structs are a fairly basic C concept that allows for structuring of data similar to object oriented programming seen in C++, basically a more archaic class. In assembly however, there isn’t really any concept similar to structs, so being able to identify them is an important skill to learn.

To do this I created a small C program to reverse and debug in order to get some familiarity with reversing structs.

main function & heap

Along with seeing struct operations, I also wanted this lab to give me some exposure to the heap, so as you can see when the colin user struct is being created, it is allocated using malloc and stored on the stack

After the function prologue, I can see that the decimal value 8 is pushed onto the stack right before the malloc call. The malloc function takes a single size_t value and returns a pointer to the allocated regin of memory.

In my code I allocated the size of our user struct, which is just two integers, or 8 bytes, so this makes sense.

After the call to malloc, I can see that the stack pointer is decremented by 4 bytes, seemingly clearing some space or shrinking the stack. After that I can see that the value of eax is placed onto the stack in the stack segment, or current stack frame. I was curious about the use of dword ptr, so I looked it up and found a great answer on stack overflow, it basically ensures the CPU writes exactly 32-bits.

So it seems like the pointer returned by malloc gets stored in the EAX register and then gets placed on the stack afterwards. Let’s set a breakpoint on that add instruction and check the EAX register to see where it points to.

Cool, so it seems like 0xCD is used as a fill pattern, and as we can see exactly 8 bytes at 0x0076C020 are reserved for our structure. I can also right click this section and select “Follow in Memory Map” in order to see that it is indeed located in the Heap region of memory.

create_user

Now I’m going to take a look at the create_user function. The function takes in three parameters, a pointer to a user struct, and two integer values.

The function will then assign the two provided integers to their corresponding member of the user struct.

Lets take a look at what this function looks like in assembly.

Firstly, I can immediately see two sets of move operations, both starting by storing ebp+8 into a register. I believe that the parameter found at ebp+8 is almost certainly the pointer to the user struct.

Lets actually step through this function to see the struct change in memory in real time. I’ll start by setting a breakpoint on that second move operation after the function prologue.

Okay so now that the pointer to our provided struct is stored in the EAX register, I’m going to write it down and then step through until that first value has been written.

Note: addresses have changed because I had to restart the program

Cool, I can see in memory the 1 value I assigned the id member. Since it’s a type int, its 4 bytes in memory, which we can see as only four bytes have been 0’d out while the other four bytes have the 0xCD fill pattern still.

We can then go back to the EIP and step forward to the end of the function and check back to see if the 20 value was written to the struct.

And there it is, I can now see both the values I wrote to the struct.

important to remember

An important thing that I’m realizing is crucial to reverse engineering is that you don’t necessarily need to understand the entire context as long as you can identify patterns in the assembly.

For instance, I’m now able to more quickly identify when a struct is being written to just by understanding the pattern of incrementing offsets in memory access instructions.