30 Years of Decompilation and the Unsolved Structuring Problem: Part 1
1–10 of 16 posts
Re: 30 Years of Decompilation and the Unsolved Structuring Problem: Part 1
#2[EDIT: Removed a comment about an apparent OCR issue, which has been fixed. Thanks for this great write-up!]
Re: 30 Years of Decompilation and the Unsolved Structuring Problem: Part 1
#3(Why? Just for fun, https://github.com/albertz/PyCParser, even more just-for-fun goal was this: https://github.com/albertz/PyCPython).
It literally would translate the C code in equivalent Python code, using ctypes heavily. It was mostly straight-forward, except for mapping goto (thus related to this control flow structuring problem).
Of course, there are some hacks to introduce goto in Python, which in many cases would operate on the Python bytecode, which actually has the JUMP_ABSOLUTE op, but there are also other ways (https://stackoverflow.com/questions/6959360/goto-in-python).
I could also have translated C directly to equivalent Python bytecode and not Python source code, but I really wanted to have Python source code.
My ugly solution worked basically like this: Whenever there was some goto in a function, it would translate it as follows:
First, we flatten any Python AST into a series of statements, with even more goto's added for while/for loops, if's, etc. (We can avoid doing this for all sub-ASTs where there are no no goto-labels. The goal is to have all goto-labels at the top-level, not inside a sub-AST.)
Only conditional goto's can stay. All Gotos and Goto-labels are marked somehow as special elements. So, we end up with sth like:
x()
y()
z()
w()
if v():
q()
Now, we can implement the goto-handling based on this flattened code:- Add a big endless loop around it. After the final statement, a break would leave the loop.
- Before the loop, we add the statement `goto = None`.
- The goto-labels will split the code into multiple part, where we add some `if goto is None:` before each part (excluding the goto-labels).
- For the goto-labels itself, we add this code:
if goto == : goto = None
- For every goto-statement, we add this code: goto = ; continue
See here: https://github.com/albertz/PyCParser/blob/master/goto.pyRe: 30 Years of Decompilation and the Unsolved Structuring Problem: Part 1
#4A funny anecdote: Some time ago, I was writing a C-to-Python translator. (Why? Just for fun, https://github.com/albertz/PyCParser , even more just-for-fun goal was this: https://github.com/albertz/PyCPython ). It literally would translate the C code in equivalent Python code, using ctypes heavily. It was mostly straight-forward, except for mapping goto (thus related to this control flow structuring problem). Of cours…
We even do this in the angr decompiler, found here: https://github.com/angr/angr/blob/8e48d001e18a913ecd4ed2e995...
Re: 30 Years of Decompilation and the Unsolved Structuring Problem: Part 1
#5This is super interesting, and I've definitely wondered how control flow "graph schemas" are applied in decompilation. [EDIT: Removed a comment about an apparent OCR issue, which has been fixed. Thanks for this great write-up!]
Re: 30 Years of Decompilation and the Unsolved Structuring Problem: Part 1
#6A funny anecdote: Some time ago, I was writing a C-to-Python translator. (Why? Just for fun, https://github.com/albertz/PyCParser , even more just-for-fun goal was this: https://github.com/albertz/PyCPython ). It literally would translate the C code in equivalent Python code, using ctypes heavily. It was mostly straight-forward, except for mapping goto (thus related to this control flow structuring problem). Of cours…
You may also be interested in the Relooper and Stackifier algorithms, which produce more efficient programs than a simple loop/switch.
Re: 30 Years of Decompilation and the Unsolved Structuring Problem: Part 1
#7Re: 30 Years of Decompilation and the Unsolved Structuring Problem: Part 1
#8Re: 30 Years of Decompilation and the Unsolved Structuring Problem: Part 1
#9I've wondered whether it would be possible to design a language with the explicit intent of being a decompilation target, such that you could guarantee that any program could be decompiled into it and then subsequently re-compiled with the original behavior preserved. Having such a language (perhaps a superset of C?) would make it way easier to perform binary patching.
Re: 30 Years of Decompilation and the Unsolved Structuring Problem: Part 1
#10I've wondered whether it would be possible to design a language with the explicit intent of being a decompilation target, such that you could guarantee that any program could be decompiled into it and then subsequently re-compiled with the original behavior preserved. Having such a language (perhaps a superset of C?) would make it way easier to perform binary patching.
There are tools like Remill (https://www.trailofbits.com/opensource/#binary) that disassemble to LLVM IR that can be fed back to the compiler to produce a new binary. You can actually target a different architecture, so it works for binary translation too.