I would like to share about reversing C++ code in IDA especially related to the VTable which is used for pointer to a function during the polymorphism code in the class inheritance
Vtable is a table used by the application to point the function call of an object (C++ class). VTables appear when the compiler does not know which function to be called during compile time. It is because of the appearance of virtual function (Object Inheritance)
Let’s analyze the image below, Class C inherits the Class B. So that Class B will point to the function-specific to its member B::bar() and B::qux. While Class C that inherits from class B then it will mean to function member that overrides the function in class B that is C::bar() while class C will still point to B:qux() because class C does not override it
VTable in Assembly
How the above scheme is laid out into assembly language. It will follow this diagram
When an C++ object is created, a memory pointer will be created and assinged to it to hold the pointer to the object. You can see the operator new will return the object pointer into eax
As you may see that the first dword pointer of the following address from the class points to the first VFTable in the PE data section, where this VFTable is pointing to the address of a function in the assembly area. Like below
When we see the offset const Poligon::`vftable data section, it points to function Poligon::area(void) and the next 4 bytes will point to Poligon::keliling(void).
When the application want to call the function member of the class, it will access them like an array which is using bytes iterator such as eax+4 will call the second function which is Poligon::keliling(void)
we can see that the sequence as below
mov eax, [ebp+Polygon_Object_Ref_2] : this will copy the the value of ebp+Polygon_Object_Ref_2 to eax.
mov edx, [eax] : it will copy the value of eax point to which is the VFTable. So EDX will represent the VFTable address
mov eax, [edx] : it will also again copy the value that the edx point to that is the actual code for Poligon::area()
call eax : It will bring you jump the address of Poligon::area() on 0041141A
Because the call function is not defined during compile time then the way it call the function will be different then normal. It will call the function using call eax
If we see the eax register will point to the virtual function Poligon::area()
Automate the Process
In order to automate the VTable mapping, we can use python code script. I do not create my self the code but i took it from
""" A simple script to locate vtable groups in binaries with the Itanium ABI. Note that this script does not account for virtual inheritance or (more notably), cases were the vtable contains null pointers. This may happen in more recent compilers with purely abstract types. """ import idaapi import idautils def read_ea(ea): return (ea+4, idaapi.get_32bit(ea)) def read_signed_32bit(ea): return (ea+4, idaapi.as_signed(idaapi.get_32bit(ea), 32)) def get_table(ea): ''' Given an address, returns (offset_to_top, end_ea) for the table located at that address or None if there is no table''' ea, offset_to_top = read_signed_32bit(ea) ea, rtti_ptr = read_ea(ea) if rtti_ptr != 0: return None func_count = 0 while True: next_ea, func_ptr = read_ea(ea) if not func_ptr in idautils.Functions(): break func_count += 1 ea = next_ea if func_count == 0: return None return offset_to_top, ea def get_table_group_bounds(ea): ''' Given an address, returns the (start_ea, end_ea) pair for the table group located at that address''' start_ea = ea prev_offset_to_top = None while True: table = get_table(ea) if table is None: break offset_to_top, end_ea = table if prev_offset_to_top is None: if offset_to_top != 0: break prev_offset_to_top = offset_to_top elif offset_to_top >= prev_offset_to_top: break ea = end_ea return start_ea, ea def find_tablegroups(segname=".rodata"): ''' Returns a list of (start, end) ea pairs for the vtable groups in 'segname' ''' seg = idaapi.get_segm_by_name(segname) ea = seg.startEA groups =  while ea < seg.endEA: bounds = get_table_group_bounds(ea) if bounds == bounds: ea += 4 continue groups.append(bounds) ea = bounds return groups
After running the above in the IDA python interpreter, you can execute
find_tablegroups() to get a list of vtable group addresses.