r/haskell • u/darrint • Jul 16 '11
Reverse Engineering of Compiled Haskell
A client of mine is considering use of Haskell for some software that will be deployed in the field. One of his concerns (possibly a concern upstream from him) is that the "lower levels" of the code "block users from easily seeing how it works." By that I'm assuming they mean looking at byte code or disassembled machine code. Would Haskell's compiled output be any better or worse than C or C++ in this respect?
edit: Thanks all for the very helpful responses.
It sounds like a good summary of this topic is: GHC's output, stripped, is more difficult to reverse engineer than that of a similar program written in C or C++. That is due to the increased indirection, different idioms, and lack of interest and tools. Interest in reversing GHC's output could increase in the future and reversing could become easier.
Of course any useful code that can run on a CPU can be reverse engineered. This question was more about comparing the reversing effort to C and C++.
7
u/ezyang Jul 16 '11
It's different. GHC has its own calling convention, and uses a very different set of idioms than you would expect from a traditional library. I don't recommend looking at GHC-produced assembly unless you also have Core, STG and C-- at hand. Fortunately, these are pretty easy to produce during compilation.
5
Jul 16 '11
The rule is: If they have access to your binary, they will figure out what it does if they really want to.
3
u/drb226 Jul 16 '11
If they have access to your binary
In other words, don't distribute binaries; execute the code on your own servers if you are super worried about this. The only way to truly obfuscate your code is to make it so even the machine can't understand it; but that sort of defeats the purpose of programming.
1
u/f2u Jul 16 '11
You have to be a bit careful about identifiers ending up in the binary, or that the business logic ends up in tables which do not actually need disassembly. (That's relevant to C++, too.) GHC does not use the hardware stack, so a stock disassembler/decompiler will be very confused. That and the different evaluation model are not major obstacles, merely deterrents, but it's not as trivial as decompiling Java.
One thing that makes me wary of putting Haskell code in the field is the lack of crash dumps.
2
u/darrint Jul 16 '11
By lack of crash dumps do you mean the equivalent of a core file for a C program? That I could use that core file and gdb to diagnose a problem?
1
u/clockfort Jul 17 '11
I must admit I've never used the functionality, but the GHC man page does seem to make mention of core files' existence.
0
Jul 17 '11
2
u/f2u Jul 17 '11
The core file is just a bit difficult to interpret, even for bugs which do not involve memory corruption or race conditions. There aren't any useful debugging symbols, either. That's the flip side of confusing disassemblers.
2
u/MatrixFrog Jul 16 '11
I really think if you don't want people reverse-engineering your code, the solution should be legal, not technical.
1
0
Jul 16 '11
3
u/clockfort Jul 16 '11
Whoah, small world. Reversing binaries -- malware, in particular, is a pretty big part of my job too :-P And I love Haskell!
GHC moving to LLVM stuff aside, I think if I wanted to reverse GHC's normal platform-specific binaries, I would take a look at GHC's mangler perl script for those platforms it supports, and read up on the internal binary structures and calling syntax, to get a good delta from what is already well known (i.e. GCC-styled C binaries).
10
0
Jul 16 '11
6
Jul 16 '11
Sorry, but your assertions about what the compiler will do are wrong. GHC does not compute the result of a function at compile time (except for some type-level functions).
5
u/augustss Jul 16 '11
Well, it might compute a call at compile time if it decides to inline the function. Just like a C++ compiler might.
17
u/godofpumpkins Jul 16 '11 edited Jul 16 '11
GHC by default puts a crapload of (moderately human-readable) symbols into binaries, and stripping them will typically reduce the binary size (and reversibility) significantly. Once the symbols are gone, I think Haskell is mostly pretty reverser-proof right now because it looks like nothing most reversers are used to reading, and there's so much indirection for everything. People get frustrated with C++ because of the virtual function calls, and GHC's output has way more of those indirect function calls. Also, most tools that reversers use make assumptions about generated code (stack layouts, function preludes, etc.) that GHC doesn't follow.
I don't think it'd be impossible for an experienced reverser to figure out, but they might run away screaming before they get down to understanding it. Also, the intersection between the binary analysis community and the people who have heard of Haskell (and especially those who use it regularly) is tiny, sadly.