fix replace code

This commit is contained in:
yunwei37
2023-05-31 01:03:16 +08:00
committed by 云微
parent fe3dfa9aca
commit 48fae08f08
11 changed files with 152 additions and 133 deletions

View File

@@ -6,4 +6,4 @@ package.json
package.yaml
ecli
bootstrap
textreplace2
replace

View File

@@ -24,7 +24,7 @@ INCLUDES := -I$(OUTPUT) -I../../libbpf/include/uapi -I$(dir $(VMLINUX))
CFLAGS := -g -Wall
ALL_LDFLAGS := $(LDFLAGS) $(EXTRA_LDFLAGS)
APPS = textreplace2 # minimal minimal_legacy uprobe kprobe fentry usdt sockfilter tc ksyscall
APPS = replace # minimal minimal_legacy uprobe kprobe fentry usdt sockfilter tc ksyscall
CARGO ?= $(shell which cargo)
ifeq ($(strip $(CARGO)),)

View File

@@ -1,3 +1,26 @@
# replace
# 使用 eBPF 替换任意程序读取或写入的文本
TODO
```sh
sudo ./replace --filename /path/to/file --input foo --replace bar
```
This program replaces all text matching `input` in the file with the `replace` text.
This has a number of uses, for example:
To hide kernel module `joydev` from tools such as `lsmod`:
```bash
./replace -f /proc/modules -i 'joydev' -r 'cryptd'
```
Spoof the MAC address of the `eth0` interface:
```bash
./replace -f /sys/class/net/eth0/address -i '00:15:5d:01:ca:05' -r '00:00:00:00:00:00'
```
Malware conducting anti-sandbox checks might check the MAC address to look for signs it is
running inside a Virtual Machine or Sandbox, and not on a 'real' machine.
**NOTE:** Both `input` and `replace` must be the same length, to avoid adding NULL characters to the
middle of a block of text. To enter a newline from a bash prompt, use `$'\n'`, e.g. `--replace $'text\n'`.

View File

