CRC(CyclicRedundancyCheck,直译:循环冗余校验)技术是一项很成熟的技术,在众多领域有广泛的应用,在数据存储和通信传输应用中处处都可以看到它的身影。最常用的CRC校验形式有CRC-16,CRC-32两种形式,采用CRC-16校验,可以保证在1014 位码元中只含有一位未被检测出的错误,采用CRC-32校验的出错概率比CRC-16还低105 倍。CRC的主要特点就是:检错能力极强,开销很小,易于实现。从性能和开销上综合考虑,其远远优于奇偶校验及算术和校验等方式。因此,很多软件在加密保护时都将CRC技术应用其中。本文拟从CRC校验的原理解剖入手,用实际代码和应用给大家解析CRC校验在软件加密中的实际应用,希望能给您的软件加密保护提供一些帮助和建议。
CRC 校验的原理解析
在实际应用中,根据环境和需求的变化,CRC形成了多种变形方式。比如:通讯协议X.25的帧检错序列采用的是CRC-CCITT方式,ARJ、LHA、ZIP等压缩软件采用的是CRC-32方式,磁盘驱动器的读写采用的是CRC-16方式,GIF、TIFF等图像存储格式也使用CRC作为检错技术。
目前,比较流行的CRC形式主要是:CRC-16(CRC-CCITT)、CRC-32两种,CRC-4、CRC-8、CRC-12等形式的应用比较少见。其实,虽然有这么多种变形方式,但其原理是完全相同的,只是在实现上有一点变化而已,下面我们就对其原理进行一番解剖,希求通透。
CRC算法本质是(模-2)除法的余数运算,使用的除数不同,CRC的类型也就不一样。怎么样,不好理解吧?没关系,我们继续讲解:CRC的算法其实是采用了多项式编码的方法,您可以将要被处理的数据块M看成一个n阶的二进制多项式,其形式如下:
a 是对应的阶数(位数)的值;
x是对应的“模(进制)”数,由于我们处理的都是二进制数,所以x就是2 了。(模-2)的意思现在您明白了吧?
下面我们用一个数进行解释吧:
有一个二进制数M=10010101,其对应的多项式就可以表示为:
CRC校验就是基于这种多项式进行的运算,其乘除法运算过程与普通代数多项式的乘除法相同,其加减法运算以2为模,加减时不进(借)位,实际上与逻辑异或(XOR)运算是一致的。
通常,根据多项表达(运算)式的不同,就形成了不同的CRC形式,以下是各种常用的多项表达(运算)式:
这些多项表达式的值就是(模-2)除法的除数,只要能确定使用哪一种多项式(也就是对应除数),您就可以很简单的获取CRC检验码了。下面就给您介绍CRC检验码的计算过程(看起来麻烦,其实简单):
1、先确定您要使用的CRC校验形式,以此确定对应除数(用G来表示)和选定阶数(用r来表示)。(如果选择CRC-4的话,r就等于4,选择CRC-16话,r就等于16,以此类推。)
2、在待处理的数据块M'后附加上r个0。假设原始数据块的长度是m位的话,附加之后的长度就变成m+r位了,我们用M来代表附加后的值。
3、用第一步选择的生成多项式的值(即对应除数G)来除第二步附加0后生成的值(M),循环计算,一直到余数的阶数小于等于r-1,这时所得到的余数(用Y表示)就是原始数据M'经过所选择的CRC校验形式所生成的CRC校验码。
●如果您想将生成的校验码与原始数据进行复合,只需要用第二步生成的(M)以模2的方法减去得到的CRC校验码(Y),所得到的值就是包含了CRC校验码的数据串M''。(不过在
软件加密过程中可能用不到这一步)。
怎么样,很简单吧,只需要三步,就可以得到CRC 的校验码。还不明白?举个例子吧:
设原始数据M'=1100110100
选择CRC-4的形式,则G=24+2+1=19=10011(二进制)
r =G 的二进制位数减1=5-1=4
对原始数据M'进行处理,在其尾部附加r个0,即:
M=M'+0000=11001101000000
再用G 循环除M:
其实校验码生成的过程就是一个循环移位的运算,位与位之间就是异或(XOR)运算。
◆一个数据的校验过程是这样的,如果有大量数据(比如说一个可执行程序或一个压缩包)将如何进行校验呢?其实很简单,只要将一个文件看成一个被一些数字分割的很长的位字串就可以了,只是这个位字串比较TA而已,你只要按标准的方式对这个比较长的位字串进行(模-2)除法运算,就一定会得到一个余数---CRC校验码,而这个校验码就是这个文件的CRC校验值。
CRC 校验的代码实现
好了,理论上的准备是很多了,现在要用进入实践了。下面,我们将给您提供一段很简单而实用的代码,用来实现CRC-32校验,最终,我会用这段代码实现软件加密保护。
大家可以看到,上面生成CRC校验码的过程中,使用了大量的位运算和逻辑操作。而我想告诉大家的是,基于位运算的算法是非常慢的而且效率很低。因此,在实际使用中不推荐使用“计算法”来生成CRC校验码,而建议使用“查表法”来进行CRC校验码计算。查表法又是什么方法呢?这里我不做过多的分析,简单的说,它是利用预先计算出的标准码表(对应不同的校验形式有不同的码表,见附表1、2),用简单的移位和XOR操作,快速计算出CRC校验码的方法。具体的算法就是:
(1)将上次计算出的CRC校验码右移一个字节;
(2)将移出的这个字节与新的要校验的字节进行XOR 运算;
(3)用运算出的值在预先生成码表中进行索引,获取对应的值(称为余式);
(4)用获取的值与第(1)步右移后的值进行XOR 运算;
(5)如果要校验的数据已经处理完,则第(4)步的结果就是最终的CRC校验码。如果还有数据要进行处理,则再转到第(1)步运行。
看上面的过程是十分简单的,不好理解的可能是“预先生成的码表”。其实这个码表就是2^8 的数组,为什么是8次方呢?因为我们是用字节来进行运算的,而一个字节是8位,所以就是2的8次方了。因此这个码表就是拥有256值的数组,对应的每个值实际上就是0-255以对应的CRC多项表达式(见原理分析)为权的CRC码。如CRC-16的多项表达式就是,CRC-32的多项表达式就是:
CRC 校验在软件加密保护中的攻与防
上面用大篇幅介绍CRC的原理与实现,都是为现在的实战打基础,现在我们就要用实战来校验了。
大家已经知道,CRC校验生成的结果只是一个Long型的整数,市面上一些软件是如何将这个整数应用在软件加密保护中呢?这里我给大家介绍两种常用的方式:
1、是对程序自身的进行保护。首先对原始可执行程序进行CRC校验,同时保存校验结果(可以保存在注册表、配置文件或可执行程序本身)。在程序运行时,对程序自身进行CRC校验,并将运算出的结果与保存的原始结果进行比较,如果不相同,就说明程序已经被修改(最有可能是被破解或被病毒感染)。即使只有1Bit的修改,都会被CRC检查出来,所以用CRC做自校验相当有效。
2、用CRC校验算法,对注册名和注册码进行变形运算和判断,以此做为注册保护和授权的手段。
这两种方式在软件保护上的运用十分广泛。可以说,每一种软件加壳(加密)保护软件(如upx,Aspack,FSG等)都使用了CRC进行自身校验保护。
为了证明CRC在软件加密保护上的效果,我制作了一套测试用例,大家可以在http://www.xxx.com上下载CRCTest.rar压缩包,按本文进行测试和分析。
压缩包中有两个可执行程序:crctest.exe和Makecrc.exe。其中crctest.exe就是我们要进行分析的对象,界面如下:
软件已经进行了CRC外壳校验保护,同时,使用CRC-32算法做注册码校验,可以说将CRC在软件加密保护上的应用全部发挥出来了。
MakeCrc.exe是配套工具,用来给上面的程序注入CRC保护码和计算注册码。
现在,可以打开crctest.exe 文件,并随意输入注册名和注册码,看一看!
您也可以用16进制编辑器(如:Hiew,010Editor,RTA等),将crctest.exe的最后一个字节00修改成0F保存修改后,再运行程序,程序会提示被修改。
怎么样,这就是CRC保护的效果。如果您试图强行暴破来完成注册的话,就必须修改原始文件,但是软件将会在自校验时发现自己被修改了,然后自动退出。除非您得到正确的注册码或注册算法,而软件使用的注册算法也是由CRC算法变形实现的。如果在不知道具体算法的情况,想要强行暴破是比较麻烦的,这就是CRC的威力。市面上大多数软件大多是这样做的,毕竟谁也不想自己的软件被人破解或修改,难道您不这么认为吗?