-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathr2pipe.h
More file actions
135 lines (110 loc) · 3.46 KB
/
r2pipe.h
File metadata and controls
135 lines (110 loc) · 3.46 KB
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
/*
Copyright (C) 2025, Yu JiaWei
和命令行工具 radare2 交互, 对文件进行静态分析.
*/
#pragma once
#include "include/common.h"
/*
为了避免处理跨平台 IO, 使用 subprocess 的 subprocess_read_stdout() 机制来
收集 stdout. 为了避免读取 read_xxx() 函数阻塞, Process 会启动线程在后台
不断读取 stdout 到环形缓冲区, read_xxx() 按需从缓冲区读取.
实现细节见 r2pipe_impl.h.
*/
class Process {
public:
// span, stringview, initilizer_list 都是轻量容器
// 外部来管理 c_args 字符串的生命周期.
using ArgvT = span<const std::string_view>;
/*
传入参数列表, Process 自动在末尾添加 nullptr
*/
explicit Process(ArgvT args);
~Process();
Process(const Process &) = delete;
Process &operator=(const Process &) = delete;
/*
主动等待 Process 停止. 如果执行结束后不关心子进程 可以不调用.
*/
int join();
/*
主动终止 Process, 然后等待其退出
*/
int terminate();
/*
检查进程是否存活
*/
bool is_alive();
vector<char> read_all();
vector<char> read_until(char delimiter);
vector<char> read_until_nonblock(char delimiter);
/*
这个版本可以写入二进制 (包含 \0).
*/
void write(span<const char> data);
static bool in_path(ArgvT exe);
private:
struct Impl;
unique_ptr<Impl> impl_;
};
string addr2line(uint64_t pc, const Path& target);
class R2Session {
public:
/*
为了降低问题复杂度, 这里仅支持有 ELF 信息的二进制文件.
更复杂的 fuzz_info.json 构建请使用独立的 fuzz_info_build.exe 工具.
*/
R2Session(const Path& target,
const std::string& arch = "sparc",
int bits = 32,
bool big_endian = true,
uint64_t entry_addr = 0,
uint64_t load_addr = 0
);
/*
执行有输出的 r2 命令, -q0 模式下会追加一个 \0 结尾.
如果命令本身没有输出, 那么 r2 不会输出 \0, 可能导致阻塞, 建议使用 cmd_nonblcok().
*/
string cmd(string_view cmd) {
LOG_DEBUG("[R2Session] command: {}", cmd);
proc_->write(std::format("{}\n", cmd));
auto buf = proc_->read_until('\0');
return string(buf.begin(), buf.end());
}
/*
用于执行不关心命令结果的 r2 脚本
如果命令有输出, 但是使用了 cmd_nonblock(), 可导致输出
驻留在 stdout 缓冲区, 导致下一次读取被污染.
因此, 命令执行并短暂睡眠后, 会尝试读取缓冲区.
如果缓冲区有内容, 则清空缓冲区.
*/
void cmd_nonblock(string_view cmd) {
LOG_DEBUG("[R2Session] command: {}", cmd);
proc_->write(format("{}\n", cmd));
sleep_ms(100); // 等待 r2 可能的返回值
if (proc_->read_all().size() > 0)
// 如果有输出, 则清空缓冲区
proc_->read_until_nonblock('\0');
}
/*
当明确命令的结果是 Json 时使用. 仅支持阻塞版本
*/
Json cmdj(string_view command);
~R2Session() {
if (proc_) {
proc_->write("q\n"); // 退出 r2
proc_->join(); // 等待进程结束
}
}
private:
void read_prompt() { proc_->read_until('\0'); }
void sleep_ms(int ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}
bool check_r2_in_path() {
std::array<string_view, 2> arr = {"radare2.exe", "-v"};
span<const string_view> args(arr);
return Process::in_path(args);
}
unique_ptr<Process> proc_;
vector<string_view> cmd_args_; // r2 命令参数
};