P1umerのStudio.

P1umer 今天又咸鱼了吗

字数统计: 2,216阅读时长: 10 min
2018/12/27 Share

27/12/2018

昨晚重新做了个 ubuntu 虚拟机用来跑 libfuzzer,经过了几天的探索感觉对libfuzzer有点初步的认识了,然而意识到写libfuzzer最重要的还是熟悉对应代码的api,于是下一步打算好好看一看chrome ipc里面的函数调用关系(TODO)。但还是先从阅读chrome自带的ned-fuzzer。(然鹅落了一堆作业啊啊啊啊难过)

appcache_fuzzer.cc 结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
namespace content{

namespace{
···
}

//注册
DEFINE_BINARY_PROTO_FUZZER(const fuzzing::proto::Session& session)
{
//Some Initialization
···
//fuzzer?
for(commend:session)
{
switch(commend){
case kRegisterHost:{__some__commend};
case kUnregisterHost:{__some__commend};
case ...;
case ...;
...
}
//初始化host
host.reset()
SingletonEnv().thread_bundle.RunUntilIdle();
}
}

所以这个逻辑看上去很简单的样子,也没有什么特别的算法,无非就是:

  • 定义了一些模拟通讯过程的函数
  • 注册 fuzzer
  • 通过proto产生的随机Session的session.commands()作为commend来针对commend进行fuzz
  • 每次执行完commend进行host状态的初始化

这个 fuzz 的结构貌似就是这样,但是我还没有搞明白:

