对write也进行了hook,并且提供了初始化函数
This commit is contained in:
parent
e6568b3d81
commit
2256a6ce3b
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
BIN
intercept.so
BIN
intercept.so
Binary file not shown.
Loading…
Reference in New Issue