RT
文件Fuzz教程第二篇
文件 Fuzz 教程之二:Peach 语法实战
Author:dragonltx
经过教程一的介绍,大家已经对 Peach 语法有了大致的了解,本篇文章将用那些语法进行实战。
实例一
typedef union {
uint32 ctype <format=hex>; // Chunk Type
char cname[4]; // character representation
} CTYPE ;
typedef struct {
uint32 length; // Number of data bytes (not including length,type, or crc)
CTYPE type; // Type of chunk
ubyte data[length]; // Data (or not present)
uint32 crc <format=hex>; // CRC type and data (not including length or crc)
} CHUNK ;
上述结构的数据模型如下:
<Block name = "Chunk" minOccurs = "1" maxOccurs = "1024">
<Number name = "Length" size = "32" endian="big" signed = "false">
<Relation type = "size" of = "Data" />
</Number>
<Block name = "TypeAndData">
<Blob name = "Type" length = "4" mutable="false"/>
<Blob name = "cname" length="4"/>
</Block>
<Blob name = "Data" />
<Number name = "CRC" size = "32">
<Fixup class = "checksums.Crc32Fixup">
<Param name = "ref" value = "TypeAndData" />
</Fixup>
</Number>
</Block>
详解
CHUNK:该结构可以用 Block 来表示,Block 包含 3 个属性,name 的值是“Chunk”,minOccurs 的值为“1”,表示至少出现 1 次,maxOccurs 的值为“1024”,表示最多出现1024 次。
length:该值可以用 Number 来表示,Number 包含 3 个属性,size 的值是“32”,表示是 uint32 类型,endian 的值是“big”,表示大端序,signed 的值是“false”,表示无符号。
type:该结构也用 Block 来表示,其中 ctype 用 Blob 类型,大小是 4 字节,不可变异。Cname 也是用 Blob 类型,大小是 4 字节。
data:这边 data 用 Blob 类型,data 的大小在“Length”中指定,通过 size 这个 Relation
来指定,<Relation type="size" of="Data"/>,即 data 的大小是 Length 字节。
crc:crc 的值通过 Fixup 这个类来计算
总结:这个例子主要展示了 Block、Number、Relation、Fixup 的用法。
实例二
typedef struct
{
char id[4];
uint32 datalen;
if (datalen % 2)
char data[datalen+1];
else
char data[datalen];
} strfHEADER;
上述结构的数据模型如下:
<DataModel name="StrfHeader">
<Blob name="StreamFormatFourCC" value="strf" length="4" token="true" mutable="false"/>
<Number name="cbFileSize" size="32" endian="little" signed="false"/>
<Block name = "IsOdd" minOccurs="0" maxOccurs="1">
<Relation type="when" when="(int(self.find('cbFileSize').getInternalValue())%2) == 1"/>
<Blob lengthType="calc" length="int(self.find('cbFileSize').getInternalValue())+1" />
</Block>
<Block name = "IsEven" minOccurs="0" maxOccurs="1">
<Relation type="when" when="(int(self.find('cbFileSize').getInternalValue())%2) == 0"/>
<Blob lengthType="calc" length="int(self.find('cbFileSize').getInternalValue())" />
</Block>
</DataModel>
详解
id:用 Blob 来表示,value 的值为“strf”,长度为 4,token 的值为“true”,用来作为这个数据模型的特征。
datalen:用 Number 表示,大小为 32 位,即 uint32,小端,无符号。
datalen 为奇数时:用 Block 来表示这个块,minOccurs 为 0 表示可能不出现,maxOccurs
为 1 表示最多出现一次。用到了 when 这个 Relation,这个 Block 成立的条件是
when="(int(self.find('cbFileSize').getInternalValue())%2) == 1"。data 用 Blob 表示, lengthType 的值为“calc”,表示 Blob 的大小要通过计算得到,length 的值为“int(self.find('cbFileSize').getInternalValue())+1”,表示 Blob 的大小是这样计算得来。
dalalen 为偶数时:情况与奇数时类似。
总结:这个例子主要展示了 when 这个 Relation 和 Blob 的用法。
实例三
while ( !FEof())
{
ReadBytes( tag, FTell(), 4 );
tag[4] = 0;
count++;
if ( header.object_version==0)
if ( count >header.num_headers)
break;
switch ( tag)
{
case "DATA":
DATA_CHUNKS data_chunk;
break;
case "PROP":
PROP_CHUNK prop_chunk;
break;
case "MDPR":
MDPR_CHUNK mdpr_chunk;
break;
case "CONT":
CONT_CHUNK cont_chunk;
break;
case "INDX":
INDX_CHUNKS indx_chunk;
break;
default:
DEFAULT_CHUNK d_chunk;
break;
}
}
上述结构的数据模型如下:
<DataModel name = "Rm">
<Block ref="RmHeader"/>
<Choice maxOccurs="100">
<Block ref="data_chunks"/>
<Block ref="mdpr_chunk"/>
<Block ref="indx_chunks"/>
<Block ref="prop_chunk"/>
<Block ref="cont_chunk"/>
<Block ref="default_chunk"/>
</Choice>
</DataModel>
详解
用 Choice 来表示 switch,Choice 的属性为 maxOccurs,值为“100”,表示最多出现 100次,每一个的选择都会从“data_chunks”“mdpr_chunk”“indx_chunks”“prop_chunk”“cont_chunk”“default_chunk”选择一个 Block,具体是选择哪一个,根据每个 Block的标志进行选择。
总结:这个例子主要展示了 Choice 的用法。
实例四
struct IMAGEDESCRIPTOR_PACKEDFIELDS {
UBYTE LocalColorTableFlag : 1;
UBYTE InterlaceFlag : 1;
UBYTE SortFlag : 1;
UBYTE Reserved : 2;
UBYTE SizeOfLocalColorTable : 3;
} PackedFields;
上述结构的数据模型如下:
<Flags name="PackedFields" size="8">
<Flag name="LocalColorTableFlag" position="7" size="1"/>
<Flag name="InterlaceFlag" position="6" size="1"/>
<Flag name="SortFlag" position="5" size="1"/>
<Flag name="Reserved" position="3" size="2"/>
<Flag name="SizeOfLocalColorTable" position="0" size="3"/>
</Flags>
详解
PackedFields:用 Flags 表示,name 的值为“PackedFields”,size 的值为“8”,表示大小为 8 位,即 1 字节。
LocalColorTableFlag:用 Flag 表示,name 的值为“LocalColorTableFlag”,position 的值为 7,即第 7 位,size 的值为“1”,表示大小为 1 位。其他 Flag 类似。
总结:这个例子展示了 Flags/Flag 的用法。
实例五
typedef struct
{
uint32 nDataSize;
char strDataType[4];
char strVersion;
char flags[3];
char data[nDataSize-12];
} DATA_REFERENCE;
typedef struct
{
uint32 nBoxlen;
char strType[4];
char strVersion;
char flags[3];
uint32 entrycount;
DATA_REFERENCE dr[entrycount];
} DREF;
上述结构的数据模型如下:
<DataModel name="dref">
<Number name="nBoxlen" size="32" endian="big" signed="false"/>
<Blob name="strType" length="4" valueType="hex" value="64726566" token="true" mutable="false"/>
<Blob name="strVersion" length="1"/>
<Blob name="strFlags" length="3"/>
<Number name="entrycount" size="32" endian="big" signed="false">
<Relation type="count" of="data_reference"/>
</Number>
<Block name="data_reference" maxOccurs="1024">
<Number name="nBoxlen" size="32" endian="big" signed="false">
<Relation type="size" of="data" expressionGet="size-12" expressionSet="size+12"/>
</Number>
<Blob name="strType" length="4" mutable="false"/>
<Blob name="strVersion" length="1"/>
<Blob name="strFlags" length="3"/>
<Blob name="data"/>
</Block>
</DataModel>
详解
dr:dr 用 Block 来表示,name 的值为“data_reference”,maxOccurs 的值为“1024”,必须设定 maxOccurs 的值,否则在进行数据解析时,dr 的个数会被设置为 1。dr 的个数通过 entrycount 来指定,通过 count 这个 Relation 来联系起来,即<Relation type="count"of="data_reference"/>。
DATA_REFERENCE 中 的 data : 由 于 data 的 大 小 为 nDataSize-12 , 必 须 用 到expressionGet/expressionSet。通过这样设定 data 的大小,<Relation type="size" of="data"expressionGet="size-12" expressionSet="size+12"/>。
总结:这个例子展示了 count、size 这两个 Relation 的用法,以及expressionGet/expressionSet的用法。
实例六
switch (PacketLenType)
{
case 0:
break;
case 1:
BYTE PacketLen;
localPacketLen = PacketLen;
break;
case 2:
WORD PacketLen;
localPacketLen = PacketLen;
break;
case 3:
DWORD PacketLen;
localPacketLen = PacketLen;
break;
}
上述结构的数据模型如下:
<Choice name="PacketLengthTypeChooser">
<Block name="PacketLengthNONE">
<Blob name="PacketLength" length="0" constraint="self.find('LengthTypeFlags.PacketLengthType').getInternalValue() == 0">
</Blob>
</Block>
<Block name="PacketLengthBYTE">
<Number size="8" name="PacketLengthType" constraint="self.find('LengthTypeFlags.PacketLengthType').getInternalValue() == 1"/>
</Block>
<Block name="PacketLengthWORD">
<Number size="16" name="PacketLengthType" constraint="self.find('LengthTypeFlags.PacketLengthType').getInternalValue() == 2"/>
</Block>
<Block name="PacketLengthDWORD">
<Number size="32" name="PacketLengthType" constraint="self.find('LengthTypeFlags.PacketLengthType').getInternalValue() == 3"/>
</Block>
</Choice>
详解
constraint:通过 constraint 这个约束条件来完成 switch 的功能。当LengthTypeFlags.PacketLengthType 的值为 0 时,Blob 的大小为 0,当LengthTypeFlags.PacketLengthType 的值为 1 时,Blob 的大小为 8,即 BYTE,依此类推。
总结:这个例子展示了 constraint 的用法。
注:本帖由看雪论坛志愿者PEstone 重新将PDF整理排版,若和原文有出入,以原作者附件为准
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。
上传的附件: