This blog post will demonstrate the process of reverse engineering object-oriented programming concepts such as Classes, Inheritance and Virtual functions. Using a simple piece of C++ code I will reconstruct the decompiled code to an understandable compliable format using tools such as the Snowman Decompiler and IDA PRO.

The C++ Code

class A {
public:
virtual void print() = 0;
};

class B : public A { //make class a assessable to class b
public:
void print() { cout << “Class B” << endl; }
};

class C : public A { //make class a assessable to class c
public:
void print() { cout << “Class C” << endl; }
};

int main(){
A *a1, *a2;
a1 = new B();
a2 = new C();
a1->print();
a2->print();

system(“pause”);
return 0;
}

The Decompiler

When a C++ program is compiled from source code all class information is lost (classes store function information in addition to data), locals and names don’t appear in the binary. Class Methods are turned into functions and the function names are mangled. This leaves analysing and reversing a C++ binary more complex.

The decompiler allows you to understand the structure and logic of classes, by turning assembly into Pseudo code. This Pseudo code is complex and hard to understand, more code is produced than needed, you have partial or missing code making reconstructing the code more complex.

Snownman Decompiler

Snowman decompiles C++ Object-Oriented code to (ANSI-C ) C code of the same equivalent. The snowman decompiler supports x86, AMD64, and ARM architectures. You can use it as a standalone GUI application, a command-line tool, an IDA plug-in, a radare2 plug-in, an x64dbg plug-in, or a library.

The Main Method

When the file is decompiled in the Snowman Decompiler we can go straight to the main method as shown.

The code may not be understandable to the untrained eye. The classes are converted to functions.
We can see here two functions and two created objects. The objects are converted to function pointers and executed.

The Classes

Having a quick look at functions related to main, which would have been class methods, we can see three functions, their names are A(), B() and C(). I rename these functions as _A, _B and
_C.

Inheritance
Looking at the code, I can see Inheritance is implemented which is an object-oriented programming concept in which parent-child relationships are established between classes. Child classes inherit function and data from the parent base class.


We have three classes here, _A is the base type and both _B and _C are subtypes which inherit the characteristics and behaviours of _A.

All three classes have been decompiled as type void, we change _A to type struct, as structs are the same as classes in C++, without changing the whole structure of the code. A quick tidy up of the classes makes things more clear:

There are different methods to achieve Inheritance the method I have chosen here is include a struct pointer as an argument in the _B and _C functions. From experience I see a pointer to two Virtual functions in class _B and _C.

VIRTUAL FUNCTIONS
Using Virtual functions is how Polymorphism is implemented. A standard function is normally executed at compile time. A Virtual function is one that can be overridden by a subclass and whose execution is determined at runtime.

This is used to simplify complex programming tasks. A Virtual function has to be named “Virtual” in the C++ code.

Virtual Function Table
The C++ compiler adds special data structures when it compiles code to support virtual functions, these data structures can be called virtual functions tables of vtables or vftables. A virtual table is a lookup table of functions pointers.

Virtual Functions In IDA PRO
Looking in IDA PRO at class B we see its calling a virtual function in class A.

Double clicking on off_49510 we see the following:

The address off_49510 is a virtual table and it stores a pointer to a virtual function called print. It looks to be a virtual print function, if we double click on _ZN1B5printEv we see the following:

Reconstructing Classes

With the information we now have we have a better idea of how this program is constructed. Going back to the classes I changed the following:

Class _B and _C inherits _A object pointer through a function argument and also returns a struct object. I renamed the two virtual function addresses to vftable1 and 2 so they can be used in this program.


I introduced a function pointer to Struct _A called “print”, this will be used later in main as a pointer to either vftable 1 or 2.

I will now create these functions from the information I gathered in Ida Pro:

The Main Method

We can now return back and construct the main function with what we know from the information we gathered from the classes. The names of functions that are decompiled are usually mangled. After a bit of a tidy up makes it a bit more understandable.

At the start of main, we see memory allocation is taking place, two objects are created and passed to two functions. The address of those objects are used in a function pointer, here is an example of a function pointer:

typedef int func(void); //create function
func* f =(func*))0xabcd1234; //get the function address
f(); //call function

Conclusion

Understanding object-oriented programming and how it works is the first step in reconstructing Classes, Inheritance and Virtual functions. Using tools such as IDA PRO and Snowman Decompiler helps reconstructing code and making it a lot easier to understand.