先从最简单的Choice数据模型开始看peach下的Choice到底是怎么执行的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<DataModel name="ChoiceSample"> <Choice name="Choice1" > <Block name="Type1"> <String value="[String in Type1]" /> </Block> <Block name="Type2"> <String value="[String in Type2]" /> </Block> <Block name="Type3"> <String value="[String in Type3]" /> </Block> <Block name="Type4"> <String value="[String in Type4]" /> </Block> <Block name="Type5"> <String value="[String in Type5]" /> </Block> </Choice> </DataModel> |
1 2 3 4 5 6 7 8 9 |
<StateModel name="State" initialState="State1" > <State name="State1" > <Action type="output" > <DataModel ref="ChoiceSample" /> </Action> </State> </StateModel> |
默认的情况下,直接引用Choice类型,peach运行总是选择Choice模块中第一个出现的数据,这里是Type1:
1 2 3 4 5 6 7 8 9 10 11 |
[*] Test 'Default' starting with random seed 37190. [R1,-,-] Performing iteration [String in Type1] [1,2,0:00:00.078] Performing iteration [String in Type1] [2,2,0:00:00.041] Performing iteration [String in Type1] [*] Test 'Default' finished. |
通过在Action中显式指定Choice的Block,就可以改变Choice的选择(DataModel不变,修改StataModel中的内容):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<StateModel name="State" initialState="State1" > <State name="State1" > <Action type="output" > <DataModel ref="ChoiceSample" /> <Data> <Field name="Choice1.Type1" value="" /> <Field name="Choice1.Type2" value="" /> <Field name="Choice1.Type3" value="" /> </Data> </Action> </State> </StateModel> |
再次运行,可以看到结果变为Type3了,这是因为peach取了最后一个数据,虽然示例中从Type1~Type3配置了三条:
1 2 3 4 5 6 7 8 9 10 11 |
[*] Test 'Default' starting with random seed 63908. [R1,-,-] Performing iteration [String in Type3] [1,2,0:00:00.08] Performing iteration [String in Type3] [2,2,0:00:00.043] Performing iteration [String in Type3] [*] Test 'Default' finished. |
通过上面的演示,Choice作为输出数据模型的时候,如何进行数据选取的基本方法应该就已经明了了。接下来再看看Choice的其他三个属性(minOccurs,maxOccurs,occurs)分别是如何工作的 :
minOccurs和maxOccurs可以理解为一个Choice模块中可以在一次迭代中同时选中的数据个数的下限和上限;
occurs的解释有些含糊,暂时无法确切定义,从行为上看和maxOccurs-最多可选取数据个数的行为一致。
看一个示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<DataModel name="ChoiceSample"> <Choice name="Choice1" minOccurs="2" maxOccurs="4" > <Block name="Type1"> <String value="[String in Type1]" /> </Block> <Block name="Type2"> <String value="[String in Type2]" /> </Block> <Block name="Type3"> <String value="[String in Type3]" /> </Block> <Block name="Type4"> <String value="[String in Type4]" /> </Block> <Block name="Type5"> <String value="[String in Type5]" /> </Block> </Choice> </DataModel> |
在Data中进行相关的数据配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<StateModel name="State" initialState="State1" > <State name="State1" > <Action type="output" > <DataModel ref="ChoiceSample" /> <Data> <Field name="Choice1[0].Type1" value="" /> <Field name="Choice1[1].Type2" value="" /> <Field name="Choice1[2].Type3" value="" /> <Field name="Choice1[3].Type4" value="" /> <Field name="Choice1[3].Type5" value="" /> </Data> </Action> </State> </StateModel> |
运行结果如下:
1 2 3 4 5 6 7 8 9 10 11 |
[*] Test 'Default' starting with random seed 20446. [R1,-,-] Performing iteration [String in Type1][String in Type2][String in Type3][String in Type5][String in Type1] [1,2,0:00:00.08] Performing iteration [String in Type1][String in Type2][String in Type3][String in Type5][String in Type1] [2,2,0:00:00.044] Performing iteration [String in Type1][String in Type2][String in Type3][String in Type5][String in Type1] [*] Test 'Default' finished. |
可以看到输出结果中有5个Choice中的数据,Type1,Type2,Type3,Type5,Type1(最后Type1是由于没有定义Filed数据,默认选择了Choice中的第一个数据;而且输出数据有5条,和理解中的4条有一些的差异)。这里唯一需要注意的就是类似数组的标记,设置了MinOccurs(MaxOccurs)的属性,就只能以这种方式定义Data。occurs的配置方式和上面类似,由于没有最新官方的文档可以参考,不再另外演示。
上面的方法在一定程度上可以满足随机选择的目的,但是pits测试套写完之后就无法再变化,因此如果需要每次运行可以随机的在Choice中选择一条数据,可以通过下面两种方法来实现:
1.通过-D方式在外部指定Field的名字,这样可以在启动peach的时候通过外部脚本随机指定这个值,例如
1 2 3 4 5 6 7 8 9 |
<Action type="output" > <DataModel ref="ChoiceSample" /> <Data> <Field name="Choice1.Type##tag1##" value="" /> </Data> </Action> |
1 2 3 4 5 6 7 8 |
<?xml version="1.0" encoding="utf-8"?> <PitDefines> <All> <String key="tag1" value="2" /> </All> </PitDefines> |
2.在Choice中的数据不需要执行变异的时候,可以指定Mutator为ChoiceSwitch(community版本好像没有实现这个变异算法,虽然可以配置,但运行时不生效),例如
1 2 3 4 5 6 7 8 9 10 11 12 |
<Test name="Default"> <StateModel ref="State"/> <Mutators mode="include"> <Mutator class="ChoiceSwitch" /> </Mutators> <Publisher class="Console" /> <Strategy class="Random"> </Strategy> </Test> |
最后,再看一下当Choice类型作为输入数据进行解析的时候,可以尝试的两种方式(本次未验证,暂时记录):
1.通过在Choice每一条数据的开始,设置一个token类型的数值,通过这条token类型的数据作为标记来crack输入数据,例如小白鸽的翻译文档中的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<DataModel name="ChoiceSample2"> <Choice name="Choice1" > <Block name="Type1"> <Number name="Str1" size="8" value="1" token="true" /> <Number size="32" /> </Block> <Block name="Type2"> <Number name="Str2" size="8" value="2" token="true" /> <Blob length="255" /> </Block> <Block name="Type3"> <Number name="Str3" size="8" value="3" token="true" /> <String length="8" /> </Block> </Choice> </DataModel> |
2.通过constraint约束进行匹配,参考(http://www.flinkd.org/fuzzing-with-peach-part-1/#b-file-data)的方法:
1 2 3 4 5 6 7 8 9 10 11 12 |
<Choice name="dd_chooser"> <Block name="dd_64"> <Number name="dd_CompSize64" size="64" endian="little" signed="false"/> <Number name="dd_DecompSize64" size="64" endian="little" signed="false" constraint="'4b50' not in hex(value)"/> </Block> <Block name="dd_32"> <Number name="dd_CompSize32" size="32" endian="little" signed="false"/> <Number name="dd_DecompSize32" size="32" endian="little" signed="false"/> </Block> </Choice> |