什么是扭曲加密变换呢?这是我开发的一款软件,可能官方的名词叫做“混淆加密”,我给自己的软件起名叫做扭曲加密变换技术。我断断续续用了一年多的时间开发这款软件,但是没做什么推广,这款软件直到现在不对外公开的。
 
    现在加密变换适用于VC6、VS2005、VS2008等这么几个平台,下面我给大家讲一下在这个软件的开发过程中的一些思考,以及我的一些解决方案。
 
一、加密软件现状
 
    当前常用的加密软件可以分为:
  • 加壳类,比如ASProtect;
  • 虚拟机类,比如VMProtect。
    对于加壳类,壳总是壳,它与它要保护的内容总是有明显的分界线。尽管现在的加壳软件总是尽可能地加强壳与核的联系,但壳总是能脱掉的。当初我开发了一款跟踪调制器,可以对付这一类的加壳软件,因为一般来说,加壳软件的壳在一个新的段里面,就是原来的PE程序有数据段、代码段,壳比较难以做到和原来的程序处在同一个段,通常会在新的段里面,这就是它的分界线。所以在调试一个加过壳的软件的时候,运行到从一个段到另外一个段的时候的跳转时就停下来,这个时候原来程序的入口点就找到了,这也是加壳软件的弱点,就是难以和原来的程序严丝无缝地合并在一起。
 
    那么当我们找到它的入口点之后,用一条命令DumpPE,把当前的内存映象存为一个文件。然后,我又加了一个命令MakePE,用这个命令,把这个映象重组一下,于是这个程序就脱壳了。当时在Win98时代,那个时候的壳也比较简单,我的TRW2000真的好用,三个命令就脱掉壳了。
 
    后来,加壳者发现这样不行。他们一般来说还会提供一些很难跟踪,很难调试的函数,推荐加壳者,推荐开发者,调用一下你的函数,我再用加壳,这样的程序就不能简单用以上的方法。不过能够调用的函数通常也是比较简单的。
 
    我们要破解一个软件的时候,我们首先第一步要做的通常是把一个软件脱壳,脱壳成了破解的第一步,也成了所有破解者的基本功。破解者说,谁不会脱壳啊?如果他不会脱壳的话,就没法搞破解。所以说脱壳成了破解的基本功,大家先要把壳脱了,然后分析它。
 
    但是如果我们要逆向一个程序,我们不是要破解它,我们想把这个程序整个的变成源文件,整个我要搞懂它,这个时候其实反倒简单了。怎么说呢,我根本不需要脱这个壳,我只需要把程序运行起来,把内存映象保存下来,就可以分析了。我根本不需要脱壳,至于你在程序中调用的加壳软件提供的API函数多半是不重要的,可以不管它。通常来说,加壳软件对于逆向是没有什么保护作用的。
 
    另外一个虚拟机类的加密,它需要用户选择一个或几个函数进行加密,它只能保护几个重点函数,不能保护你的整个软件不被逆向。它通常把几行代码,通过虚拟机膨胀之后,变成几百行,甚至是更高。所以呢,虚拟机类的加密软件,他们通常只能让你加密你代码中的几个函数,或者是函数中的一部分,会推荐你在编程序的时候,前面加一个标志,这段是用虚拟机加密的。这就决定了用虚拟机类加密,通常只能加密少量代码,而你的软件的绝大多数代码都会暴露的,这显然是不安全的。
 
    并且我们看VMProtect的说明书,它明确说明它是为了保护你的注册机制,它并不能保护你的软件设计思路。
 
    总之,现有的加密软件只能防破解,不能防逆向。
 
