I am still in college for a Computer Security degree and took my first assembly language based class last semester. We touched upon the subject of reverse engineering and why it is an important part of fighting malware and ill-wished applications.

During my class we mainly used IDA pro, but also checked out some similar and free browser based applications.

In these applications, we were able to obtain so much information about the instructions and low level code that I was wondering why we even need a human to go over it and recreate the higher level languages (like writing a 'C' version of a piece of malware). 

Here my question:

Why can't a program use the information that is present in assembly code and turn it into a simplistic language automatically? 

I understand that it wouldn't look the exact same way it would when it was first written, but shouldn't it be possible to re-create it in a way that makes it easier to read and follow?

It's just something that I can't wrap my head around, thanks!

Short Answer

It's absolutely possible, but the accuracy and readability is a completely different matter. One clarification to be made: Reverse Engineering is not Decompiling.



Long Answer

Reverse Engineering is generally the process by which you take something (anything really) apart to see how it works.  Disassembling is when you take a binary formatted file and interpret the machine code into is assembly code.  Decompiling is interpreting the assembly code into a higher level language.

I believe your question is really, Why can't decompiling a program be automated?  Well it can be!

There are several different Java Decompilers.  Java byte-code is completely reversible due to its architecture independence.  What becomes tricky is decompiling a language like C.  Hex Rays does provide a C decompiler, but C is a complicated language.  There are 10 different ways to accomplish the same task.  What can be done in 20 lines, can be done in 3, or 10.  It's the interpretation of the language that makes the automation of decompiling C difficult.  

Sure you can decompile C to its most simplistic instructions.  Then you get lines like **(*var1) = 3; or (*bytecode)(param1) which can be a call to a function pointer.  What's worse is that you must remember that these are still just an interpretation.  I can't stress that enough.  What if the interpretation is wrong?  This is something you have to worry about at the disassembly level, but at least there are a reasonable amount of outcomes for 5-6 bytes for an instruction.  Now you have to interpret 15-20 bytes in order to figure out a function call or a for-loop.  If there are anti-reverse engineering techniques then it makes the interpretation even more difficult.

Context plays a huge role.  What's the difference between a function pointer, a char * pointer, and a uint32?  Absolutely nothing, except the context in which its used.  Compiler optimizations might use __fastcall rather than __stdcall.  Which means now you have to interpret where parameters to functions are going to be; either on the stack or in a register?  Inline functions, macro's, #defines will all become part of a larger subroutine.  There's no real way to interpret those types of contexts.