  • proto产生的数据是什么样的
  • commend的作用
  • 以及最重要的:前面的函数定义
  • 最最重要的,为什么选择 commend 这一层面去fuzz

所以第一条,先弄明白 google-proto 是怎么工作的

【+】文件在这

【+】看一段 proto 中文引导

在研究proto之前,很有趣的一点是: appcache_fuzzer.pb.happcache_fuzzer.pb.cc 中都存在:

1
2
// Generated by the protocol buffer compiler.  DO NOT EDIT!
// source: appcache_fuzzer.proto

啊哈!也就是说我们只要弄明白 appcache_fuzzer.proto 是怎么回事就好了。

但我还是先来研究一下 proto 是什么(回到 开头)。

emmmm,所以这是一个比较【方便的消息格式】,可以编译为c++的类以及类的实现代码。

so,来看一下 appcache_fuzzer.proto QaQ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
message Session {
repeated Command commands = 1;
}

// Based on content::AppCacheBackend interface
// See content/common/appcache_interfaces.h
message Command {
oneof command {
RegisterHost register_host = 1;
UnregisterHost unregister_host = 2;
SelectCache select_cache = 3;
SetSpawningHostId set_spawning_host_id = 4;
SelectCacheForSharedWorker select_cache_for_shared_worker = 5;
MarkAsForeignEntry mark_as_foreign_entry = 6;
GetStatus get_status = 7;
StartUpdate start_update = 8;
SwapCache swap_cache = 9;
GetResourceList get_resource_list = 10;
DoRequest do_request = 11;
RunUntilIdle run_until_idle = 12;
}
}

// We only need a few hosts to encapsulate all the logic
enum HostId {
HOST_N2 = -2;
HOST_N1 = -1;
HOST_0 = 0;
HOST_1 = 1;
HOST_2 = 2;
}

// Caches are created more quickly so we want more of them
enum CacheId {
CACHE_N1 = -1;
CACHE_0 = 0;
CACHE_1 = 1;
CACHE_2 = 2;
CACHE_3 = 3;
CACHE_4 = 4;
CACHE_5 = 5;
CACHE_6 = 6;
CACHE_7 = 7;
CACHE_8 = 8;
CACHE_9 = 9;
}

message RegisterHost {
required HostId host_id = 1;
}

message UnregisterHost {
required HostId host_id = 1;
}

message SelectCache {
required HostId host_id = 1;
required HostId from_id = 2;
required Url document_url = 3;
required Url opt_manifest_url = 4;
}

enum HttpCode {
RESPONSE_100 = 100;
RESPONSE_200 = 200;
RESPONSE_206 = 206;
RESPONSE_301 = 301;
RESPONSE_302 = 302;
RESPONSE_303 = 303;
RESPONSE_304 = 304;
RESPONSE_307 = 307;
RESPONSE_308 = 308;
RESPONSE_401 = 401;
RESPONSE_403 = 403;
RESPONSE_404 = 404;
RESPONSE_500 = 500;
RESPONSE_501 = 501;
}

message DoRequest {
required HttpCode http_code = 1;
required bool do_not_cache = 2;
required ManifestResponse manifest_response = 3;
required Url url = 4;
}

message ManifestResponse {
repeated Url urls = 1;
}

// Make sure to test logic when fetching more than the max concurrent allowed.
enum UrlTestCaseIndex {
EMPTY = 0;
PATH_1 = 1;
PATH_2 = 2;
PATH_3 = 3;
PATH_4 = 4;
PATH_5 = 5;
}

// In order to efficiently fuzz the appcache logic, we don't want
// to worry about all the possible url parsing. For this reason,
// we generate either an empty GURL or one of up to 5 paths,
// http://localhost/[1-5]. We can update this if in the future
// more coverage can be achieved.
// We represent this with a UrlTestCaseIndex enum. The 0 value is
// a special case representing an empty string or GURL().
// If not empty, we just append the int value of the UrlTestCaseIndex
// enum to "http://localhost/". Using an enum in this way makes
// mutations more efficient.
message Url {
required UrlTestCaseIndex url_test_case_idx = 1;
}

message RunUntilIdle {}

message SetSpawningHostId {
required HostId host_id = 1;
required HostId spawning_host_id = 2;
}

message SelectCacheForSharedWorker {
required HostId host_id = 1;
required CacheId cache_document_was_loaded_from = 2;
}

message MarkAsForeignEntry {
required HostId host_id = 1;
required Url document_url = 2;
required CacheId cache_document_was_loaded_from = 3;
}

message GetStatus {
required HostId host_id = 1;
}

message StartUpdate {
required HostId host_id = 1;
}

message SwapCache {
required HostId host_id = 1;
}

message GetResourceList {
required HostId host_id = 1;
}
  • 以上包含message的嵌套关系以及部分字段的取值范围
  • 所以大概明白了proto产生的数据类型就是类似与上述嵌套关系产生的 message,用来作为注册fuzz时的随即数据接口,该随机数据的语法为proto的message定义。

所以第二个问题就是,commend的含义?

28/12/2018

回到了昨天的问题,所以各个commend具体是什么含义?

一共有这些 commend:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
message Command {
oneof command {
RegisterHost register_host = 1;
UnregisterHost unregister_host = 2;
SelectCache select_cache = 3;
SetSpawningHostId set_spawning_host_id = 4;
SelectCacheForSharedWorker select_cache_for_shared_worker = 5;
MarkAsForeignEntry mark_as_foreign_entry = 6;
GetStatus get_status = 7;
StartUpdate start_update = 8;
SwapCache swap_cache = 9;
GetResourceList get_resource_list = 10;
DoRequest do_request = 11;
RunUntilIdle run_until_idle = 12;
}
}

oh,像这样的类型均为message类型,在appcache_fuzzer.proto下面均有定义,但我们现在关注的是每个 commend 对应的 renders 到 browser 的具体 IPC 过程。

1
2
// Based on content::AppCacheBackend interface
// See content/common/appcache_interfaces.h

SO,继续研究 appcache_interfaces.h ,此处是 renders 联系 browser 的接口。

1
2
3
4
#include "base/files/file_path.h"
#include "content/common/appcache.mojom.h"
#include "content/public/common/appcache_info.h"
#include "mojo/public/cpp/system/message_pipe.h"

好,先来弄明白 mojo

mojo

【+】mojo 简介

【+】Mojom IDL and Bindings Generator

【+】Mojo C++ Bindings API

得到的信息:

  • Generator 根据 mojom 文件生成了两个 Interface
  • InterfacePtr:是发送消息的端点,一旦绑定到一个消息管道的端点,就可以马上序列化要发送的消息,并写入管道
  • InterfaceRequest:是接受消息的端点,本质上仅仅是一个持有消息管道端点的容器,本身不会做任何事情,需要传递到直到绑定了实现了mojom文件接口的类,才能读取消息
  • 定义 pipe :

    1
    2
    3
    4
    5
    6
    #include "sample/logger.mojom.h"

