diff --git a/execve_intercept.c b/execve_intercept.c index 1fb13a4..e423a30 100644 --- a/execve_intercept.c +++ b/execve_intercept.c @@ -178,75 +178,34 @@ int is_ansi_escape_sequence(const char *str) { return str[0] == '\033' && str[1] == '['; } -// 复制标准输出和错误输出到日志文件 -void duplicate_output_to_log() { - DEBUG_LOG("Duplicating stdout/stderr to log file: %s", LOG_OUT_FILE); - int log_fd = open(LOG_OUT_FILE, O_WRONLY | O_CREAT | O_APPEND, 0644); - if (log_fd == -1) { - perror("Failed to open log file"); - return; - } +// 保存原始的 write 函数指针 +static ssize_t (*original_write)(int fd, const void *buf, size_t count) = NULL; - int pipe_fds[2]; - if (pipe(pipe_fds) == -1) { - perror("Failed to create pipe"); - close(log_fd); - return; - } +// 保存日志文件描述符 +static int log_fd = -1; - pid_t pid = fork(); - if (pid == -1) { - perror("Failed to fork"); - close(log_fd); - close(pipe_fds[0]); - close(pipe_fds[1]); - return; - } +// 我们自己的 write 函数 +ssize_t write(int fd, const void *buf, size_t count) { + ssize_t result = -1; - if (pid == 0) { // 子进程:读取 pipe,并写入日志 - close(pipe_fds[1]); // 关闭写端 - char buffer[1024]; - ssize_t n; - int has_error = 0; - - while ((n = read(pipe_fds[0], buffer, sizeof(buffer))) > 0) { - // 检查buffer中是否包含错误信息 - if (strstr(buffer, "error") || strstr(buffer, "Error") || - strstr(buffer, "ERROR")) { - has_error = 1; - } - - // 输出到终端时保留颜色 - if (isatty(STDOUT_FILENO)) { - if (write(STDOUT_FILENO, buffer, n) == -1) { - perror("Failed to write to stdout"); - } - } - if (write(log_fd, buffer, n) == -1) { - perror("Failed to write to log file"); - } + result = original_write(fd, buf, count); + // 如果原始 write 成功,则将相同的内容写入日志文件 + if (result > 0 && log_fd != -1) { + ssize_t log_result = original_write(log_fd, buf, count); + if (log_result == -1) { + fprintf(stderr, "Error writing to log file: %s\n", strerror(errno)); + // 注意:这里不应该影响原始 write 的返回值 } - - if (has_error) { - printf("\n检测到命令执行出错,已经上报北冥论坛~ \n"); - fflush(stdout); // 确保提示文字被输出 - } - - close(pipe_fds[0]); - close(log_fd); - _exit(0); - } else { // 父进程:写入 pipe - close(pipe_fds[0]); // 关闭读端 - dup2(pipe_fds[1], STDOUT_FILENO); - dup2(pipe_fds[1], STDERR_FILENO); - close(pipe_fds[1]); - close(log_fd); } + return result; } typedef int (*orig_execve_type)(const char *filename, char *const argv[], char *const envp[]); +// 原始指针 +static orig_execve_type orig_execve = NULL; + // 判断父进程是否为终端 shell (bash, zsh, fish 等) int is_terminal_shell() { pid_t ppid = getppid(); @@ -326,8 +285,6 @@ int execve(const char *filename, char *const argv[], char *const envp[]) { // 仅在 shell 终端调用 execve 时拦截 if (!is_terminal_shell()) { DEBUG_LOG("Not a terminal shell, bypassing interception."); - orig_execve_type orig_execve = - (orig_execve_type)dlsym(RTLD_NEXT, "execve"); return orig_execve(filename, argv, envp); } @@ -340,16 +297,12 @@ int execve(const char *filename, char *const argv[], char *const envp[]) { // 如果共享内存未成功加载,则直接执行 if (shared_config == NULL) { DEBUG_LOG("Shared memory not initialized, bypassing interception."); - orig_execve_type orig_execve = - (orig_execve_type)dlsym(RTLD_NEXT, "execve"); return orig_execve(filename, argv, envp); } // 如果功能被禁用,则直接执行 if (!shared_config->enabled) { DEBUG_LOG("Not enabled."); - orig_execve_type orig_execve = - (orig_execve_type)dlsym(RTLD_NEXT, "execve"); return orig_execve(filename, argv, envp); } @@ -363,8 +316,6 @@ int execve(const char *filename, char *const argv[], char *const envp[]) { // 特殊处理以 shell.posix // 方式执行的命令,直接执行,不进行规则匹配和输出重定向 if (argv[1] != NULL && strcmp(argv[1], "shell.posix") == 0) { - orig_execve_type orig_execve = - (orig_execve_type)dlsym(RTLD_NEXT, "execve"); return orig_execve(filename, argv, envp); } @@ -394,12 +345,37 @@ int execve(const char *filename, char *const argv[], char *const envp[]) { } // 复制 stdout 和 stderr 到日志文件 - duplicate_output_to_log(); + // duplicate_output_to_log(); - orig_execve_type orig_execve = (orig_execve_type)dlsym(RTLD_NEXT, "execve"); return orig_execve(filename, argv, envp); } +// 构造函数,在库被加载时执行 +__attribute__((constructor)) static void initialize() { + DEBUG_LOG("Initializing execve_intercept library."); + // 获取原始的 write 函数 + original_write = dlsym(RTLD_NEXT, "write"); + if (original_write == NULL) { + fprintf(stderr, "Error in dlsym(\"write\"): %s\n", dlerror()); + exit(EXIT_FAILURE); + } + + // 打开日志文件,以追加模式打开,如果不存在则创建 + log_fd = open(LOG_OUT_FILE, O_WRONLY | O_CREAT | O_APPEND, 0644); + if (log_fd == -1) { + fprintf(stderr, "Error opening log file \"%s\": %s\n", LOG_OUT_FILE, + strerror(errno)); + exit(EXIT_FAILURE); + } + + load_config_if_needed(); + orig_execve = (orig_execve_type)dlsym(RTLD_NEXT, "execve"); + if (orig_execve == NULL) { + fprintf(stderr, "Error in dlsym(\"execve\"): %s\n", dlerror()); + exit(EXIT_FAILURE); + } +} + // 在库卸载时分离和删除共享内存 __attribute__((destructor)) static void cleanup_shared_memory() { DEBUG_LOG("Cleaning up shared memory."); @@ -409,7 +385,20 @@ __attribute__((destructor)) static void cleanup_shared_memory() { } shared_config = NULL; } + if (log_fd != -1) { + DEBUG_LOG("Closing log file descriptor."); + close(log_fd); + } // 注意:这里不删除共享内存段,因为可能被其他进程使用。 // 如果需要删除,需要一个明确的机制来判断是否是最后一个使用者。 // 例如,可以创建一个单独的工具来管理共享内存的生命周期。 } + +__attribute__((destructor)) static void debug_log() { + DEBUG_LOG("execve_intercept library unloaded."); + // log输出路径 + DEBUG_LOG("Log file: %s", LOG_FILE); + DEBUG_LOG("Log out file: %s", LOG_OUT_FILE); + DEBUG_LOG("Config file: %s", CONFIG_FILE); + DEBUG_LOG("Shared memory ID: %d", shm_id); +} diff --git a/intercept.so b/intercept.so index 2d551b7..2c48af2 100755 Binary files a/intercept.so and b/intercept.so differ