二、逆向的可怕
 
     根据经验,如果努力一点,一人一天可以逆1000行C++代码,我有多年的软件逆向的工作经验,经常干这种事情,并且我最近一段时间,还开了一个逆向的培训班,教学生学习一些逆向的知识。直到上个月,我还刚刚完成了一个六万行C++代码的工程。根据经验,如果努力一点,一个人一天可以逆1000行C++代码!也就是说你辛辛苦苦几年时间开发出来的软件,如果不加保护,可能会以每人每天1000行的速度被逆向全部代码,这是多么可怕的一件事情。尤其是驱动。我们知道,驱动是最富技术含量的,驱动开发是最难的,能够做驱动开发的人,都是顶尖高手,都是薪水很高的人。而恰恰驱动呢,却是软件保护中一个问题最严重的地方。我们可以看到,我们的系统里面的那些驱动程序,个个很短小。就是说我们可能花费了很大的精力,很长的时间开发出来一个驱动,包括了我们软件的所有核心技术,但是它可能只有几十KB。被一个有经验的逆向者,可能几天时间逆向出全部源码。
 
    这个也不妨告诉大家,我最近在做的软件,叫WinMount。这个软件的思想是合并了WinRAR和Daemon Tools两个软件的功能,就是我可以把一个压缩包展开,也可以把一个虚拟光驱文件展开,这样一下子把两款电脑的必备软件合并在一起了。我又增加了自己的思想,你有一个包,我把这个包直接虚拟成不存在的一个盘,把它放到虚拟的盘里去,这是我的思想。所以我现在正在做的这个软件,就是即时解压的这么一个思想,这是我现在主要搞的软件。
 
    我要给大家说什么呢,即使是一个优秀的程序员,有一个想法,就这么凭空能把程序编出来吗?很困难的。一般我们都要参考一下别的软件,参考一下它们的思路。我当时有这个想法,有这个思想做这个软件做WinMount,又参考了一个类似的软件才做出来的。当然,那个软件的功能和这个软件的功能是完全不相同的,那个软件有一个子功能,可以虚拟出一个盘出来,我一看这个软件不错,我要把这个功能发扬光大,做成当时心目中的工程,于是我把那个软件逆向了一下,把里面所需要的内容拿出来了。
 
    所以说被破解不可怕,可怕的是被逆向。如果你的软件被逆向了,就会冒出多个与你的软件功能相同的软件,你所有的技术就都不存在了。
 
三、加密产品如何切入?
 
    如果我们要开发一款加密产品,怎么做?
 
    刚才我们把传统的加密软件都推翻了,我们说加壳的也不行,虚拟机的也不行,我们首先要考虑第一个问题,我们要用什么作为我们加密的输入。比方说我们可以考虑,如果我用C++源码作为输入,搞得很难懂怎么样?这个辛苦点,因为你源码搞得再混乱,编译器会优化的,所以这一步是行不通的。所以说呢,多数程序就选择了用最终的执行文件EXE作为输入,现在的加壳软件和虚拟机都用了这个方法,我很通俗的把他们所用的方法,加壳的软件叫做包粽子,EXE已经存在在那里了,你想保护他,你包一层就可以了吗?虚拟机叫做挖窟窿。比如一个房子建好了,这个房子已经建好了,不是正在建,你感觉住着不牢靠,我把这两块砖敲下来,换成石头的,这个就是安全的吗?所以我们认为他们的方式都是不合适的。在实际分析当中,也是有问题的。比如说函数占用的空间是2KB,通常虚拟机类软件,把这2KB,填一些随机代码,这个函数的前面一个函数他不敢动,后面一个函数他也不敢动,这就是一个窟窿,一个优秀的分析者,他肯定能识别出这个窟窿,然后我还没分析这个函数,已经知道这个函数有多大了,在加密的战争中你已经失败了。
    分析了以上两种可能,我们感觉它那种方法不好,所以我想出来一个方法,就是用编译中间文件OBJ作为加密的输入。我后来没有了解,是不是到目前为止,只有我一款软件用这个方法的,反正我是自己独立想出来的,我感觉这个方法很好。优点是什么?就是我加密的代码是无缝连接到工程中的。再一个就是我们分析OBJ的格式,比起C++的源码会简单得多。属于我的OBJ文件中有一个符号,这个OBJ会告诉我这儿有一个符号。所以我认为反汇编OBJ比反汇编EXE是安全的。
 
 
    本文主要内容整理自著名程序员刘涛涛先生在 2008中国软件安全峰会上的演讲,欢迎 下载本文资料