Snowman: native code to C/C++ decompiler
derevenets.com
derevenets.com
[1] http://rada.re
[2] https://radare.gitbooks.io/radare2book/content/disassembling...
The radeco project is a train wreck. The current state of radeco-lib (unless it's been remediated in the last month) is disappointing and the only reason it compiles is because the last SoC student appears to have commented out the bindings that radeco is meant to use to get radeco-lib to do anything. I actually spent an evening attempting to undo that absurd series of commits but after getting a lot of the commented out back in place, not being a Rust programmer, hit roadblocks I did not understand regarding types and traits.
Unsolicited advice incoming. Please keep a close eye on your RSoC students this year. Their goals to achieve anything which they can present do not necessarily grok with the ongoing health of your project. I'd also love it if you would drop Rust and work with a more accessible language, at least while you work toward an initial version which spits out something resembling C code. Ultimately it's your project so do whatever you want but IMHO making everyone understand an inherently complex project in a language which is not straightforward is not the best option. Or at least add some documentation and make your lib and program build together...
I tested the IDA plugin and it happily gave me very long lines like this:
esp74 = reinterpret_cast<void*>(reinterpret_cast<int32_t>(__zero_stack_offset()) - 0x104 - 4 - 4 - 4 - 4 - 4 + 4 - 4 + 4 - 4 + 4 - 4 + 4 - 4 + 4 - 4 + 4 - 4 + 4 - 4 + 4 - 4 + 4 - 4 + 4 - 4 + 4 - 4 + 4 - 4 + 4 - 4 + 4 - 4 + 4 - 4 - 4 + 4 - 4 - 4 + 4 - 4 - 4 + 4 - 4 - 4 + 4 + 20);
Edit:Furthermore there seem to be some correctness issues, or at least misleading output.
If a string is modified at runtime (for example for obfuscation purposes) then passed as an argument, Snowman will show the original string directly like foo("incorrect", 23), instead of just using an opaque variable like foo(some_var, 23)
I quite like the authors' blog about the development of the decompiler, as it gives a lot of insight into how it works and what academic literature it draws on.
You can also find a video of a talk the author (Felix Cloutier) gave at the Security Open Source workshop:
https://net.cs.uni-bonn.de/fileadmin/ag/martini/Staff/yakdan...
Sadly, DREAM++ has never been released open source :(
Unfortunately for me I'm stuck with Hopper as Snowman is windows only.
Would be cool if it could even guess variable names from patterns it has seen before, like x,y,z for vector structs.
assembly -> RNN -> C
Would be asking for a bit much IMO. If you develop something like snowman that outputs many possible equivalent C ASTs and train something that tries to choose the one that was the original code.
Thus, I naturally tried this one on itself, but that didn't work so well --- it spent several minutes analysing, then crashed.
Then I picked something slightly easier, upon which it did manage to decompile successfully, but the output is... not exactly what I expected. Copious void pointers of various levels of indirection (plenty of "three-star-programmer" code...) and reinterpret_cast sprinkled everywhere --- I have the original code and it was written in C, so it amusingly enough decided to automatically convert it to C++, along with the inability to recognise accesses to local variables leading to long sequences of -4-4-4-4+4-4-4+..., mean that for me it's not really all that better than reading the Asm directly.
The latter test was with a binary compiled with a very old compiler, so I suspect something with the newest optimising compilers will produce even more confounding output.
That said, it's great to see plenty of decompilers being written and released publicly; I remember around 2 decades ago when any mention of decompilation would be met with disdain and chants of "that's impossible!" Hex-Rays and IDA may have spurred a lot of this development; but speaking from experience, cracking groups have always written their own private decompiler-ish tools, mainly featuring dataflow analysis.
https://github.com/radare/radare2-extras/tree/master/r2snowm...
r2pm -i r2snow
Of course, debuggers like x64dbg fit a niche for when you need to do a lot of dynamic work, like dumping data or unpacking an executable, they're not static analysis tools like IDA or Binja, which you'll probably want if you're analyzing algorithms and trying to understand the inner workings of something.
EDIT: I have a [dead] reply saying everyone moved to Immunity that I'd like to respond to. There's some truth to that in some communities, but the catch there is that Immunity never got good x64 support either. To my knowledge, it's basically just an Olly fork with some additional scripting features and stuff, doesn't solve the 64-bit problem or the 32-bit on 64-bit OSes problem.
> x64dbg is licensed under GPLv3, which means you can freely distribute and/or modify the source of x64dbg, as long as you share your changes with us.
Should probably read: "... as long as you make genuine offer of providing the source code and changes to those you distribute your version of x64dbg to."
In practice it of course makes sense to upstream changes, but there's nothing in the gpl about that.
Anyway, I guess I would have reworded it somewhat, to make it more obvious that the source is under GPL, but that the project welcomes and encourages upstreaming changes. This opposed to the code being under a modified GPL.
I like the x64dbg UI a lot more, I loved the persistent breakpoints and it was just very easy to pick up and work with. I found one shortcoming: it doesn't have an inline memory viewer - but it can export a memory section to a file.
So, a decompiler is cool and all, but...a five-line "Hello World" program turned into a 144-line decompiled program. Is that an accomplishment? I'm pretty sure the "reconstructed" C from that is longer than the assembly.
EDIT: Just to confirm, this is what I got when I put the Hello World code into "hello.c" and ran GCC against it:
gcc -O2 -S -c hello.c
hello.s: .file "hello.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "Hello, World!"
.text
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB11:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $.LC0, %edi
call puts
xorl %eax, %eax
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE11:
.size main, .-main
.ident "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-18)"
.section .note.GNU-stack,"",@progbits int64_t puts = 0x4003e6;
void func_4003e0(int64_t rdi) {
goto puts;
}
int64_t main() {
func_4003e0("Hello, World!");
return 0;
}Yeah, as you've discovered, there's a lot of "magic" going on behind the scenes to establish the standard C runtime environment that executes your main() function.
Here's a great writeup that illustrates the, uh, extensive amount of work that happens after spawning a new process but before main() is called:
http://dbp-consulting.com/tutorials/debugging/linuxProgramSt...
There is going to be an event on this Thursday (July 27, 2017) where the author of this tool will be talking about decompilation.
int64_t puts = 0x4003e6;
void func_4003e0(int64_t rdi) { goto puts; }
What is this? Is there some compiler that will actually accept this use of goto? Is it just a convention meant for human consumption to translate jump instructions with no translated target? Is it a bug in the decompiler?
For example, "mov eax, 0x0040137C"
Is is this an address or a numeric constant?
Should it be translated to:
1) var = 4199292;
2) var = &SomeGlobalVariable;
If you're lucky you might get a non-ambiguous answer from the relocation table embedded in your executable.
So you're probably better off writing a new backend for the Go compiler (a backend generating machine code, or C code).
The resulting program will have, by far, a lot less dangerous approximations.
Let's use a more concrete example. Let's say we write a Go program that copies a file. On Windows, this might use an API call like CopyFile:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa3...
If you decompile the compiled Go program into C, it'd still have the references to API calls like this. These APIs would have to be implemented on the new OS for the decompiled program to work without modification.