-
-
Notifications
You must be signed in to change notification settings - Fork 84
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
492 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# syscall_hijack | ||
|
||
This example demonstrates how to hijack the syscall (Like openat) in the victim process. | ||
|
||
In this example, we use the dummy.c as the victim process and open_modify.bpf.c as the BPF program. We also use loader.c as the loader to load the BPF program. | ||
|
||
We hijack the open/openat syscall in the victim process and modify the file path. For example, we try to open the file "test.txt" in the victim process, but we modify the file path to "test2.txt" in the BPF program. | ||
|
||
Thanks to @officeyutong for the help. | ||
|
||
## How to run | ||
|
||
You should change the some path in dummy.c (Including victim_path & victim_envp) | ||
|
||
Open the **first** terminal and input command below. | ||
|
||
```console | ||
# In the example/syscall_hijack directory | ||
make | ||
|
||
sudo ./dummy | ||
``` | ||
|
||
When you run the last command, you will get the pid of the victim process. | ||
Then you should change the pid in open_modify.bpf.c(const volatile int target_pid = xxx;) | ||
|
||
Then you can enter **second** terminal and input command below. | ||
|
||
```console | ||
# In the example/syscall_hijack directory | ||
make loader | ||
|
||
cd ../.. | ||
|
||
sudo LD_PRELOAD=build/runtime/syscall-server/libbpftime-syscall-server.so example/syscall_hijack/loader | ||
``` | ||
|
||
Then you enter any character in the first terminal, you can see the result in the second terminal. | ||
|
||
The output in the **first** terminal is like below. | ||
|
||
```console | ||
current pid: 1091256 | ||
|
||
[2024-12-16 20:54:38.567] [info] [agent-transformer.cpp:39] Entering bpftime syscal transformer agent | ||
[2024-12-16 20:54:38.567] [stderr] [debug] [agent-transformer.cpp:72] Using agent /home/sy03/.bpftime/libbpftime-agent.so | ||
[2024-12-16 20:54:38.567] [stderr] [info] [text_segment_transformer.cpp:246] Page zero setted up.. | ||
[2024-12-16 20:54:38.567] [stderr] [info] [text_segment_transformer.cpp:274] Rewriting executable segments.. | ||
[2024-12-16 20:54:38.567] [stderr] [debug] [text_segment_transformer.cpp:282] Rewriting segment from 590a7712b000 to 590a7712c000 | ||
|
||
.... | ||
|
||
``` | ||
|
||
The output in the **second** terminal is like below. | ||
|
||
```console | ||
[2024-12-16 18:46:59.215] [info] [syscall_context.cpp:83] Init bpftime syscall mocking.. | ||
[2024-12-16 18:46:59.215] [info] [syscall_context.cpp:84] The log will be written to: ~/.bpftime/runtime.log | ||
BPF program loaded and attached. Press Ctrl+C to exit. | ||
Event: pid=1028323, uid=0, comm=, fname=, flags=0, ret=0 | ||
Event: pid=1028323, uid=0, comm=, fname=, flags=0, ret=0 | ||
Event: pid=1028323, uid=0, comm=, fname=, flags=0, ret=0 | ||
Event: pid=1028323, uid=0, comm=, fname=, flags=0, ret=0 | ||
Event: pid=1028323, uid=0, comm=, fname=, flags=0, ret=0 | ||
Event: pid=1028323, uid=0, comm=, fname=, flags=0, ret=0 | ||
Event: pid=1028323, uid=0, comm=, fname=, flags=0, ret=0 | ||
Event: pid=1028323, uid=0, comm=, fname=, flags=0, ret=0 | ||
Event: pid=1028323, uid=0, comm=, fname=, flags=0, ret=0 | ||
... | ||
|
||
``` | ||
|
||
|
||
## Reference | ||
|
||
[eBPF Development Practice: Modifying System Call Arguments with eBPF](https://eunomia.dev/tutorials/34-syscall/) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#include <stdio.h> | ||
#include <unistd.h> | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
// 等待一段时间,以便外部完成对eBPF map的PID注入更新 | ||
int pid = getpid(); | ||
printf("current pid: %d\n", pid); | ||
// sleep(20); | ||
printf("pending until input\n"); | ||
int c = getchar(); | ||
|
||
// 设置要执行的victim程序路径 | ||
char *victim_path = "/home/sy03/bpftime/example/syscall_hijack/victim"; | ||
// 设置argv | ||
char *victim_argv[] = { "victim", NULL }; | ||
// 设置envp,并在其中加入LD_PRELOAD、AGENT_SO和其他环境变量 | ||
char *victim_envp[] = { | ||
"SPDLOG_LEVEL=debug", | ||
"BPFTIME_LOG_OUTPUT=console", | ||
"LD_PRELOAD=/home/sy03/.bpftime/libbpftime-agent-transformer.so", | ||
"AGENT_SO=/home/sy03/.bpftime/libbpftime-agent.so", // 新增的环境变量 | ||
NULL | ||
}; | ||
|
||
// 直接execve victim程序 | ||
execve(victim_path, victim_argv, victim_envp); | ||
perror("execve failed"); | ||
return 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// loader.c | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <signal.h> | ||
#include <unistd.h> | ||
#include <bpf/libbpf.h> | ||
#include <bpf/bpf.h> | ||
#include "open_modify.skel.h" | ||
|
||
// 定义事件结构体,与 eBPF 程序中的 event 结构体一致 | ||
struct event { | ||
int pid; | ||
int uid; | ||
char comm[16]; | ||
char fname[100]; | ||
int flags; | ||
int ret; | ||
}; | ||
|
||
// const char *dst_file = "new_hijacked.txt"; | ||
|
||
|
||
static volatile bool exiting = false; | ||
|
||
static void sig_handler(int sig) | ||
{ | ||
exiting = true; | ||
} | ||
|
||
// 事件处理回调函数 | ||
static int handle_event(void *ctx, void *data, size_t data_sz) | ||
{ | ||
struct event *e = data; | ||
|
||
printf("Event: pid=%u, uid=%u, comm=%s, fname=%s, flags=%d, ret=%d\n", | ||
e->pid, e->uid, e->comm, e->fname, e->flags, e->ret); | ||
|
||
return 0; | ||
} | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
struct ring_buffer *rb = NULL; | ||
struct open_modify_bpf *skel; | ||
int err; | ||
|
||
|
||
signal(SIGINT, sig_handler); | ||
signal(SIGTERM, sig_handler); | ||
|
||
skel = open_modify_bpf__open_and_load(); | ||
if (!skel) { | ||
fprintf(stderr, "Failed to open and load BPF skeleton\n"); | ||
return 1; | ||
} | ||
|
||
err = open_modify_bpf__attach(skel); | ||
if (err) { | ||
fprintf(stderr, "Failed to attach BPF skeleton\n"); | ||
goto cleanup; | ||
} | ||
|
||
|
||
|
||
printf("BPF program loaded and attached. Press Ctrl+C to exit.\n"); | ||
|
||
// ring buffer | ||
rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_event, NULL, | ||
NULL); | ||
if (!rb) { | ||
fprintf(stderr, "Failed to create ring buffer\n"); | ||
err = 1; | ||
goto cleanup; | ||
} | ||
|
||
// 进入事件循环,读取 ring buffer 中的事件 | ||
while (!exiting) { | ||
err = ring_buffer__poll(rb, 100 /* timeout, ms */); | ||
if (err == -EINTR) { | ||
break; | ||
} else if (err < 0) { | ||
fprintf(stderr, "Error polling ring buffer: %d\n", err); | ||
break; | ||
} | ||
} | ||
|
||
ring_buffer__free(rb); | ||
|
||
cleanup: | ||
open_modify_bpf__destroy(skel); | ||
return err < 0 ? 1 : 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) | ||
OUTPUT := .output | ||
CLANG ?= clang | ||
BPFTARGET := bpf | ||
LIBBPF_SRC := ../../third_party/libbpf/src | ||
BPFTOOL_SRC := ../../third_party/bpftool/src | ||
LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) | ||
BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/bpftool) | ||
BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool | ||
ARCH ?= $(shell uname -m | sed 's/x86_64/x86/' \ | ||
| sed 's/arm.*/arm/' \ | ||
| sed 's/aarch64/arm64/' \ | ||
| sed 's/ppc64le/powerpc/' \ | ||
| sed 's/mips.*/mips/' \ | ||
| sed 's/riscv64/riscv/' \ | ||
| sed 's/loongarch64/loongarch/') | ||
VMLINUX := ../../third_party/vmlinux/$(ARCH)/vmlinux.h | ||
|
||
SPDLOG_SRC := /home/sy03/bpftime/third_party/spdlog/include | ||
|
||
INCLUDES := -I$(OUTPUT) \ | ||
-I$(LIBBPF_SRC)/include \ | ||
-I$(LIBBPF_SRC)/include/uapi \ | ||
-I$(dir $(VMLINUX)) \ | ||
-I$(SPDLOG_SRC) | ||
|
||
CFLAGS := -g -Wall -O2 | ||
CXXFLAGS := -g -Wall -O2 | ||
LDFLAGS := -lelf -lz -lbpf -pthread | ||
|
||
CARGO ?= $(shell which cargo) | ||
ifneq ($(CARGO),) | ||
LDFLAGS += -lrt -ldl -lpthread -lm | ||
endif | ||
|
||
CLANG_BPF_SYS_INCLUDES ?= $(shell $(CLANG) -v -E - </dev/null 2>&1 \ | ||
| sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }') | ||
|
||
ifeq ($(V),1) | ||
Q = | ||
msg = | ||
else | ||
Q = @ | ||
msg = @printf ' %-12s %s\n' "$(1)" "$(2)" | ||
MAKEFLAGS += --no-print-directory | ||
endif | ||
|
||
define allow-override | ||
$(if $(or $(findstring environment,$(origin $(1))),\ | ||
$(findstring command line,$(origin $(1)))),,\ | ||
$(eval $(1) = $(2))) | ||
endef | ||
|
||
$(call allow-override,CC,$(CROSS_COMPILE)cc) | ||
$(call allow-override,LD,$(CROSS_COMPILE)ld) | ||
|
||
.PHONY: all clean victim loader | ||
|
||
all: victim loader dummy | ||
|
||
clean: | ||
$(call msg,CLEAN,Cleaning build artifacts) | ||
$(Q)rm -rf $(OUTPUT) victim loader | ||
|
||
$(OUTPUT) $(OUTPUT)/libbpf $(BPFTOOL_OUTPUT): | ||
$(call msg,MKDIR,$@) | ||
$(Q)mkdir -p $@ | ||
|
||
# 构建 libbpf | ||
$(LIBBPF_OBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(OUTPUT)/libbpf | ||
$(call msg,LIBBPF,$@) | ||
$(Q)$(MAKE) -C $(LIBBPF_SRC) BUILD_STATIC_ONLY=1 \ | ||
OBJDIR=$(dir $@)/libbpf DESTDIR=$(dir $@) \ | ||
INCLUDEDIR= LIBDIR= UAPIDIR= install | ||
|
||
# 构建 bpftool | ||
$(BPFTOOL): | $(BPFTOOL_OUTPUT) | ||
$(call msg,BPFTOOL,$@) | ||
$(Q)$(MAKE) ARCH= CROSS_COMPILE= OUTPUT=$(BPFTOOL_OUTPUT)/ -C $(BPFTOOL_SRC) bootstrap | ||
|
||
# 编译 BPF 程序 | ||
$(OUTPUT)/open_modify.bpf.o: open_modify.bpf.c open_modify.h $(LIBBPF_OBJ) $(VMLINUX) | $(OUTPUT) $(BPFTOOL) | ||
$(call msg,COMPILING BPF,$@) | ||
$(Q)$(CLANG) -O2 -g -target $(BPFTARGET) \ | ||
$(INCLUDES) $(CLANG_BPF_SYS_INCLUDES) \ | ||
-c $< -o $(OUTPUT)/open_modify.tmp.bpf.o | ||
$(Q)$(BPFTOOL) gen object $@ $(OUTPUT)/open_modify.tmp.bpf.o | ||
|
||
# 生成 BPF skeleton | ||
$(OUTPUT)/open_modify.skel.h: $(OUTPUT)/open_modify.bpf.o | $(OUTPUT) $(BPFTOOL) | ||
$(call msg,GENERATING SKEL,$@) | ||
$(Q)$(BPFTOOL) gen skeleton $< > $@ | ||
|
||
# 编译用户空间程序:victim (仅编译victim,不依赖 BPF) | ||
victim: victim.cpp | ||
$(call msg,COMPILING VICTIM,$@) | ||
$(Q)$(CXX) $(CXXFLAGS) $(INCLUDES) -o $@ victim.cpp $(LDFLAGS) | ||
|
||
# 编译用户空间程序:loader (编译 BPF + loader) | ||
loader: loader.c $(OUTPUT)/open_modify.skel.h $(LIBBPF_OBJ) | ||
$(call msg,COMPILING LOADER,$@) | ||
$(Q)$(CC) $(CFLAGS) $(INCLUDES) -o $@ loader.c \ | ||
-I$(OUTPUT) -L$(dir $(LIBBPF_OBJ)) -lbpf $(LDFLAGS) -lelf | ||
|
||
dummy: dummy.c | ||
$(call msg,COMPILING DUMMY,$@) | ||
$(Q)$(CC) $(CFLAGS) $(INCLUDES) -o $@ $< $(LDFLAGS) | ||
|
||
# 保持中间文件 | ||
.SECONDARY: | ||
|
||
.DELETE_ON_ERROR: |
Oops, something went wrong.