Two special functions for C++ classes are the constructor and destructor. When an object is created, the constructor is called. When an object is destroyed, the destructor is called.
The constructor performs any initialization needed by the object. Objects can be created on the stack or stored on the heap. For objects created on the stack, there is no need to allocate specific memory for the object; the object will simply be stored on the stack along with other local variables.
The destructor for objects is automatically called when the objects go out of scope. Sometimes this tends to complicate disassembly, because the compiler may need to add exception handling code in order to guarantee that object destructors are called.
For objects that are not stored on the stack, the memory is allocated with the new
operator, which is a C++ keyword that creates heap space for a new
object and calls the constructor. In disassembly, the new
operator is usually an imported function that can be spotted easily. For example, Example 20-8 shows the IDA Pro disassembly using the new
operator implemented as an imported function. Since this is the
new
operator and not a regular function, it has an unusual
function name. IDA Pro identifies the function properly as the new
operator and labels it as such. Similarly, a delete
operator is called when heap-allocated objects are to be freed.
Object creation and deletion are key elements of the execution flow for a C++ program. Reverse-engineering these routines can usually provide key insight into the object layout and aid analysis in other member functions.
Example 20-8. The new
operator in disassembly
00401070 push ebp 00401071 mov ebp, esp 00401073 sub esp, 1Ch 00401076 mov [ebp+var_10], ❶ offset off_4020F0 0040107D mov [ebp+var_10], ❷ offset off_4020DC 00401084 mov [ebp+var_4], offset off_4020F0 0040108B push 4 0040108D call ??2@YAPAXI@Z ; operator new(uint)
In Example 20-8, we’re looking at an object stored on
the stack. The offset moved into location var_10
is the vtable.
The compiler here shows some strange behavior by putting different offsets into the same location
twice in a row. The instruction at ❶ is useless, because
the second offset at ❷ will overwrite what is stored at
❶.
If we were to look at the offsets for this code, we would see that they are the vtables for the two classes. The first offset is the vtable for the parent class, and the second offset is the vtable for the class of the object being created.