地狱怪客

fuzz pdfium Podofo poppler

原文:https://www.jianshu.com/p/8bb348ba8d61

 

源代码下载

  1. 前提条件是有ss,不然毛都下载不下来
  2. google重新发明了一套下载、编译、测试自家项目的工具(轮子)depot_tool(包括gcllient、GYP、GN和Ninja等),所有的代码都需要利用这些工具从命令行下载编译。于是我们需要让终端也具备ss的能力。
    • 下载polipo,终端执行sudo polipo socksParentProxy=localhost:1080
    • 终端执行export https_proxy=127.0.0.1:8123,搞定。嫌每次打开终端都要输入这句很麻烦的话,可以把它加到bashrc里面。
  3. 下载depot_tools。或者打开ss的全局模式,去googlesource.com网站上下载,或者终端执行
        git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
    
  4. 将depot_tools目录添加到系统$PATH,执行
        gclient config --unmanaged https://pdfium.googlesource.com/pdfium.git
    

加入要同步的项目目录

  1. 执行gclient sync进行同步,获得pdfium的源代码。同步时间会很长,因为同步下来的目录大小大概是3.5G
  2. 期间会提示“To use a proxy in this situation, please supply those settings in a .boto file pointed to by the NO_AUTH_BOTO_CONFIG environment var.” 可能需要配置一下polipo,不过我依然下载了全部代码,编译通过了。

编译

没有找到项目首页里说的编译文件build/gyp_pdfium,因为据说google已经放弃GYP,只支持GN构建了。GN的用法参考这里。按照代码目录下的README.md的步骤编译就好啦。我关掉了v8和xfa支持,编译起来还挺快。几个注意事项如下:

  1. pdfium默认静态编译,不放心的话在args.gn文件里加上一句pdf_is_complete_lib = true。这个条件定义在根目录下的BUILD.gn里,它的关键在于设置了GN工具的参数complete_static_lib为真。
  2. 如果想修改args.gn或者某个BUILD.gn里定义的参数重新编译,执行下列命令即可:
        ninja -C <out_dir> -t clean  # 清除已生成文件
        gn gen <out_dir>             # 重新生成编译文件
        ninja -C <out_dir>           # 编译
    

用AFL对pdfium做模糊测试

AFL需要对测试对象插桩,所以得用afl-gccafl-clang来编译测试对象。虽然对google新发明的这套编译流程一窍不通,不过我还是找到两种办法。

方法1:利用chromium中的现成代码

不知道为什么,chromium代码是直接支持afl测试的,但是作为它的pdf解析器的pdfium却去掉了相应的代码,然后又在BUILD.gn中保留了这个选项。幸好我见过不少精分,还比较淡定。

  1. 首先下载chromium的afl支持文件,放到third_party/afl目录下。其实管用的就那一个BUILD.gn,src目录下就是afl的源代码,我直接用的我本机上的。
  2. 在args.gn文件里里加上use_afl = trueoptimize_for_fuzzing = true的开关,重新编译。
  3. 编译完成后在你的<out_dir>目录下会有afl-fuzz文件,以及业已插桩完毕pdfium_test。下面用afl的默认方式测试pdfium_test即可。不过测试速度很慢,exec_speed只有200/sec左右。

PS:从pdfium的BUILD.gn代码里可以知道,它还支持libfuzzer和drfuzz的测试,开关为use_drfuzzuse_libfuzzer。不过默认也是没有对应支持文件的,需要自己加,我就没研究了。

方法2. 在toolchain中指定自己编译的afl-gcc

GN工具用toolchains来制定构建项目用到的编译器、链接器以及相应参数等。通常GN的主配置文件会根据主机和目标的架构设置default_toolchain,比如pdfium就在build/config/BUILDCONFIG.gn里对这样设置Linux x86_64下的缺省toolchain。

    if (is_clang) {
         _default_toolchain = "//build/toolchain/linux:clang_$target_cpu"
    } else {
         _default_toolchain = "//build/toolchain/linux:$target_cpu"
    }

其中is_clang可以在args.gn里声明,缺省似乎是is_clang = true。想用哪个编译器插桩,就去代码中引号指明的对应文件里把cc = "xxx"改成 cc = "afl-xxx",并对应地将is_clang设为truefalse

不知道得到的pdfium用的什么编译器编译出来的?执行

   objdump -s --section .comment out/Debug/pdfium_test

看看注释里有无clang或gcc字样就可以了。

其他pdf引擎的编译

常见的C/C++编写的pdf引擎有poppler(Evince、Xpdf)、podofo(ImageMagick)和mupdf(SumatraPDF)

编译Podofo

采用了CMake编译系统,使用模糊测试同样需要指定CCCXX--disable-shared。所以编译命令形如:

     CC=afl-gcc CXX=afl-g++ cmake -G "Unix Makefiles" ../podofo-0.9.5/ -DPODOF O_BUILD_SHARED:BOOL=FALSE -DPODOFO_BUILD_STATIC:BOOL=TRUE

如果提示找不到FREETYPE_LIBRARYFONTCONFIG_LIBRARY,安装libfreetype6-dev,libfontconfig1-dev包就行了。剩下的找不到libjpeg、libtiff之类不影响程序编译。

编译poppler

同样采用了CMake,编译命令形如:

     CC=afl-gcc CXX=afl-g++ cmake ../poppler-0.64.0/ -DBUILD_SHARED_LIBS=OFF

作者:cgnail
链接:https://www.jianshu.com/p/8bb348ba8d61
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

码字很辛苦,转载请注明来自人生在世《fuzz pdfium Podofo poppler》

评论