Skip to content

Commit

Permalink
example update: syscall_hijack
Browse files Browse the repository at this point in the history
  • Loading branch information
Sy0307 committed Dec 16, 2024
1 parent 50a1e15 commit 9603ebb
Show file tree
Hide file tree
Showing 7 changed files with 492 additions and 0 deletions.
77 changes: 77 additions & 0 deletions example/syscall_hijack/README.md
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/)
30 changes: 30 additions & 0 deletions example/syscall_hijack/dummy.c
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;
}
92 changes: 92 additions & 0 deletions example/syscall_hijack/loader.c
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;
}
112 changes: 112 additions & 0 deletions example/syscall_hijack/makefile
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:
Loading

0 comments on commit 9603ebb

Please sign in to comment.