FuzzIL粗略分析
FuzzIL
FuzzIL是FUZZILLI使用的中间语言,FuzzIL由Lifter转换为语法正确的js代码
首先看看HowFuzzilliWorks里的一个FuzzIL的例子:
1 | v0 <- BeginPlainFunctionDefinition -> v1, v2, v3 |
在经过Lifter的转换后:
1 | function v0(v1, v2, v3) { |
在文档里还说明了FuzzIL的几个重要属性:
- FuzzIL里的Program是由一系列instructions组成的
- 任何FuzzIL的Program都能被lift为语法正确的js代码
- FuzzIL的一条instruction由一个operation和输入输出variable组成,可能还带有一个或多个参数(如上面示例中由单引号括起来的)
- 任何的variable都是定义了之后才使用,并且变量名后的标号是连续的
- 控制流通过“Block”来描述,它至少有一个Begin和End的operation,但是也可以有intermediate operations,比如BeginIf, BeginElse, EndIf
- Block instructions可以有内部输出(在示例中’->’后面的那些),这些输出只在新打开的作用域中可见(如函数的参数)
- instructions 的输入总是variable,没有即时值
- instruction 的每一个输出都是一个新的variable,现有的variable只能通过专门的operation来重新分配,如Reassign指令
这几个属性中提到了Program,instruction,operation,variable,Block,这些都会在后面解释
FuzzIL的主要代码实现都在Sources\Fuzzilli\FuzzIL目录下:
1 | Mode LastWriteTime Length Name |
Context.swift
该文件定义了operation需要的context:
1 | /// Current context in the program |
通俗易懂
Operation.swift
注释里说明了operation可以被不同的program共享
1 | /// Operations can be shared between different programs since they do not contain any |
numInputs_
和numOutputs_
表明该operation所需的variable数量,如例子中的StoreProperty v3, 'foo', v4
,它没有output,但是需要两个input的variable,还要带有一个属性名字;这也对应了它的定义:
1 | class StoreProperty: Operation { |
attributes也是一个比较重要的成员,它表明了该operation的一些特性,后续lift和变异也会依赖这些特性
Variable.swift
variable的实现很简单:
1 | /// A variable in the FuzzIL language. |
内部会有一个num表示他是第几个变量,其名字就是v+’num’,如例子中的v1,v2;要注意的是不同的Program是可以用相同的变量名的
Instruction.swift
该文件定义了Instruction类:
1 | /// The building blocks of FuzzIL code. |
如类的开头注释里所说,instruction由operation和一些in out的variable组成,比较重要的成员就是inouts_,该成员保存了in和out的variable还有一个index,该index是和Code相关的,用来表明该instruction在所属code(code就是由一连串的instruction组成的)中的位置;
在一堆in和out的getter定义后就是该instruction的flag,该flag对operation的attribute进行了一些简单的归类
该文件后面还有一个对Protobuf的支持,这不是我们分析的重点(看不动了)就跳过了
Code.swift
1 | /// Code: a sequence of instructions. Forms the basis of Programs. |
code是由一连串的instruction组成的,在它内部最重要的一个函数就是check函数,check函数用来静态检查instruction是不是合法的:
1 | /// Checks if this code is statically valid, i.e. can be used as a Program. |
首先是开头的一连串变量定义,接着:
1 | func defineVariable(_ v: Variable, in scope: Int) throws { |
check函数在内部声明了一个defineVariable函数用于定义variable,从error的提示来看,variable不允许重复定义且他们的id(v.number)一定要是连续的,也就是v1后面必须是v2,最后再把定义的variable和其所在的scope一起存入definedVariables这个map中
然后开始一个大循环,对该code所有的instruction进行检查:
1 | for (idx, instr) in instructions.enumerated() { |
这是循环开头一些简单的check,比如instruction的index是否匹配,该指令input的variable是否已经都定义了,是否在scope中可见,在分析一下该指令的context是否正确
最后是block相关的检查:
1 | // Block and scope management (1) |
isBlockBegin和isBlockEnd对着看,isBlockBegin会将scopeCounter加1,visibleScopes变量在将scopeCounter添加进去,表示接下来的变量都属于新的scope,而isBlockEnd将最后一个scope移除;在isBlockBegin和isBlockEnd的中间是确保instruction的output变量的正确;isBlockBegin和isBlockEnd还涉及switch和classDefinition指令,他们检查的相关代码一部分在ClassUtils.swift,一部分在operation.swift文件里,俺理解的不是很透彻;
Program.swift
1 | /// Immutable unit of code that can, amongst others, be lifted, executed, scored, (de)serialized, and serve as basis for mutations. |
Program类主要还是由code,comments和types三个组成,在其开头的注释中也说明了code该有的属性:
- 所有input的variable都必须是定义过的
- variable的number必须是从零开始,并且是依次递增的
- 只有可见的variable才能被使用,可见代表着vraiable所在的block还没有被销毁
- block是平衡的,也就是说那些带isBlockxxx属性的instruction必须配对(如BeginIf和EndIf)
- 一条instruction总是产生一个新的output的variable(这个不知道该怎么理解,因为从operation里的定义来看,有些operation是没有output的)
文件的后面还定义了对protobuf的支持(看不动了)
综合一下:
1 | Program<--- ProgramComments |
大概是这么个情况
接下来看一下ProgramComments和ProgramTypes
ProgramComments
相关实现在ProgramComments.swift里,代码不多,看着感觉像是拿来做记录用的
ProgramTypes
相关实现在ProgramTypes.swift里:
1 | public struct ProgramTypes: Equatable, Sequence { |
先看看这个TypeInfo:
1 | // Sources\Fuzzilli\FuzzIL\TypeInfo.swift |
这里面有个Type,其实现是在Sources\Fuzzilli\FuzzIL\TypeSystem.swift里,是需要着重分析的对象
Type
TypeSystem.swift文件开头有一长串的注释来解释这个TypeSystem,总的来说就是为了能够更好的生成语义正确的js代码
Type定义了BaseType和Type之间的一些操作:Unioning(|)、Intersecting (&)、Merging (+);
首先来看看BaseType:
1 | struct BaseType: OptionSet, Hashable { |
其中定义了两个特殊的basetype,一个是nothing,一个是anything
Type在实现上定义了两个bitsets,一个是definiteType,一个是possibleType,从代码的示例和注释来看,definiteType像是交集,possibleType像是并集:
1 | /// Internally, types are implemented as bitsets, with each base type corresponding to one bit. |
‘|’ 调用的是union函数, ‘+’ 调用的是merging函数 ,还有个‘&’ 调用的是intersection函数,这里就不贴了
Type还有一个ext的成员,其类型为TypeExtension:
1 | class TypeExtension: Hashable { |
该类用于表示js里的对象,class,还有个FunctionSignature应该是对应js里的function,具体内容可以看FunctionSignature和Parameter类的实现
参考链接
https://github.com/googleprojectzero/fuzzilli/blob/main/Docs/HowFuzzilliWorks.md