Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
RetDec: open-source machine-code decompiler based on LLVM (retdec.com)
58 points by ingve on Feb 5, 2019 | hide | past | favorite | 16 comments


Can this be used practically to recompile a binary from one platform (e.g. Intel) to another (e.g. ARM)? It would be interesting to compare the performance with an emulator like QEMU.


If your goal is to move across different ISAs, then dynamic binary translation is always going to be better than static translation. The problem you're going to run into is that any imprecision in the static analysis is going to explode into problems.

If the two architectures have differently-sized pointers, you are clearly screwed before you start. Any value that contains a pointer now has to have its size adjusted, so if you misidentify a pointer as an integer (or vice versa), problems abound. Compilers have a hard time with that, and they get to have the programmer literally tell them what things are pointers.


QEMU can use dynamic binary translation.


I have been thinking about this for a while now - on the one had, as somebody who has never tried anything like this and has no intention of ever doing so, it sounds like a really good idea. On the other hand, if it was such a good idea, why aren't people doing that already instead of paying the performance penalty for emulation over and over?


There are a few billion reasons why it doesn't work. Indirect calls and jumps are usually the most common one because they can only be resolved while the program is running. Then there is self modifying code, most commonly because the executable was packed with UPX or equivalent. Then there is the fact that contrary to popular opinion emulators aren't forbidden from using JIT compilers which cache commonly executed code. The JIT may take some time to run but it's a negligible portion of total CPU time.

Then there is the problem that the userbase for running emulated software just doesn't exist or is incredibly small. People and businesses are completely fine with running x86 only software on x86 hardware. The effort spent on building a super advanced emulator should instead be spent on making the new platform easier to develop for and ensuring more software is supported natively.


> Indirect calls and jumps are usually the most common one because they can only be resolved while the program is running.

and

> emulators aren't forbidden from using JIT compilers

work together also in reverse: decompilers are not forbidden from running the code being analyzed, and a re-compiler could use a JIT in order to work around some more dynamic issues.


Thank you for the explanation!


This is neat. I recall not long ago seeing a presentation on rev.ng [1] [2], which has some similarity to RetDec.

[1] https://rev.ng/

[2] http://llvm.org/devmtg/2016-11/Slides/DiFederico-rev.ng.pdf


I am coming to realize that ARMv5 and earlier are “dying” in the many projects are slowly removing support for them (e.g. node.js), or weren’t initially supported and the line in the sand is drawn at ARMv6 or later (likely due to the popularity of the early raspberry pi’s), for example with clozure Common Lisp: https://github.com/Clozure/ccl/issues/190#issuecomment-46068...

Perhaps I can use something like this to port the ARMv6 assembly backwards to ARMv5?


Been working on a few reverse engineering projects myself and it's a great refreshing experience when you can find a tool that outputs a good approximation of what the original code was doing, even if the approximation is terrible. Modern compilers seem to love to move around registers, use one-off instructions, pad everything, stick nops in everywhere, etc.

Also vtables are an extreme pain. What's function 0x10? Just gotta guess or try and inspect it at runtime.


> love to move around registers

Using -O2? I would imagine register moving is done in this case out of necessity due to either call conventions, syscall conventions, loop semantics, etc

> Pad everything/stick nops everywhere

Yes and I'm glad they do. Branching to a non 16-byte aligned address is much slower. Accessing misaligned data is slower too.


For vtables, generally you can follow the object up the call chain until you find its constructor/initializer. Then you see the actual vtable and define it as a struct; now you have method names.


So basically this is a capstone to llvm mapper allowing you to use llvm tools. Nice I guess, too bad it is capstone though


Pretty cool stuff. On a somewhat related topic, is anyone aware of a tool for adding efficient instrumentation to X86-64 binary code (e.g. to add simple checks to every memory store/load)? I'm aware of e.g. BAP, but I'm not sure whether there are better alternatives.


The best dynamic instrumentation tool for x86 code is probably Intel's Pin tool (https://software.intel.com/en-us/articles/pin-a-dynamic-bina...).


One wonders if, given a proper abstraction, some closed source executables can be recompiled to WASM with an LLVM IR "lifter".




Consider applying for YC's Fall 2026 batch! Applications are open till July 27.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: