为什么有些语言可以被反编译？而有的不能？
要理解这个问题，先要看「正」编译的过程是怎样的。 你有一个想法，这是一种人类自然语言可以表达出来的东西。你利用编程技能，把它「翻译」成你熟悉的一种编程语言: 这个过程叫做编程。 然后你使用编译器（compiler）将它翻译成机器所能理解的语言: 这个过程叫做编译。编程和编译都是「信息丢失」的过程。比如你说，我有一组整数，我要把这些数排个序，然后轻车熟路地写了个冒泡排序。然而一定程度上，你的原始动机其实已经从代码里丢失了——有经验的人可以一眼看出这段代码是在排序，而新手小明看到的只有一些 for 和 if 之类的东西。如果是更复杂的功能，可能过一段时间你自己都看不懂自己当时是想干什么。从程序语言到机器语言的过程其实也是一样的。这两个过程其实都是把「做什么」转换成「怎么做」的过程，转换完成之后，究竟一开始是要做什么，这个信息已经丢失了。 所谓「反编译」，其实就是找回这些丢失的信息的过程。从这个角度上来说，你阅读一段代码的过程，其实就是在将它「反编译」成自然语言。如果要完美地反编译，那只存在一种可能，就是信息完全没有丢失——比如说你阅读的这段代码有充分的注释，或者它使用了一种你所知晓的模式（这也是为什么大家一再强调注释和设计模式的重要性）。对于从机器语言到程序语言的反编译过程，也是一样。 比如说有比反编译更低级（非贬义）的过程，叫做反汇编: 严格来说汇编语言也是一种编程语言，不过我们在这里把它和我们常说的高级编程语言（包括C语言）区分开。 这个步骤里，我在汇编和机器语言里使用的是双向实线箭头，因为它们是可以互相转换的。从汇编语言到机器语言的过程中没有丢失任何信息——因为两者的指令是一一对应的，因此反汇编可以轻松达成。 这就是很多程序语言只能反汇编、不能（难以，下同）反编译的原因。一般我们管这种语言叫「编译语言」，又称「原生语言」。代表有C、C++等。 那为什么有的语言可以反编译呢？这又要从机器语言说起。就像不同地域的人所用的语言不同一样，不同的机器说的语言也不尽相同。用行话说，叫「指令集不同」。比方说，你的电脑和你的手机，指令集通常是不一样的。一段程序要让不同的机器都能执行，只能分别翻译（编译）成相应的机器语言。这个过程太麻烦了，于是人们想了个办法，搞出了一种叫解释语言的东西（此处未考证解释语言是否就是因此发明的，只是帮助理解）。如下图： 解释语言有两种执行方式，这取决于执行端的「解释器」是如何工作的。一种是直接解释执行，中间就没有机器语言什么事情了，但这种方式效率很低。因此现代的解释语言基本上都会采用第二种方式，也就是经由图中上部的路径，先通过JIT编译的方式翻译成机器语言，然后再执行，保证执行效率。JIT编译大致可以理解为「用到什么就编译什么」，这个过程常常是在执行过程中同步进行的。 「解释器」的英文interpreter，其实就是名词「翻译」的意思。这好比你国外交部发了封文件到各国大使馆，再由大使馆的工作人员分别翻译成相应的语言，传达给目标国相关部门。代表性的解释语言如Javascript，它要在不同机器的浏览器上都能正确执行，所以采用这种方式。 但是这样一来，程序代码就必须提供给每一台执行端机器了。这可是泄密啊。对于防止泄密，最直接的方式自然是加密。 有锁就有钥匙，同时也有开锁术；有加密解密，也有相应的破解方式。这时候所谓的「反编译」，其实就是破解加密算法。这一点就不展开聊了。 后来，人们觉得解释语言执行得实在有点慢，于是又想了一个办法：把一些可以前期做掉的工作先做掉，只留着那些跟目标机器有关的工作，到时候再说。于是程序被处理成了一种叫做「中间语言」，或者叫「字节码」的东西： 这个过程一般也叫做编译。中间语言词汇少，比较精炼，执行起来也更快。这些语言一般也会用上JIT技术，进一步把中间语言编译成机器语言（而非解释执行），执行效率也就跟那些原生的编译语言不相上下了。这种语言代表性的有C#、Java等。 程序语言可以编译成中间语言，反过来，中间语言也可以在一定程度上反编译成程序语言。这是因为采用这种编译方式的编程语言为了保证它们的高级特性（比如说反射），在编译的过程中保留了源程序的绝大部分信息，只有很少的信息丢失；也正是因为丢失了这一部分信息，中间语言通常不能完美地反编译——最常见的就是反编译出来的程序中局部变量的名字都丢了，被替换成了由反编译器自动生成的名字。但这样反编译出来的程序，结构和功能都是完备的，可读性也有一定的保障。一般来说，我们所说的可以反编译的程序都是指这样一类语言写就的程序。 中间语言可以被反编译；加密又会被破解，而且执行前还要解密，会带来额外的性能开销。有没有办法能让代码既能有效执行，又不被截获代码的人所利用呢?这时候人们从一些职业素养很差的程序员那里得到了启发。 实现一个相同的功能，可以有无数种形式的代码。你恪尽职守，认认真真地写注释，准确地命名函数和变量， 严格按照规范进行缩进和换行;小明却相反，完全没有注释，变量全部用abcd乃至故意误导别人（var mySon = laowang.Son），缩进换行邋遢，尤其是在大括号前不换行，让大家很不满。于是老板想，我们先把小明开除掉，然后给你发奖金并要求大家按照你的方式写代码，并且开发一个工具，唤作「混淆器」，在发布时再把代码处理成小明写的那种样子： 这样代码即使被反编译和解密了，别人看也看不懂，不小心还会被带到坑里去。代码毕竟是写给人看的，只是偶尔让机器跑一跑，所以没有可读性的代码是没有价值的。这种方法一出，广受好评，于是变成了一种非常普遍的做法。注意图中省略了中间代码和JIT的步骤，混淆通常会跟这些技术一起使用。