下文中的Python指的是在官方cpython解释器上实现的Python 3.8

1. 一切皆对象

Python之中一切皆对象,更具体些说一切都是指向对象的指针(虽然Python本身并无指针的概念)。

这一点Python远比Java更为激进,Java虽然也有“一切皆对象”的口号,但是至少intdouble等基础类型就不是以对象的形式存在,且对象的方法作为对象的子组件自然也不是对象。但是在Python中则连最基本的整数值是以对象,对象中的方法本身也是另一个对象。可以说是名副其实地做到了一切皆是对象。

2. 连类型也是对象

C++明确区分了类型和对象,前者是一个理念中存在的形式,后者是绑定了特定存储空间的一个内容。

Java中对类型虽然也是都是java.lang.Class类的对象,但是除了反射等少数使用场景,类型和对象之间通常也是泾渭分明的。

而到了Python中,二者却已经到了难分难解的地步了。类型可以像普通对象一样建立、修改、销毁,唯一不同的只是可以产生对象。因此Python中将能产生对象的对象(亦即类型)称为类型对象(定语类型表示其特征,中心语对象表示一切皆对象的本质),其他的对象(寻常所言对象)称为实例对象。

阅读全文 »

下文中的Python指的是在官方cpython解释器上实现的Python 3.8

1. Python也有编译器

一般的观点中常将编程语言分为编译执行解释执行两类,C/C++是最典型的编译执行,而Python被视为最典型的解释执行。

典型以Java为例,二者并非泾渭分明,

graph LR
source(*.java) --javac--> bytecode(*.class)
bytecode --java--> result(程序输出)
  • 第一步中,编译器javac把源文件编译成字节码文件,这一步像是编译型语言,只不过输出不是CPU指令,而是虚拟机指令(所谓跨平台的原因再此)。
  • 第二部中,解释器java(或者说虚拟机JVM)负责执行字节码,产生实际程序效果。

Python其实也和Java一样,存在编译字节码和对字节码进行解释执行两步。只不过,Java的编译部分通常在开发者机器上完成,解释部分在用户机器上运行;而Python中这两步统统运行在用户机器上,编译发生在解释执行的前一刻(即Just In Time编译),编译器嵌入在解释器内部,对开发者和用户透明。通常唯一让使用者察觉到Python字节码存在的现象便是__pycache__文件夹,这个文件夹中缓存了被import的模块的字节码,以便加快执行速度。

阅读全文 »

河西 关中 山西 河北 辽东 山东 川蜀 江南 事件 西晋 280年,晋灭吴,三国结束 成汉 301年,李特起兵 304年,刘渊起兵 前凉 汉赵 慕容鲜卑 汉赵 东晋 311年,永嘉之乱
316年,司马睿即位
后赵 319年,刘曜改汉为赵,石勒自立 后赵 前燕 329年,后赵石勒灭前赵
337年,慕容皝自称为燕王
346年,桓温灭成汉 冉魏 段齐 349年,石虎死
350年,秦齐自立,冉魏诛羯
前秦 351年,冉魏灭后赵
352年,慕容儁灭冉魏称帝
355年,前燕取段齐
376年,前秦苻坚统一北方 后凉 西秦 西燕 383年,淝水之战,前秦分崩 后秦 后燕 394年,后秦灭前秦,后燕灭西燕 北凉 南凉 北魏 南燕 397年,后凉动荡
同年,北魏夺燕冀州地
398年,慕容德自立南燕
西凉 400年,李暠立北凉,后秦灭西秦 北燕 谯蜀 403年,后凉降于后秦
405年,谯纵自立于蜀
407年,赫连勃勃建胡夏
409年,西秦复国,冯跋立北燕
西秦 胡夏 410年,刘裕灭南燕
413年,朱龄石灭谯蜀
414年,西秦灭南凉
417年,刘裕灭后秦而返
北魏 420年,刘裕篡晋
421年,北凉灭西凉
439年,北魏统一北方
阅读全文 »

AFL(american fuzzy lop)最初由Michał Zalewski开发,和libFuzzer等一样是基于覆盖引导(Coverage-guided)的模糊测试工具,它通过记录输入样本的代码覆盖率,从而调整输入样本以提高覆盖率,增加发现漏洞的概率。其工作流程大致如下:

  1. 从源码编译程序时进行插桩,以记录代码覆盖率(Code Coverage)
  2. 选择一些输入文件,作为初始测试集加入输入队列(queue)
  3. 将队列中的文件按一定的策略进行“突变”
  4. 如果经过变异文件更新了覆盖范围,则将其保留添加到队列中
  5. 上述过程会一直循环进行,期间触发了crash的文件会被记录下来

AFL流程

阅读全文 »

被测程序在启用libFuzzer并编译链接后,即成为了一个可接受用户参数的命令行程序,直接执行程序便是启动测试。

1. 命令统一格式

一般格式:

./fuzzer -flag1=val1 -flag2=val2 ... dir1 dir2 ...

flags代表各个控制测试过程的选项参数,可以提供零到任意个,但必须是严格的-flag=value形式,并不是很符合unix命令行习惯:

  • 选项前导用单横线,即使选项是一个词而非单个字符
  • 选项必须要提供对应的值,即使只是一个开关选项如-help,必须要写作-help=1,且选项与值中间只能用等号,不能用空格。

dirs表示语料库目录,它们的内容都会被读取作为初始语料库,但测试过程中生成的新输入只会被保存到第一个目录下。

阅读全文 »

官方文档地址

根据官方定义:libFuzzer is in-process, coverage-guided, evolutionary fuzzing engine.

其本身是llvm项目的一部分,和clang是亲兄弟,二者项目源码分别可见于https://github.com/llvm/llvm-project/tree/master/compiler-rt/lib/fuzzerhttps://github.com/llvm/llvm-project/tree/master/clang,就在同一个仓库里面。

现在稍微新的版本的clang都已经内置libFuzzer了,所以Linux下直接apt install clang就安装完事了。

1. Fuzz Target

libFuzzer要求实现一个fuzz target作为被测对象的接口。

官方文档中的代码示例如下:

// fuzz_target.cc
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
DoSomethingInterestingWithMyAPI(Data, Size);
return 0; // Non-zero return values are reserved for future use.
}

给的是个C++的源码,但实际上却通过extern "C"指定采用C风格的编译约定。所以实际上fuzz target的C语言原型如下:

int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);

名称参数返回值类型都不能动,并且注意参数中传来的字节数组Data是通过底层const修饰了的,也就是不允许修改其中数据。

fuzzer target(即LLVMFuzzerTestOneInput函数)目的是作为被测对象与libFuzzer库之间的一个中转接口,其作用在于接受libFuzzer提供的输入数据Data字节串,(可能还需要进行数据格式转换,)然后传递给实际的被测函数(如上述示例中的DoSomethingInterestingWithMyAPI)。

阅读全文 »

数据引用:bilibili AV5711740视频结束部分

阅读全文 »