Data structures (struct
s, union
s, class
es, etc) are higher level elements that completely disappear after the compilation step takes place. Meaning that the concepts themselves are completely invisible in the binary. Of course, certain code patterns may still suggest or imply that a data structure was present in the code, there are no assembly equivalent (nor one is needed) to the struct
, union
or class
keywords.
After providing the above context, I'll address the specific questions and statements you've made throughout the question:
I believe that ebp + offset
are local variables?
You accurately understand that ebp
is used to reference the stack and that therefore any ebp
based reference is probably a reference to a stack-based variable.
Could it really just be tonnes of local variables?
It could. However as I've explained in the first paragraph it is impossible to know for sure whether the original source code had a lot of local variables or a single, a few, or maybe even nested structures.
It is however, unnecessary (unless your goal is to reach binary identical code reconstruction) to specifically use the same constructs used in the original code. If your goal is to gain a decent understanding of the code, you should feel free to implement those data structures as you see fit and will be the most intuitive representation for you. You should rely on IDA's structure definitions you make the assembly code as readable to you as possible, without putting too much thought as to how the original source code was written.
Or could it actually be a data structure and this is how IDA is representing it?
Therefore, this is not how "IDA represents it", but how any compiler will translate the code to assembly. IDA just helps with an interactive interface to the disassembled machine code.
ebp
is the base address of the structure
As the function starts with a rather standard mov ebp, esp / sub esp, IMM
it is unlikely that ebp
itself points to a structure. It points to the stack offset at where a new stack frame was created. This is a very common practice. It is very likely, however, that a structure begins at a certain offset on the stack, and ebp
is used to reference it, using the offset from the start of the stack frame.
The mov
instructions between the mov [...], offset value
are padding bytes
Assuming you're talking about the mov, REG, IMM
instructions, these are probably register initializations that are used further down the line. They are spread between the stack-based mov
instructions for performance reasons. To oversimplify, pipeline optimizations allow modern processors to assign register values somewhat in parallel to slower RAM write operations, resulting in an overall faster execution.
I'm guessing they are just padding bytes since esi
doesn't contain a value (it was xor
at the top of the screenshot) and is mov ebp + offset
quite a lot in this block.
The esi
register does contain a value, that value is simply zero. xor
ing a register with itself is a common way to set it to zero, which is shorter than a mov REG, 0
instruction to encode. Additionally, mov OFFSET, REG
is shorter than mov OFFSET, 0
, so overall the compiler saves us a few bytes of code.