2

Background: I want to convert Qt RTTI into symbols, to more easily navigate a large executable.

If you don't know already, Qt is a C++ application framework based on a message passing system. Since C++ has very little in the way of introspection and reflection, which are important features for an expressive message passing system, Qt comes with a tool called moc (Meta Object Compiler), which parses your source files and builds an index of classes, methods, properties etc. that need to be enumerated, resolved, etc. at runtime. Sadly, the metadata generated by moc is optimized for runtime access (in part because of limitations of the C++ language) and is slightly hostile to static analysis. In particular, you'd expect method tables like this (pseudocode):

methods = {
    "frob" -> &frob,
    "fuzz" -> &fuzz
}

but for several boring reasons, moc generates a dispatch method instead (pseudocode again):

dispatch(method, args) {
    switch(method) {
        case "frob": return frob(args)
        case "fuzz": return fuzz(args)
        default: return -1
    }
}

Needless to say, decompiling even simple, machine-generated code is much, much harder than analyzing static data.

Conceptually, it's simple: find all dispatch functions, and run each of them in a simulator until it performs a call or returns; extract the method implementation address from the call opcode, write to symbol/map file with the method name. I already have a quick hack to identify dispatch functions (a hacked QtCore4.dll that hooks all objects and dumps their metadata), but I don't know what to use to decompile them.

The question: what (free) tools would you recommend to do this programmatically? At a minimum, I'd need a PE loader and an x86 simulator, Python preferred.

I've been pointed to angr, which is impressive, and among other things translates code to a platform-independent IR, which increases the chances that I could actually release my code as a general purpose tool, but angr seems designed to do the complete opposite of what I need. Not only its documentation is sparse and impenetrable, but considering it's designed to derive the data from the code (and I already have the data!), it seems overengineered for my use case and would probably be unbearably slow even if I figured it out.

2 Answers 2

3

Wow, I actually figured out enough of angr to do it. Consider this C program (an extremely simplified scale model of qt_metacall):

#include <stdio.h>

int foo(void) {
    return puts("foo");
}

int bar(void) {
    return puts("bar");
}

int baz(void) {
    return puts("baz");
}

int frob(int n) {
    switch (n) {
    case 1:
        return foo();
    case 2:
        return bar();
    case 3:
        return baz();
    default:
        return -1;
    }
}

int main(int argc, char **argv) {
    return frob(argc) < 0;
}

We compile it and we use angr to determine the address of frob, like this:

import angr
b = angr.Project('a.out', load_options={'auto_load_libs':False})
b.analyses.CFG()

for addr in [f.addr for f in b.kb.functions.values() if f.name == 'frob']:
    print hex(addr)

(in my use case, my hacked QtCore4.dll will provide the list of qt_metacall methods to be disassembled)

Then this script, invoked as script.py [executable] [address of dispatcher function] [method index], will print the address of the method with the specified index:

import angr

def main(argv):
    executable=argv[1]
    dispatcher=int(argv[2], 0)
    method_index=int(argv[3], 0)

    # Load the executable
    b = angr.Project(executable, load_options={'auto_load_libs': False})

    # Prepare a call to the dispatcher function, with the method index as its argument
    state = b.factory.call_state(dispatcher, method_index)

    # Isn't there an easier way to make a closure in Python?!
    class CallAddr:
        value = None

        def on_exit(self, state):
            # When the code performs a call, we've found the method that corresponds to the index
            if state.inspect.exit_jumpkind == 'Ijk_Call':
                # Resolve the address of the exit target, that's our method
                self.value = state.se.any_int(state.inspect.exit_target)

    method_addr = CallAddr()

    # Install breakpoint to analyze "exits" (i.e. jumps)
    state.inspect.b('exit', action=method_addr.on_exit)

    # Step through the dispatcher function
    p = b.factory.path(state)
    p.step()

    # Keep running until either a conditional or a call
    while len(p.successors) == 1 and method_addr.value is None:
        p = p.successors[0]
        p.step()

    # No call was performed, method not found
    if method_addr.value is None:
        return 1

    print hex(method_addr.value)
    return 0

if __name__ == "__main__":
    import sys
    sys.exit(main(sys.argv))

Considering how powerful angr is (and how little of it I'm using), it feels like killing ants with a nuclear bomb, but it works

0

The article "Qt Internals & Reversing" by Daniel Pistelli describes how Qt works on low level and how to reconstruct the slots and methods from the metadata (statically). It's probably a little outdated in regards to Qt5 but should be a good starting point.

2
  • Also worths mentioning it has a complementary IDA script
    – NirIzr
    Oct 18, 2016 at 15:01
  • Sorry, I already read that article and it doesn't help me much. See that section about qt_metacall at the very end? qt_metacall is what I called "dispatch" in my pseudocode, and I don't want to analyze all qt_metacall methods by hand, especially considering that they're machine-generated and they have a very simple structure (if condition call method, else if condition call method, etc.) Oct 18, 2016 at 15:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.