    mojo::MessagePipe pipe;
    sample::mojom::LoggerPtr logger(
    sample::mojom::LoggerPtrInfo(std::move(pipe.handle0), 0));
    sample::mojom::LoggerRequest request(std::move(pipe.handle1));
  • MOJO C++ Bindings library 给出了对应的接口:

    1
    2
    sample::mojom::LoggerPtr logger;
    auto request = mojo::MakeRequest(&logger);
  • 此时管道已经完备,但是 LoggerRequest 端并未对消息进行处理。

  • request 作为参数初始化 LoggerImpl
  • Binding 接受 request 和消息类进行对Mojo-pipe的监控
  • 监听和反序列化均由 Binding 完成
  • Binding 调用 Logger 类的 Log 输出/处理消息
  • 最终可以在 Impl 类的一端看到 Logger 发送的消息

31/12/2018

抱歉

这两天亲戚来北京,然后陪玩了一段时间,学习耽搁了不少。

今天要做的是看 35c3 的有关 fuzz 的talk,顺便做一些笔记,确定一下之后要写什么样的 fuzz。

TALK-1

【+】dharma

【+】rr

【+】TODO

TALK-2 BY ned

【+】没看完,等看完了写个总结

继续看 mojo,卡在了 line_.back() 那里,可能我思路闭塞了

然而明天要看加密与解密了。。

等到周末继续看这一块吧

31/1/2018

时隔一个月重新开始笔记

从今天开始重新开始一点一点完整写 libfuzzer,计划假期结束能熟练编写libfuzzer,另外最好可以编写一个简单的 llvm pass :)

[+] 写了基本的 libfuzzer,复习了一些编译以及运行选项

[+] 顺道学习了下 shell 脚本的开发

[+] tip:可以在单步fuzz中遍历某些可选项的值,即使用的是同一个 Data 字符串

1/2/2019

[+] 起床看了会神经网络,知道最基本流程该怎么写了

[+] 修改了一下心脏滴血fuzzer,发现了好多问题,比如 fsanitize=fuzzer 和 fsannitize-coverage=balabala 的区别,比如一些函数在fuzzer内部定义和在外部定义为什么测试会有差别,以及经过修改的fuzzer再更改了一些选项后跑出来 mem-leak & oom…有待解决

[+] 详细研究了ASan的算法,在 llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp 里面研究了 Global Variable & Stack Variable & Heap Variable 的插桩过程以及相应的算法

2/2/2019

[+] 在看 ASAN 源码过程中意识到学会编写 llvm pass 一定会对以后独自编写 fuzzer 框架有用的,因此今天除了接着研究ASAN源码之余要学习一下llvm pass的编写,目标是熟练掌握 ModulePass 以及 FunctionPass

[+] 配了 llvm 环境 & 熟悉了一下基本的操作

[+] 还在看怎么写 pass…(并没有看完,明天接着看)

3/2/2019

[+] 弄清楚了注册并使用 pass 的流程

[+] 抄了下入门 pass && 简单的看了下 llvm IR(挖坑,过了年来填)

[+] 下午在看番(逃

13/2/2019

[+] 整理一下这段时间看的 llvm 相关笔记

[+] 看了遍 llvm 的 IR

[+] 找了些 pass 来看,发现有很多的 api 不知道怎么用orz

14/2/2019

[+] 特殊的节日,就抽空看了下 34c3 的一篇演讲 Implementing an LLVM based Dynamic Binary Instrumentation framework

15/2/2019

[+] 重新看了一遍 Asan 源码,对比一下前段时间看的 llvm 的一些点,加深印象

[+] 继续学 libfuzzer 写法

CATALOG
  1. 1. 27/12/2018
    1. 1.0.1. appcache_fuzzer.cc 结构
    2. 1.0.2. 所以第一条,先弄明白 google-proto 是怎么工作的
    3. 1.0.3. 所以第二个问题就是,commend的含义?
  • 2. 28/12/2018
    1. 2.0.1. 回到了昨天的问题,所以各个commend具体是什么含义?
      1. 2.0.1.1. mojo
  • 3. 31/12/2018
    1. 3.0.1. 抱歉
    2. 3.0.2. TALK-1
    3. 3.0.3. TALK-2 BY ned
  • 4. 31/1/2018
  • 5. 1/2/2019
  • 6. 2/2/2019
  • 7. 3/2/2019
  • 8. 13/2/2019
  • 9. 14/2/2019
  • 10. 15/2/2019