Fuzz testing
看如下这段代码
2
3{
4
5 if(a>0&&a<100&& b==0 && c==255)
6
7 {
8
9 printf("trig a bug");
10
11 return 0;
12 }
13
14 return 1;
15}
16
这段代码的意思就是在参数 a,b,c所组成的参数空间中的 一个 特殊的 取值范围内即当0<a<100 ,b=0,c=255这个特殊 空间的时候会触发一个特殊的bug.当然实际的情况要比这种情况复杂的多。但是总会隐藏着类似的bug.
如何通过测试找到这些bug呢?这是一个问题,如何在一堆API的参数中找到这样的bug,这是一个大问题。嗯我们现在就讨论这个问题。
从我们便于理解的角度上看这个问题。其实我们希望我们的测试用例能够在一定概率的情况下在整个参数空间中触及到这个bug的触发参数区域。
最笨的办法就是枚举测试空间,这个实际上并不是一个可行的方法。参数空间会随着参数的个数增加产生参数空间爆炸。
那到底该怎么办呢?在有限的资源下最大可能的找到这样的有问题的参数样本,可行的办法就是一堆随机的参数来然后通过合适的组合来尽可能的覆盖整个参数空间。现在问题就是如何产生合适的随机数了。下面我们就讨论一下如何或者比较好的随机数和如何比较好的组合在一起。
随机数:
随机数在软件开发中应用很广泛,在通信,加密,游戏中都需要随机数发生器。那什么是随机数呢?
随机数至少应该具备两个条件:
1. 数字序列在统计上是随机的。
2. 不能通过已知序列来推算后面未知的序列。
只有实际物理过程才是真正随机的。而一般来说,计算机是很确定的,它很难得到真正的随机数。所以计算机利用设计好的一套算法,再由用户提供一个种子值,得出被称为“伪随机数”的数字序列,这就是我们平时所使用的随机数。
这种伪随机数字足以满足一般的应用,但它不适用于加密等领域,因为它具有弱点:
1. 伪随机数是周期性的,当它们足够多时,会重复数字序列。
2. 如果提供相同的算法和相同的种子值,将会得出完全一样的随机数序列。
3. 可以使用逆向工程,猜测算法与种子值,以便推算后面所有的随机数列。
即是说: 随机序列 = F(算法, 种子)
说到随机数的产生不得不提的是我们的随机数发生器往往是可以预测的。例如我们常用的随机rand 函数就是一个可以预测的。
int __cdecl rand (void )
{
return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff);
}
在这个的背后其实是用的是Knuth pseudo-random number-generating 技术。Knuth 在这本书中"Seminumerical Algorithms," Vol. 2 of The Art of Computer Programming (Addison-Wesley, 1981)发表了这个算法。在实际的应用中我们如何产生适合应用的随机数是根据实际情况定的。比如我们在输入参数的安全性方面没有任何先验知识的情况下,均匀分布是比较好的。在有先验知识或者是白盒测试的情况下正态分布可能是比较好的随机数分布。
这些分布的产生一般都是先产生一个平均分布然后求对应分布的逆。网上能找到一堆伪随机数生成器的代码。下面就随便给一个。如何产生一个更好的伪随机数,以后再说吧。
2{
3
4 int minInteger = (int)(min*10000);
5 int maxInteger = (int)(max*10000);
6 int randInteger = rand()*rand();
7 int diffInteger = maxInteger - minInteger;
8 int resultInteger = randInteger % diffInteger + minInteger;
9 return resultInteger/10000.0;
10}
11double Normal(double x,double miu,double sigma)
12{
13 return 1.0/sqrt(2*PI*sigma) * exp(-1*(x-miu)*(x-miu)/(2*sigma*sigma));
14}
15double NormalRandom(double miu,double sigma,double min,double max)
16{
17 double dResult;
18 double dScope;
19 double dNormal;
20 do
21 {
22 dResult = AverageRandom(min,max);
23 dScope = AverageRandom(0,Normal(miu, miu, sigma));
24 dNormal = Normal(dResult, miu, sigma);
25 }while( dScope > dNormal);
26 return dResult;
27
28}
29
产生了随机数以后,参数进行适当的组合对对应的API函数进行测试,这样就能在数学上保证尽可能得覆盖到对应得参数空间。最大可能的找到bug。
对于白盒测试来讲这种测试方法就更加适合,因为可以找一些比较合适的值作为初始值然后再产生随机的参数,就可以更有针对性的找到bug。
其实这是一种测试-FUZZ testing 的基本思想.