@@ -16,6 +16,10 @@
// Simple message structure to get events from eBPF Programs
// in the kernel to user spcae
#define TASK_COMM_LEN 16
#define LOCAL_BUFF_SIZE 64
#define loop_size 64
#define text_len_max 20
struct event {
int pid;
char comm[TASK_COMM_LEN];

View File

@@ -1,96 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
#ifndef BAD_BPF_COMMON_UM_H
#define BAD_BPF_COMMON_UM_H
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <unistd.h>
#include <signal.h>
#include <sys/resource.h>
#include <errno.h>
#include <fcntl.h>
static volatile sig_atomic_t exiting;
void sig_int(int signo)
{
exiting = 1;
}
static bool setup_sig_handler() {
// Add handlers for SIGINT and SIGTERM so we shutdown cleanly
__sighandler_t sighandler = signal(SIGINT, sig_int);
if (sighandler == SIG_ERR) {
fprintf(stderr, "can't set signal handler: %s\n", strerror(errno));
return false;
}
sighandler = signal(SIGTERM, sig_int);
if (sighandler == SIG_ERR) {
fprintf(stderr, "can't set signal handler: %s\n", strerror(errno));
return false;
}
return true;
}
static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
{
return vfprintf(stderr, format, args);
}
static bool bump_memlock_rlimit(void)
{
struct rlimit rlim_new = {
.rlim_cur = RLIM_INFINITY,
.rlim_max = RLIM_INFINITY,
};
if (setrlimit(RLIMIT_MEMLOCK, &rlim_new)) {
fprintf(stderr, "Failed to increase RLIMIT_MEMLOCK limit! (hint: run as root)\n");
return false;
}
return true;
}
static bool setup() {
// Set up libbpf errors and debug info callback
libbpf_set_print(libbpf_print_fn);
// Bump RLIMIT_MEMLOCK to allow BPF sub-system to do anything
if (!bump_memlock_rlimit()) {
return false;
};
// Setup signal handler so we exit cleanly
if (!setup_sig_handler()) {
return false;
}
return true;
}
#ifdef BAD_BPF_USE_TRACE_PIPE
static void read_trace_pipe(void) {
int trace_fd;
trace_fd = open("/sys/kernel/debug/tracing/trace_pipe", O_RDONLY, 0);
if (trace_fd == -1) {
printf("Error opening trace_pipe: %s\n", strerror(errno));
return;
}
while (!exiting) {
static char buf[4096];
ssize_t sz;
sz = read(trace_fd, buf, sizeof(buf) -1);
if (sz > 0) {
buf[sz] = '\x00';
puts(buf);
}
}
}
#endif // BAD_BPF_USE_TRACE_PIPE
#endif // BAD_BPF_COMMON_UM_H

View File

@@ -58,15 +58,13 @@ struct {
const volatile int target_ppid = 0;
// These store the name of the file to replace text in
const int filename_len_max = 50;
const volatile int filename_len = 0;
const volatile char filename[filename_len_max];
const volatile char filename[50];
// These store the text to find and replace in the file
const unsigned int text_len_max = 20;
const volatile unsigned int text_len = 0;
const volatile char text_find[filename_len_max];
const volatile char text_replace[filename_len_max];
const volatile char text_find[FILENAME_LEN_MAX];
const volatile char text_replace[FILENAME_LEN_MAX];
SEC("tp/syscalls/sys_exit_close")
int handle_close_exit(struct trace_event_raw_sys_exit *ctx)
@@ -102,7 +100,7 @@ int handle_openat_enter(struct trace_event_raw_sys_enter *ctx)
}
// Get filename from arguments
char check_filename[filename_len_max];
char check_filename[FILENAME_LEN_MAX];
bpf_probe_read_user(&check_filename, filename_len, (char*)ctx->args[1]);
// Check filename is our target
@@ -188,17 +186,15 @@ int find_possible_addrs(struct trace_event_raw_sys_exit *ctx)
return 0;
}
long int buff_size = ctx->ret;
long int read_size = buff_size;
unsigned long int read_size = buff_size;
bpf_printk("[TEXT_REPLACE] PID %d | read_size %lu | buff_addr 0x%lx\n", pid, read_size, buff_addr);
// 64 may be to large for loop
const unsigned int local_buff_size = 32;
const unsigned int loop_size = 32;
char local_buff[local_buff_size] = { 0x00 };
char local_buff[LOCAL_BUFF_SIZE] = { 0x00 };
if (read_size > (local_buff_size+1)) {
if (read_size > (LOCAL_BUFF_SIZE+1)) {
// Need to loop :-(
read_size = local_buff_size;
read_size = LOCAL_BUFF_SIZE;
}
// Read the data returned in chunks, and note every instance
@@ -209,7 +205,7 @@ int find_possible_addrs(struct trace_event_raw_sys_exit *ctx)
for (unsigned int i = 0; i < loop_size; i++) {
// Read in chunks from buffer
bpf_probe_read(&local_buff, read_size, (void*)buff_addr);
for (unsigned int j = 0; j < local_buff_size; j++) {
for (unsigned int j = 0; j < LOCAL_BUFF_SIZE; j++) {
// Look for the first char of our 'to find' text
if (local_buff[j] == text_find[0]) {
name_addr = buff_addr+j;
@@ -220,7 +216,7 @@ int find_possible_addrs(struct trace_event_raw_sys_exit *ctx)
}
}
buff_addr += local_buff_size;
buff_addr += LOCAL_BUFF_SIZE;
}
// Tail-call into 'check_possible_addrs' to loop over possible addresses
@@ -267,12 +263,13 @@ int check_possible_addresses(struct trace_event_raw_sys_exit *ctx) {
break;
}
bpf_probe_read_user(&name, text_len_max, (char*)name_addr);
for (j = 0; j < text_len_max; j++) {
if (name[j] != text_find[j]) {
break;
}
}
if (j >= name_len) {
// for (j = 0; j < text_len_max; j++) {
// if (name[j] != text_find[j]) {
// break;
// }
// }
// we can use bpf_strncmp here, but it's not available in the kernel version older
if (bpf_strncmp(name, text_len_max, (const char *)text_find) == 0) {
// ***********
// We've found out text!
// Add location to map to be overwritten

View File

@@ -1,10 +1,77 @@
// SPDX-License-Identifier: BSD-3-Clause
#include <argp.h>
#include <unistd.h>
#include "textreplace.skel.h"
#include "common_um.h"
#include "replace.skel.h"
#include "common.h"
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <unistd.h>
#include <signal.h>
#include <sys/resource.h>
#include <errno.h>
#include <fcntl.h>
static volatile sig_atomic_t exiting;
void sig_int(int signo)
{
exiting = 1;
}
static bool setup_sig_handler() {
// Add handlers for SIGINT and SIGTERM so we shutdown cleanly
__sighandler_t sighandler = signal(SIGINT, sig_int);
if (sighandler == SIG_ERR) {
fprintf(stderr, "can't set signal handler: %s\n", strerror(errno));
return false;
}
sighandler = signal(SIGTERM, sig_int);
if (sighandler == SIG_ERR) {
fprintf(stderr, "can't set signal handler: %s\n", strerror(errno));
return false;
}
return true;
}
static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
{
return vfprintf(stderr, format, args);
}
static bool bump_memlock_rlimit(void)
{
struct rlimit rlim_new = {
.rlim_cur = RLIM_INFINITY,
.rlim_max = RLIM_INFINITY,
};
if (setrlimit(RLIMIT_MEMLOCK, &rlim_new)) {
fprintf(stderr, "Failed to increase RLIMIT_MEMLOCK limit! (hint: run as root)\n");
return false;
}
return true;
}
static bool setup() {
// Set up libbpf errors and debug info callback
libbpf_set_print(libbpf_print_fn);
// Bump RLIMIT_MEMLOCK to allow BPF sub-system to do anything
if (!bump_memlock_rlimit()) {
return false;
};
// Setup signal handler so we exit cleanly
if (!setup_sig_handler()) {
return false;
}
return true;
}
// Setup Argument stuff
#define filename_len_max 50
#define text_len_max 20
@@ -98,7 +165,7 @@ static int handle_event(void *ctx, void *data, size_t data_sz)
int main(int argc, char **argv)
{
struct ring_buffer *rb = NULL;
struct textreplace_bpf *skel;
struct replace_bpf *skel;
int err;
// Parse command line arguments
@@ -121,7 +188,7 @@ int main(int argc, char **argv)
}
// Open BPF application
skel = textreplace_bpf__open();
skel = replace_bpf__open();
if (!skel) {
fprintf(stderr, "Failed to open BPF program: %s\n", strerror(errno));
return 1;
@@ -137,7 +204,7 @@ int main(int argc, char **argv)
skel->rodata->text_len = strlen(env.input);
// Verify and load program
err = textreplace_bpf__load(skel);
err = replace_bpf__load(skel);
if (err) {
fprintf(stderr, "Failed to load and verify BPF skeleton\n");
goto cleanup;
@@ -168,7 +235,7 @@ int main(int argc, char **argv)
}
// Attach tracepoint handler
err = textreplace_bpf__attach( skel);
err = replace_bpf__attach( skel);
if (err) {
fprintf(stderr, "Failed to attach BPF program: %s\n", strerror(errno));
goto cleanup;
@@ -197,6 +264,6 @@ int main(int argc, char **argv)
}
cleanup:
textreplace_bpf__destroy( skel);
replace_bpf__destroy( skel);
return -err;
}