Driller源码阅读笔记(二)
driller部分代码只是读取输入种子然后返回一个可用的新种子,实际fuzz的时候还是需要搭配fuzzer使用:https://github.com/shellphish/fuzzer
不过,fuzzer中不是直接使用Driller类,而是LocalCallback类,因此有必要看看这一部分是如何实现的。
fuzzer的shellphuzz脚本相关代码:
if args.grease_with:print ("[*] Greasing...")grease_extension = fuzzer.GreaseCallback(args.grease_with,grease_filter=helper_module.grease_filter if helper_module is not None else None,grease_sorter=helper_module.grease_sorter if helper_module is not None else None)if args.driller_workers:print ("[*] Drilling...")drill_extension = driller.LocalCallback(num_workers=args.driller_workers, worker_timeout=args.driller_timeout, length_extension=args.length_extension)stuck_callback = ((lambda f: (grease_extension(f), drill_extension(f))) if drill_extension and grease_extensionelse drill_extension or grease_extension)
由于后面fuzzer里对stuck_callback是直接调用的
def _timer_callback(self):if self._stuck_callback is not None:# check if afl has pending fav'sif ('fuzzer-master' in self.stats and 'pending_favs' in self.stats['fuzzer-master'] and \int(self.stats['fuzzer-master']['pending_favs']) == 0) or self.force_interval is not None:self._stuck_callback(self)
所以重点看Driller类的__call__方法,即driller_callback函数
def driller_callback(self, fuzz):l.warning("Driller stuck callback triggered!")# remove any workers that aren't runningself._running_workers = [x for x in self._running_workers if x.is_alive()]# get the files in queuequeue = self._queue_files(fuzz)#for i in range(1, fuzz.fuzz_id):# fname = "fuzzer-%d" % i# queue.extend(self.queue_files(fname))# start drillingnot_drilled = set(queue) - self._already_drilled_inputsif len(not_drilled) == 0:l.warning("no inputs left to drill")while len(self._running_workers) < self._num_workers and len(not_drilled) > 0:to_drill_path = list(not_drilled)[0]not_drilled.remove(to_drill_path)self._already_drilled_inputs.add(to_drill_path)proc = multiprocessing.Process(target=_run_drill, args=(self, fuzz, to_drill_path),kwargs={'length_extension': self._length_extension})proc.start()self._running_workers.append(proc)__call__ = driller_callback
这个函数大致是把afl fuzz时的queue文件夹内的种子依次取出用来作为Driller的输入,然后创建子进程执行,子进程的命令类似这个:
timeout -k 610 600 /home/waterfire/.virtualenvs/angr/bin/python3.6 /home/waterfire/.virtualenvs/angr/lib/python3.6/site-packages/driller/local_callback.py /home/waterfire/fuzz/example/test /dev/shm/work/test/sync /dev/shm/work/test/sync/fuzzer-master/fuzz_bitmap /dev/shm/work/test/sync/fuzzer-master/queue/id:000002,sync:driller,src:000007,+cov --length-extension 10
即用timeout执行后面的命令600秒,如果到了还没执行完就在610秒杀死,后面就是执行local_callback.py以及其参数,依次为目标二进制、工作目录、fuzz的bitmap路径、fuzz的队列中的输入样例。
接下来看local_callback.py的执行部分:
if __name__ == "__main__":parser = argparse.ArgumentParser(description="Driller local callback")parser.add_argument('binary_path')parser.add_argument('fuzzer_out_dir')parser.add_argument('bitmap_path')parser.add_argument('path_to_input_to_drill')parser.add_argument('--length-extension', help="Try extending inputs to driller by this many bytes", type=int)args = parser.parse_args()logcfg_file = os.path.join(os.getcwd(), '.driller.ini')if os.path.isfile(logcfg_file):logging.config.fileConfig(logcfg_file)binary_path, fuzzer_out_dir, bitmap_path, path_to_input_to_drill = sys.argv[1:5]fuzzer_bitmap = open(args.bitmap_path, "rb").read()# create a folderdriller_dir = os.path.join(args.fuzzer_out_dir, "driller")driller_queue_dir = os.path.join(driller_dir, "queue")try: os.mkdir(driller_dir)except OSError: passtry: os.mkdir(driller_queue_dir)except OSError: passl.debug('drilling %s', path_to_input_to_drill)# get the inputinputs_to_drill = [open(args.path_to_input_to_drill, "rb").read()]if args.length_extension:inputs_to_drill.append(inputs_to_drill[0] + b'\0' * args.length_extension)for input_to_drill in inputs_to_drill:d = driller.Driller(args.binary_path, input_to_drill, fuzzer_bitmap)count = 0for new_input in d.drill_generator():id_num = len(os.listdir(driller_queue_dir))fuzzer_from = args.path_to_input_to_drill.split("sync/")[1].split("/")[0] + args.path_to_input_to_drill.split("id:")[1].split(",")[0]filepath = "id:" + ("%d" % id_num).rjust(6, "0") + ",from:" + fuzzer_fromfilepath = os.path.join(driller_queue_dir, filepath)with open(filepath, "wb") as f:f.write(new_input[1])count += 1l.warning("found %d new inputs", count)
其中inputs_to_drill是种子的队列,默认只有参数传递的fuzz种子,如果设置了length_extension参数就会扩展之后加入inputs_to_drill,然后对每个种子通过Driller类的drill_generator方法生成新种子,这个方法最后还是会用到前一篇讲的_drill_input。
现在,我更想关注的是driller与fuzz交互的部分,即driller如何获取已fuzz的路径以及如何将新的种子传递给fuzz。
首先,从上面代码可以看到生成新种子后,直接在queue里创建新文件写入种子即可。
其次,已fuzz的路径应该是通过fuzz_bitmap传递,上一篇里可以看到fuzz_bitmap会作为参数传递给angr.exploration_techniques.DrillerCore
self._core = angr.exploration_techniques.DrillerCore(trace=r.trace, fuzz_bitmap=self.fuzz_bitmap)
DrillerCore类中最重要的是step方法
def step(self, simgr, stash='active', **kwargs):simgr.step(stash=stash, **kwargs)# Mimic AFL's indexing scheme.if 'missed' in simgr.stashes and simgr.missed:# A bit ugly, might be replaced by tracer.predecessors[-1] or crash_monitor.last_state.prev_addr = simgr.one_missed.history.bbl_addrs[-1]prev_loc = prev_addrprev_loc = (prev_loc >> 4) ^ (prev_loc << 8)prev_loc &= len(self.fuzz_bitmap) - 1prev_loc = prev_loc >> 1for state in simgr.missed:cur_loc = state.addrcur_loc = (cur_loc >> 4) ^ (cur_loc << 8)cur_loc &= len(self.fuzz_bitmap) - 1hit = bool(self.fuzz_bitmap[cur_loc ^ prev_loc] ^ 0xff)transition = (prev_addr, state.addr)mapped_to = self.project.loader.find_object_containing(state.addr).binaryl.debug("Found %#x -> %#x transition.", transition[0], transition[1])if not hit and transition not in self.encounters and not self._has_false(state) and mapped_to != 'cle##externs':state.preconstrainer.remove_preconstraints()if state.satisfiable():# A completely new state transition.l.debug("Found a completely new transition, putting into 'diverted' stash.")simgr.stashes['diverted'].append(state)self.encounters.add(transition)else:l.debug("State at %#x is not satisfiable.", transition[1])elif self._has_false(state):l.debug("State at %#x is not satisfiable even remove preconstraints.", transition[1])else:l.debug("%#x -> %#x transition has already been encountered.", transition[0], transition[1])return simgr
prev_loc和cur_loc分别将执行step前后的两个地址后20bit映射到了2字节,然后把它们异或的值作为fuzz_bitmap的索引,并通过fuzz_bitmap对应的值是否为0xff来判断该路径是否被执行过。如果未被执行过就会求解约束并当成功求解时添加结果。
Driller源码阅读笔记(二)相关推荐
- Driller源码阅读笔记(一)
Driller源码:https://github.com/shellphish/driller 所给样例为: import drillerd = driller.Driller("./CAD ...
- werkzeug源码阅读笔记(二) 下
wsgi.py----第二部分 pop_path_info()函数 先测试一下这个函数的作用: >>> from werkzeug.wsgi import pop_path_info ...
- ThreadPoolExecutor源码阅读笔记(二)FutureTask
BlockingQueue: 队列他决定了任务的调度方式,我们主要关注BlockingQueue的offer, poll,take三个方法 offer往队列里面添加任务如果队列已经满了话返回false ...
- 源码阅读笔记 BiLSTM+CRF做NER任务 流程图
源码阅读笔记 BiLSTM+CRF做NER任务(二) 源码地址:https://github.com/ZhixiuYe/NER-pytorch 本篇正式进入源码的阅读,按照流程顺序,一一解剖. 一.流 ...
- 代码分析:NASM源码阅读笔记
NASM源码阅读笔记 NASM(Netwide Assembler)的使用文档和代码间的注释相当齐全,这给阅读源码 提供了很大的方便.按作者的说法,这是一个模块化的,可重用的x86汇编器, 而且能够被 ...
- libreCAD源码阅读笔记1
libreCAD源码阅读笔记1 一 前言: 正如官网(https://www.librecad.org)所说,libreCAD是一个开源的CAD制图软件,可以运行在Windows.Apple.Linu ...
- Live555源码阅读笔记(一):源码介绍文档 及 源码目录结构
目录 一.Live555介绍 1.Live555项目介绍 2.官网及帮助文档介绍 二.源码目录结构 1.UsageEnvironment 2.BasicUsageEnvironment 3.group ...
- dgl源码阅读笔记(3)——DeepWalk
dgl源码阅读笔记(3)--DeepWalk 图神经网络开源库dgl阅读笔记 文章目录 dgl源码阅读笔记(3)--DeepWalk 图神经网络开源库dgl阅读笔记 @[TOC](文章目录) 前言 一 ...
- Transformers包tokenizer.encode()方法源码阅读笔记
Transformers包tokenizer.encode()方法源码阅读笔记_天才小呵呵的博客-CSDN博客_tokenizer.encode
最新文章
- Python进阶之路 3.4.2 条件语句(if、else和elif)
- iis8 php mysql_windows2012下 iis8+php5.2+mysql5 配置
- Andoird自定义ViewGroup实现竖向引导界面
- DbEntry 访问Access2010数据库
- java 下载excel到本地_java已知下载链接将Excel文件利用httpclient下载到本地
- c语言课程设计实训主要目的,《C语言课程设计实验大纲.doc
- 2022PMP考试敏捷知识点(2)
- java 密码 星号显示_Java多线程 例子 cmd窗口下 实现输入密码星号显示
- 多目标应用:基于MOGWO的地铁隧道上方基坑工程优化设计(提供MATLAB代码)
- MySQL模糊查询like优化,再也用不着 like+% 了
- 浅谈面向对象的编程思想:如何优雅地把大象装进冰箱?
- Gherkin简单使用
- #金数据#微信小程序#微信小程序跳转金数据小程序并获取问卷信息
- 汪汪汪WDG--看门狗的作用
- 服务机器人“大战”进入下半场,竞争焦点变了
- 电子专业如何写毕业论文
- rust: 引用第三方库(Cargo.toml、Cargo.lock文件)
- 使用JAVA对接跨境贸易电子商务数据交换接口拼接xml
- 统一数据交换(UDX)
- 【电子刊物制作】名编辑电子杂志大师教程 | 设置多国语言浏览界面