-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathpatch_do_execve_6_6.cpp
More file actions
193 lines (157 loc) · 7.48 KB
/
Copy pathpatch_do_execve_6_6.cpp
File metadata and controls
193 lines (157 loc) · 7.48 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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#include "patch_do_execve_6_6.h"
#include "analyze/base_func.h"
#include "3rdparty/aarch64_asm_helper.h"
using namespace asmjit;
using namespace asmjit::a64;
using namespace asmjit::a64::Predicate;
PatchDoExecve66::PatchDoExecve66(const PatchBase66& patch_base, const KernelSymbolOffset& sym)
: PatchBase66(patch_base) {
init_do_execve_param(sym);
}
PatchDoExecve66::~PatchDoExecve66() {}
void PatchDoExecve66::init_do_execve_param(const KernelSymbolOffset& sym) {
// 6.6内核固定使用do_execveat_common,filename在x1寄存器
m_doexecve_reg_param.do_execve_addr = sym.do_execveat_common;
m_doexecve_reg_param.do_execve_filename_reg = kernel_6_6::DO_EXECVE_FILENAME_REG;
m_doexecve_reg_param.is_single_char_ptr = false;
// Fallback
if (m_doexecve_reg_param.do_execve_addr == 0) {
m_doexecve_reg_param.do_execve_addr = sym.do_execve;
m_doexecve_reg_param.do_execve_filename_reg = 0;
}
if (m_doexecve_reg_param.do_execve_addr == 0) {
m_doexecve_reg_param.do_execve_addr = sym.do_execveat;
m_doexecve_reg_param.do_execve_filename_reg = 1;
}
}
size_t PatchDoExecve66::patch_do_execve(
const SymbolRegion& hook_func_start_region,
size_t task_struct_cred_offset,
size_t task_struct_seccomp_offset,
size_t comm_handler_addr,
std::vector<patch_bytes_data>& vec_out_patch_bytes_data)
{
size_t hook_func_start_addr = hook_func_start_region.offset;
if (hook_func_start_addr == 0) { return 0; }
std::cout << "Start hooking do_execve at: 0x" << std::hex << hook_func_start_addr << std::endl << std::endl;
// 6.6内核固定参数
int atomic_usage_len = get_cred_atomic_usage_len();
int securebits_padding = get_cred_securebits_padding();
int securebits_len = 4 + securebits_padding;
uint64_t cap_ability_max = get_cap_ability_max();
int cap_cnt = get_need_write_cap_cnt();
size_t hook_jump_back_addr = m_doexecve_reg_param.do_execve_addr + 4;
char empty_root_key_buf[ROOT_KEY_LEN] = { 0 };
aarch64_asm_ctx asm_ctx = init_aarch64_asm();
auto a = asm_ctx.assembler();
// ========== 代码布局 ==========
// [0-47]: ROOT密钥存储区 (48字节)
// [48-51]: 原始指令占位
// [52+]: Hook逻辑代码
Label label_end = a->newLabel();
Label label_cycle_name = a->newLabel();
Label label_check_cmd = a->newLabel(); // Pro新增:命令检查
Label label_normal_root = a->newLabel(); // Pro新增:正常提权
Label label_do_root = a->newLabel(); // 执行提权
Label label_seccomp_retry = a->newLabel(); // seccomp原子操作重试
// 嵌入ROOT密钥空间 (48字节)
int key_start = a->offset();
a->embed((const uint8_t*)empty_root_key_buf, sizeof(empty_root_key_buf));
// 原始指令占位 (会被替换)
a->mov(x0, x0); // NOP placeholder
// ========== 修复:保存关键参数寄存器 ==========
// 保存x0,x1(do_execve的前两个参数)以便通信处理器调用后恢复
// x0 = fd, x1 = struct filename*
a->stp(x0, x1, ptr(sp).pre(-16));
// ========== 检查filename有效性 ==========
a->mov(x11, Imm(uint64_t(-kernel_6_6::MAX_ERRNO)));
a->cmp(a64::x(m_doexecve_reg_param.do_execve_filename_reg), x11);
a->b(CondCode::kCS, label_end); // 无效指针,跳过
// 获取filename字符串指针
// 6.6使用struct filename*,需要解引用获取字符串
a->ldr(x11, ptr(a64::x(m_doexecve_reg_param.do_execve_filename_reg)));
// ========== 比较filename与ROOT密钥 ==========
int key_offset = key_start - a->offset();
aarch64_asm_adr_x(a, x12, key_offset);
a->bind(label_cycle_name);
a->ldrb(w14, ptr(x11).post(1));
a->ldrb(w15, ptr(x12).post(1));
a->cmp(w14, w15);
a->b(CondCode::kNE, label_end); // 不匹配,跳过
a->cbnz(w15, label_cycle_name); // 继续比较
// ========== ROOT密钥匹配成功 ==========
// Pro新增:检查是否为命令调用 (filename[48] == '/')
if (comm_handler_addr != 0) {
// 重新获取filename指针
a->ldr(x11, ptr(a64::x(m_doexecve_reg_param.do_execve_filename_reg)));
a->ldrb(w14, ptr(x11, ROOT_KEY_LEN));
a->cmp(w14, Imm('/'));
a->b(CondCode::kEQ, label_check_cmd); // 是命令调用
a->b(label_do_root); // 是提权调用
// 命令调用处理
a->bind(label_check_cmd);
// 修复:恢复栈(我们push了x0,x1)
a->ldp(x0, x1, ptr(sp).post(16));
// 跳转到通信处理器
emit_safe_bl(a, hook_func_start_addr, comm_handler_addr);
// 返回-ENOENT阻止真正执行
a->mov(x0, Imm(-2)); // -ENOENT
a->ret(x30);
}
// ========== 执行提权逻辑 ==========
a->bind(label_do_root);
// 获取current task
emit_get_current(a, x12);
// 获取cred指针: cred = current->cred
a->ldr(x14, ptr(x12, task_struct_cred_offset));
// 清除uid/gid/suid/sgid/euid/egid/fsuid/fsgid
a->add(x14, x14, Imm(atomic_usage_len));
a->str(xzr, ptr(x14).post(8)); // uid + gid
a->str(xzr, ptr(x14).post(8)); // suid + sgid
a->str(xzr, ptr(x14).post(8)); // euid + egid
a->str(xzr, ptr(x14).post(8)); // fsuid + fsgid
// 清除securebits
a->str(wzr, ptr(x14).post(securebits_len));
// 设置所有capability为最大值
a->mov(x13, Imm(cap_ability_max));
a->stp(x13, x13, ptr(x14).post(16)); // cap_inheritable + cap_permitted
a->stp(x13, x13, ptr(x14).post(16)); // cap_effective + cap_bset
if (cap_cnt >= 5) {
a->str(x13, ptr(x14).post(8)); // cap_ambient
}
// 清除seccomp (6.6内核: CONFIG_THREAD_INFO_IN_TASK = true)
// 修复:添加原子操作重试循环
a->mov(x15, Imm((uint64_t)1ULL << kernel_6_6::TIF_SECCOMP));
a->bind(label_seccomp_retry);
a->ldaxr(x14, ptr(x12));
a->bic(x14, x14, x15);
a->stlxr(w16, x14, ptr(x12)); // 使用w16存储结果
a->cbnz(w16, label_seccomp_retry); // 失败则重试
// 清除seccomp.mode
a->str(wzr, ptr(x12, task_struct_seccomp_offset));
// ========== 跳转回原函数 ==========
a->bind(label_end);
// 修复:恢复参数寄存器
a->ldp(x0, x1, ptr(sp).post(16));
aarch64_asm_b(a, (int32_t)(hook_jump_back_addr - (hook_func_start_addr + a->offset())));
// 输出生成的汇编
std::cout << print_aarch64_asm(a) << std::endl;
// 导出字节码
std::vector<uint8_t> bytes = aarch64_asm_to_bytes(a);
if (bytes.size() == 0) return 0;
std::string str_bytes = bytes2hex((const unsigned char*)bytes.data(), bytes.size());
size_t shellcode_size = str_bytes.length() / 2;
// 替换占位符为原始指令
char hookOrigCmd[4] = { 0 };
memcpy(&hookOrigCmd, (void*)((size_t)&m_file_buf[0] + m_doexecve_reg_param.do_execve_addr), sizeof(hookOrigCmd));
std::string strHookOrigCmd = bytes2hex((const unsigned char*)hookOrigCmd, sizeof(hookOrigCmd));
str_bytes = str_bytes.substr(0, sizeof(empty_root_key_buf) * 2) + strHookOrigCmd + str_bytes.substr(sizeof(empty_root_key_buf) * 2 + 0x4 * 2);
if (shellcode_size > hook_func_start_region.size) {
std::cout << "[发生错误] patch_do_execve failed: not enough kernel space." << std::endl;
return 0;
}
vec_out_patch_bytes_data.push_back({ str_bytes, hook_func_start_addr });
// 在do_execve入口插入跳转
patch_jump(m_doexecve_reg_param.do_execve_addr, hook_func_start_addr + sizeof(empty_root_key_buf), vec_out_patch_bytes_data);
return shellcode_size;
}