fixed
This commit is contained in:
parent
eb6316e8ec
commit
61a42adb2e
|
|
@ -11,6 +11,12 @@
|
|||
"shm.h": "c",
|
||||
"unistd.h": "c",
|
||||
"logging.h": "c",
|
||||
"fcntl.h": "c"
|
||||
}
|
||||
"fcntl.h": "c",
|
||||
"exec_hook.h": "c",
|
||||
"dlfcn.h": "c",
|
||||
"signal.h": "c",
|
||||
"stdio.h": "c",
|
||||
"wait.h": "c"
|
||||
},
|
||||
"C_Cpp.errorSquiggles": "disabled"
|
||||
}
|
||||
35
Makefile
35
Makefile
|
|
@ -1,28 +1,47 @@
|
|||
CC = gcc
|
||||
CFLAGS = -shared -fPIC -Wall -Wextra -Werror -O2 -fno-strict-aliasing -fPIC -fno-omit-frame-pointer -fno-stack-protector -Wl,-z,relro,-z,now
|
||||
CFLAGS = -shared -fPIC -Wall -Wextra -Werror -fno-strict-aliasing -fPIC -fno-omit-frame-pointer -fno-stack-protector -Wl,-z,relro,-z,now
|
||||
LDFLAGS = -ldl -ljson-c
|
||||
HOOK_LDFLAGS = -ldl -pthread
|
||||
|
||||
TARGET_NAME = intercept.so
|
||||
HOOK_NAME = hook_write.so
|
||||
|
||||
BUILD_DIR = build
|
||||
SRC_DIR = src
|
||||
|
||||
SRC = $(wildcard $(SRC_DIR)/*.c)
|
||||
SRC := $(filter-out $(SRC_DIR)/hook_write.c, $(SRC)) # 排除 hook_write.c
|
||||
|
||||
OBJ = $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(SRC))
|
||||
TARGET = $(BUILD_DIR)/$(TARGET_NAME)
|
||||
|
||||
HOOK_SRC = $(SRC_DIR)/hook_write.c
|
||||
HOOK_OBJ = $(BUILD_DIR)/hook_write.o
|
||||
HOOK_TARGET = $(BUILD_DIR)/$(HOOK_NAME)
|
||||
|
||||
# 如果需要开启 debug,只需执行 make DEBUG=1
|
||||
ifeq ($(DEBUG),1)
|
||||
CFLAGS += -DDEBUG -g # Add -g for debugging symbols
|
||||
CFLAGS += -DDEBUG -g
|
||||
endif
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(BUILD_DIR)/$(TARGET_NAME): $(OBJ)
|
||||
@mkdir -p $(BUILD_DIR)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
all: $(TARGET) $(HOOK_TARGET)
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
|
||||
@mkdir -p $(BUILD_DIR)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(TARGET): $(OBJ)
|
||||
@mkdir -p $(BUILD_DIR)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
$(HOOK_TARGET): $(HOOK_OBJ)
|
||||
@mkdir -p $(BUILD_DIR)
|
||||
$(CC) $(CFLAGS) -Wno-error=unused-result -o $@ $^ $(HOOK_LDFLAGS)
|
||||
|
||||
$(HOOK_OBJ): $(HOOK_SRC)
|
||||
@mkdir -p $(BUILD_DIR)
|
||||
$(CC) $(CFLAGS) -Wno-error=unused-result -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR)
|
||||
|
||||
|
|
@ -30,4 +49,4 @@ debug:
|
|||
rm -rf $(BUILD_DIR)
|
||||
$(MAKE) DEBUG=1
|
||||
|
||||
rebuild: clean all
|
||||
rebuild: clean all
|
||||
|
|
|
|||
BIN
build/config.o
BIN
build/config.o
Binary file not shown.
BIN
build/debug.o
BIN
build/debug.o
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
build/logging.o
BIN
build/logging.o
Binary file not shown.
BIN
build/rules.o
BIN
build/rules.o
Binary file not shown.
BIN
build/utils.o
BIN
build/utils.o
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,231 @@
|
|||
This is the parent process.
|
||||
Enter something: This is the child process.
|
||||
Enter something: 123
|
||||
You entered: 123
|
||||
This is a test output.
|
||||
This is a test error output.
|
||||
[DEBUG][PID 3285394] src/execve_interceptor.c:29:execve(): Intercepted execve for: /usr/bin/bash
|
||||
[DEBUG][PID 3285394] src/execve_interceptor.c:30:execve(): argv[0] = bash
|
||||
[DEBUG][PID 3285394] src/config.c:114:load_config_if_needed(): Creating shared memory for config data
|
||||
[DEBUG][PID 3285394] src/config.c:127:load_config_if_needed(): Loading config file for the first time
|
||||
[DEBUG][PID 3285394] src/config.c:17:load_config_to_shm(): Loading configuration from /tmp/exec_hook/config/execve_rules.json to shared memory
|
||||
[DEBUG][PID 3285394] src/config.c:89:load_config_to_shm(): Loaded 3 rules to shared memory
|
||||
[DEBUG][PID 3285394] src/execve_interceptor.c:43:execve(): Not a terminal shell, bypassing interception.
|
||||
[DEBUG][PID 3285513] src/execve_interceptor.c:29:execve(): Intercepted execve for: /usr/bin/lesspipe
|
||||
[DEBUG][PID 3285513] src/execve_interceptor.c:30:execve(): argv[0] = lesspipe
|
||||
[DEBUG][PID 3285513] src/config.c:114:load_config_if_needed(): Creating shared memory for config data
|
||||
[DEBUG][PID 3285513] src/config.c:127:load_config_if_needed(): Loading config file for the first time
|
||||
[DEBUG][PID 3285513] src/config.c:17:load_config_to_shm(): Loading configuration from /tmp/exec_hook/config/execve_rules.json to shared memory
|
||||
[DEBUG][PID 3285513] src/config.c:89:load_config_to_shm(): Loaded 3 rules to shared memory
|
||||
[DEBUG][PID 3285513] src/execve_interceptor.c:48:execve(): Current Config rule count : 3
|
||||
[DEBUG][PID 3285513] src/logging.c:21:write_log(): Writing exec log for command: /usr/bin/lesspipe
|
||||
[DEBUG][PID 3285513] src/logging.c:154:duplicate_output_to_log(): Signal handler for SIGINT installed.
|
||||
[DEBUG][PID 3285513] src/logging.c:236:duplicate_output_to_log(): Child process exited normally
|
||||
[DEBUG][PID 3285513] src/init_cleanup.c:23:cleanup_shared_memory(): execve_intercept library unloaded.
|
||||
[DEBUG][PID 3285513] src/init_cleanup.c:25:cleanup_shared_memory(): Log file: ./logs/execve.log
|
||||
[DEBUG][PID 3285513] src/init_cleanup.c:26:cleanup_shared_memory(): Log out file: ./logs/execve_out.log
|
||||
[DEBUG][PID 3285513] src/init_cleanup.c:27:cleanup_shared_memory(): Config file: /tmp/exec_hook/config/execve_rules.json
|
||||
[DEBUG][PID 3285513] src/init_cleanup.c:28:cleanup_shared_memory(): Shared memory ID: 2
|
||||
[DEBUG][PID 3285513] src/init_cleanup.c:30:cleanup_shared_memory(): Cleaning up shared memory.
|
||||
/tmp/exec_hook/intercept.so(print_stacktrace+0x23)[0x7f78a48e21a5]
|
||||
/tmp/exec_hook/intercept.so(cleanup_shared_memory+0x210)[0x7f78a48e29e0]
|
||||
/lib64/ld-linux-x86-64.so.2(+0x624e)[0x7f78a48f024e]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(+0x45495)[0x7f78a46b8495]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(on_exit+0x0)[0x7f78a46b8610]
|
||||
/tmp/exec_hook/intercept.so(duplicate_output_to_log+0x623)[0x7f78a48e334c]
|
||||
/tmp/exec_hook/intercept.so(execve+0x5e4)[0x7f78a48e27a8]
|
||||
bash(shell_execve+0x36)[0x60ac0270ba46]
|
||||
bash(+0x5b8e7)[0x60ac027128e7]
|
||||
bash(+0x4b993)[0x60ac02702993]
|
||||
bash(execute_command_internal+0xf1d)[0x60ac02704b5d]
|
||||
bash(parse_and_execute+0x6c8)[0x60ac027654e8]
|
||||
bash(command_substitute+0xa98)[0x60ac0272d938]
|
||||
bash(+0x780a2)[0x60ac0272f0a2]
|
||||
bash(+0x81d58)[0x60ac02738d58]
|
||||
bash(+0x83277)[0x60ac0273a277]
|
||||
bash(+0x87df9)[0x60ac0273edf9]
|
||||
bash(+0x4bf8f)[0x60ac02702f8f]
|
||||
bash(execute_command_internal+0xf1d)[0x60ac02704b5d]
|
||||
bash(execute_command+0xc8)[0x60ac027071b8]
|
||||
bash(execute_command_internal+0x343b)[0x60ac0270707b]
|
||||
bash(parse_and_execute+0x6c8)[0x60ac027654e8]
|
||||
bash(+0xaf1c6)[0x60ac027661c6]
|
||||
bash(maybe_execute_file+0x2e)[0x60ac0276659e]
|
||||
bash(main+0x1a30)[0x60ac026e9db0]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(+0x29d90)[0x7f78a469cd90]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80)[0x7f78a469ce40]
|
||||
bash(_start+0x25)[0x60ac026e9f15]
|
||||
bash: eval: 行 31: 未预期的记号 "(" 附近有语法错误
|
||||
bash: eval: 行 31: `[DEBUG][PID 3285514] src/logging.c:125:duplicate_output_to_log(): Child process 3285514: stdout is /dev/pts/6
'
|
||||
[DEBUG][PID 3285518] src/execve_interceptor.c:29:execve(): Intercepted execve for: /usr/bin/dircolors
|
||||
[DEBUG][PID 3285518] src/execve_interceptor.c:30:execve(): argv[0] = dircolors
|
||||
[DEBUG][PID 3285518] src/config.c:114:load_config_if_needed(): Creating shared memory for config data
|
||||
[DEBUG][PID 3285518] src/config.c:127:load_config_if_needed(): Loading config file for the first time
|
||||
[DEBUG][PID 3285518] src/config.c:17:load_config_to_shm(): Loading configuration from /tmp/exec_hook/config/execve_rules.json to shared memory
|
||||
[DEBUG][PID 3285518] src/config.c:89:load_config_to_shm(): Loaded 3 rules to shared memory
|
||||
[DEBUG][PID 3285518] src/execve_interceptor.c:48:execve(): Current Config rule count : 3
|
||||
[DEBUG][PID 3285518] src/logging.c:21:write_log(): Writing exec log for command: /usr/bin/dircolors
|
||||
[DEBUG][PID 3285518] src/logging.c:154:duplicate_output_to_log(): Signal handler for SIGINT installed.
|
||||
[DEBUG][PID 3285518] src/logging.c:236:duplicate_output_to_log(): Child process exited normally
|
||||
[DEBUG][PID 3285518] src/init_cleanup.c:23:cleanup_shared_memory(): execve_intercept library unloaded.
|
||||
[DEBUG][PID 3285518] src/init_cleanup.c:25:cleanup_shared_memory(): Log file: ./logs/execve.log
|
||||
[DEBUG][PID 3285518] src/init_cleanup.c:26:cleanup_shared_memory(): Log out file: ./logs/execve_out.log
|
||||
[DEBUG][PID 3285518] src/init_cleanup.c:27:cleanup_shared_memory(): Config file: /tmp/exec_hook/config/execve_rules.json
|
||||
[DEBUG][PID 3285518] src/init_cleanup.c:28:cleanup_shared_memory(): Shared memory ID: 2
|
||||
[DEBUG][PID 3285518] src/init_cleanup.c:30:cleanup_shared_memory(): Cleaning up shared memory.
|
||||
/tmp/exec_hook/intercept.so(print_stacktrace+0x23)[0x7f78a48e21a5]
|
||||
/tmp/exec_hook/intercept.so(cleanup_shared_memory+0x210)[0x7f78a48e29e0]
|
||||
/lib64/ld-linux-x86-64.so.2(+0x624e)[0x7f78a48f024e]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(+0x45495)[0x7f78a46b8495]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(on_exit+0x0)[0x7f78a46b8610]
|
||||
/tmp/exec_hook/intercept.so(duplicate_output_to_log+0x623)[0x7f78a48e334c]
|
||||
/tmp/exec_hook/intercept.so(execve+0x5e4)[0x7f78a48e27a8]
|
||||
bash(shell_execve+0x36)[0x60ac0270ba46]
|
||||
bash(+0x5b8e7)[0x60ac027128e7]
|
||||
bash(+0x4b993)[0x60ac02702993]
|
||||
bash(execute_command_internal+0xf1d)[0x60ac02704b5d]
|
||||
bash(parse_and_execute+0x6c8)[0x60ac027654e8]
|
||||
bash(command_substitute+0xa98)[0x60ac0272d938]
|
||||
bash(+0x780a2)[0x60ac0272f0a2]
|
||||
bash(+0x81d58)[0x60ac02738d58]
|
||||
bash(+0x83277)[0x60ac0273a277]
|
||||
bash(+0x87df9)[0x60ac0273edf9]
|
||||
bash(+0x4bf8f)[0x60ac02702f8f]
|
||||
bash(execute_command_internal+0xf1d)[0x60ac02704b5d]
|
||||
bash(execute_command+0xc8)[0x60ac027071b8]
|
||||
bash(execute_command_internal+0x343b)[0x60ac0270707b]
|
||||
bash(execute_command+0xc8)[0x60ac027071b8]
|
||||
bash(execute_command_internal+0x1d8e)[0x60ac027059ce]
|
||||
bash(execute_command+0xc8)[0x60ac027071b8]
|
||||
bash(execute_command_internal+0x1d8e)[0x60ac027059ce]
|
||||
bash(execute_command+0xc8)[0x60ac027071b8]
|
||||
bash(execute_command_internal+0x1d8e)[0x60ac027059ce]
|
||||
bash(execute_command+0xc8)[0x60ac027071b8]
|
||||
bash(execute_command_internal+0x1d8e)[0x60ac027059ce]
|
||||
bash(execute_command+0xc8)[0x60ac027071b8]
|
||||
bash(execute_command_internal+0x108a)[0x60ac02704cca]
|
||||
bash(parse_and_execute+0x6c8)[0x60ac027654e8]
|
||||
bash(+0xaf1c6)[0x60ac027661c6]
|
||||
bash(maybe_execute_file+0x2e)[0x60ac0276659e]
|
||||
bash(main+0x1a30)[0x60ac026e9db0]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(+0x29d90)[0x7f78a469cd90]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80)[0x7f78a469ce40]
|
||||
bash(_start+0x25)[0x60ac026e9f15]
|
||||
bash: eval: 行 77: 未预期的记号 "(" 附近有语法错误
|
||||
bash: eval: 行 77: `[DEBUG][PID 3285519] src/logging.c:125:duplicate_output_to_log(): Child process 3285519: stdout is /dev/pts/6
'
|
||||
[?2004h]0;qcqcqc@qcqcqc-ThinkCentre-M710q-N000: ~/workspace/test_execve[01;32mqcqcqc@qcqcqc-ThinkCentre-M710q-N000[00m:[01;34m~/workspace/test_execve[00m$ You entered: exit
|
||||
This is a test output.
|
||||
This is a test error output.
|
||||
[DEBUG][PID 3285395] src/execve_interceptor.c:29:execve(): Intercepted execve for: /usr/bin/bash
|
||||
[DEBUG][PID 3285395] src/execve_interceptor.c:30:execve(): argv[0] = bash
|
||||
[DEBUG][PID 3285395] src/config.c:114:load_config_if_needed(): Creating shared memory for config data
|
||||
[DEBUG][PID 3285395] src/config.c:127:load_config_if_needed(): Loading config file for the first time
|
||||
[DEBUG][PID 3285395] src/config.c:17:load_config_to_shm(): Loading configuration from /tmp/exec_hook/config/execve_rules.json to shared memory
|
||||
[DEBUG][PID 3285395] src/config.c:89:load_config_to_shm(): Loaded 3 rules to shared memory
|
||||
[DEBUG][PID 3285395] src/execve_interceptor.c:48:execve(): Current Config rule count : 3
|
||||
[DEBUG][PID 3285395] src/logging.c:21:write_log(): Writing exec log for command: /usr/bin/bash
|
||||
[DEBUG][PID 3285395] src/logging.c:154:duplicate_output_to_log(): Signal handler for SIGINT installed.
|
||||
[DEBUG][PID 3286125] src/logging.c:125:duplicate_output_to_log(): Child process 3286125: stdout is /dev/pts/6
|
||||
[DEBUG][PID 3286126] src/execve_interceptor.c:29:execve(): Intercepted execve for: /usr/bin/lesspipe
|
||||
[DEBUG][PID 3286126] src/execve_interceptor.c:30:execve(): argv[0] = lesspipe
|
||||
[DEBUG][PID 3286126] src/config.c:114:load_config_if_needed(): Creating shared memory for config data
|
||||
[DEBUG][PID 3286126] src/config.c:127:load_config_if_needed(): Loading config file for the first time
|
||||
[DEBUG][PID 3286126] src/config.c:17:load_config_to_shm(): Loading configuration from /tmp/exec_hook/config/execve_rules.json to shared memory
|
||||
[DEBUG][PID 3286126] src/config.c:89:load_config_to_shm(): Loaded 3 rules to shared memory
|
||||
[DEBUG][PID 3286126] src/execve_interceptor.c:48:execve(): Current Config rule count : 3
|
||||
[DEBUG][PID 3286126] src/logging.c:21:write_log(): Writing exec log for command: /usr/bin/lesspipe
|
||||
[DEBUG][PID 3286126] src/logging.c:154:duplicate_output_to_log(): Signal handler for SIGINT installed.
|
||||
[DEBUG][PID 3286126] src/logging.c:236:duplicate_output_to_log(): Child process exited normally
|
||||
[DEBUG][PID 3286126] src/init_cleanup.c:23:cleanup_shared_memory(): execve_intercept library unloaded.
|
||||
[DEBUG][PID 3286126] src/init_cleanup.c:25:cleanup_shared_memory(): Log file: ./logs/execve.log
|
||||
[DEBUG][PID 3286126] src/init_cleanup.c:26:cleanup_shared_memory(): Log out file: ./logs/execve_out.log
|
||||
[DEBUG][PID 3286126] src/init_cleanup.c:27:cleanup_shared_memory(): Config file: /tmp/exec_hook/config/execve_rules.json
|
||||
[DEBUG][PID 3286126] src/init_cleanup.c:28:cleanup_shared_memory(): Shared memory ID: 2
|
||||
[DEBUG][PID 3286126] src/init_cleanup.c:30:cleanup_shared_memory(): Cleaning up shared memory.
|
||||
/tmp/exec_hook/intercept.so(print_stacktrace+0x23)[0x73d8544b91a5]
|
||||
/tmp/exec_hook/intercept.so(cleanup_shared_memory+0x210)[0x73d8544b99e0]
|
||||
/lib64/ld-linux-x86-64.so.2(+0x624e)[0x73d8544c724e]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(+0x45495)[0x73d85428f495]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(on_exit+0x0)[0x73d85428f610]
|
||||
/tmp/exec_hook/intercept.so(duplicate_output_to_log+0x623)[0x73d8544ba34c]
|
||||
/tmp/exec_hook/intercept.so(execve+0x5e4)[0x73d8544b97a8]
|
||||
bash(shell_execve+0x36)[0x5e60732eca46]
|
||||
bash(+0x5b8e7)[0x5e60732f38e7]
|
||||
bash(+0x4b993)[0x5e60732e3993]
|
||||
bash(execute_command_internal+0xf1d)[0x5e60732e5b5d]
|
||||
bash(parse_and_execute+0x6c8)[0x5e60733464e8]
|
||||
bash(command_substitute+0xa98)[0x5e607330e938]
|
||||
bash(+0x780a2)[0x5e60733100a2]
|
||||
bash(+0x81d58)[0x5e6073319d58]
|
||||
bash(+0x83277)[0x5e607331b277]
|
||||
bash(+0x87df9)[0x5e607331fdf9]
|
||||
bash(+0x4bf8f)[0x5e60732e3f8f]
|
||||
bash(execute_command_internal+0xf1d)[0x5e60732e5b5d]
|
||||
bash(execute_command+0xc8)[0x5e60732e81b8]
|
||||
bash(execute_command_internal+0x343b)[0x5e60732e807b]
|
||||
bash(parse_and_execute+0x6c8)[0x5e60733464e8]
|
||||
bash(+0xaf1c6)[0x5e60733471c6]
|
||||
bash(maybe_execute_file+0x2e)[0x5e607334759e]
|
||||
bash(main+0x1a30)[0x5e60732cadb0]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(+0x29d90)[0x73d854273d90]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80)[0x73d854273e40]
|
||||
bash(_start+0x25)[0x5e60732caf15]
|
||||
bash: eval: 行 31: 未预期的记号 "(" 附近有语法错误
|
||||
bash: eval: 行 31: `[DEBUG][PID 3286127] src/logging.c:125:duplicate_output_to_log(): Child process 3286127: stdout is /dev/pts/7
'
|
||||
[DEBUG][PID 3286131] src/execve_interceptor.c:29:execve(): Intercepted execve for: /usr/bin/dircolors
|
||||
[DEBUG][PID 3286131] src/execve_interceptor.c:30:execve(): argv[0] = dircolors
|
||||
[DEBUG][PID 3286131] src/config.c:114:load_config_if_needed(): Creating shared memory for config data
|
||||
[DEBUG][PID 3286131] src/config.c:127:load_config_if_needed(): Loading config file for the first time
|
||||
[DEBUG][PID 3286131] src/config.c:17:load_config_to_shm(): Loading configuration from /tmp/exec_hook/config/execve_rules.json to shared memory
|
||||
[DEBUG][PID 3286131] src/config.c:89:load_config_to_shm(): Loaded 3 rules to shared memory
|
||||
[DEBUG][PID 3286131] src/execve_interceptor.c:48:execve(): Current Config rule count : 3
|
||||
[DEBUG][PID 3286131] src/logging.c:21:write_log(): Writing exec log for command: /usr/bin/dircolors
|
||||
[DEBUG][PID 3286131] src/logging.c:154:duplicate_output_to_log(): Signal handler for SIGINT installed.
|
||||
[DEBUG][PID 3286131] src/logging.c:236:duplicate_output_to_log(): Child process exited normally
|
||||
[DEBUG][PID 3286131] src/init_cleanup.c:23:cleanup_shared_memory(): execve_intercept library unloaded.
|
||||
[DEBUG][PID 3286131] src/init_cleanup.c:25:cleanup_shared_memory(): Log file: ./logs/execve.log
|
||||
[DEBUG][PID 3286131] src/init_cleanup.c:26:cleanup_shared_memory(): Log out file: ./logs/execve_out.log
|
||||
[DEBUG][PID 3286131] src/init_cleanup.c:27:cleanup_shared_memory(): Config file: /tmp/exec_hook/config/execve_rules.json
|
||||
[DEBUG][PID 3286131] src/init_cleanup.c:28:cleanup_shared_memory(): Shared memory ID: 2
|
||||
[DEBUG][PID 3286131] src/init_cleanup.c:30:cleanup_shared_memory(): Cleaning up shared memory.
|
||||
/tmp/exec_hook/intercept.so(print_stacktrace+0x23)[0x73d8544b91a5]
|
||||
/tmp/exec_hook/intercept.so(cleanup_shared_memory+0x210)[0x73d8544b99e0]
|
||||
/lib64/ld-linux-x86-64.so.2(+0x624e)[0x73d8544c724e]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(+0x45495)[0x73d85428f495]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(on_exit+0x0)[0x73d85428f610]
|
||||
/tmp/exec_hook/intercept.so(duplicate_output_to_log+0x623)[0x73d8544ba34c]
|
||||
/tmp/exec_hook/intercept.so(execve+0x5e4)[0x73d8544b97a8]
|
||||
bash(shell_execve+0x36)[0x5e60732eca46]
|
||||
bash(+0x5b8e7)[0x5e60732f38e7]
|
||||
bash(+0x4b993)[0x5e60732e3993]
|
||||
bash(execute_command_internal+0xf1d)[0x5e60732e5b5d]
|
||||
bash(parse_and_execute+0x6c8)[0x5e60733464e8]
|
||||
bash(command_substitute+0xa98)[0x5e607330e938]
|
||||
bash(+0x780a2)[0x5e60733100a2]
|
||||
bash(+0x81d58)[0x5e6073319d58]
|
||||
bash(+0x83277)[0x5e607331b277]
|
||||
bash(+0x87df9)[0x5e607331fdf9]
|
||||
bash(+0x4bf8f)[0x5e60732e3f8f]
|
||||
bash(execute_command_internal+0xf1d)[0x5e60732e5b5d]
|
||||
bash(execute_command+0xc8)[0x5e60732e81b8]
|
||||
bash(execute_command_internal+0x343b)[0x5e60732e807b]
|
||||
bash(execute_command+0xc8)[0x5e60732e81b8]
|
||||
bash(execute_command_internal+0x1d8e)[0x5e60732e69ce]
|
||||
bash(execute_command+0xc8)[0x5e60732e81b8]
|
||||
bash(execute_command_internal+0x1d8e)[0x5e60732e69ce]
|
||||
bash(execute_command+0xc8)[0x5e60732e81b8]
|
||||
bash(execute_command_internal+0x1d8e)[0x5e60732e69ce]
|
||||
bash(execute_command+0xc8)[0x5e60732e81b8]
|
||||
bash(execute_command_internal+0x1d8e)[0x5e60732e69ce]
|
||||
bash(execute_command+0xc8)[0x5e60732e81b8]
|
||||
bash(execute_command_internal+0x108a)[0x5e60732e5cca]
|
||||
bash(parse_and_execute+0x6c8)[0x5e60733464e8]
|
||||
bash(+0xaf1c6)[0x5e60733471c6]
|
||||
bash(maybe_execute_file+0x2e)[0x5e607334759e]
|
||||
bash(main+0x1a30)[0x5e60732cadb0]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(+0x29d90)[0x73d854273d90]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80)[0x73d854273e40]
|
||||
bash(_start+0x25)[0x5e60732caf15]
|
||||
bash: eval: 行 77: 未预期的记号 "(" 附近有语法错误
|
||||
bash: eval: 行 77: `[DEBUG][PID 3286132] src/logging.c:125:duplicate_output_to_log(): Child process 3286132: stdout is /dev/pts/7
'
|
||||
[?2004h]0;qcqcqc@qcqcqc-ThinkCentre-M710q-N000: ~/workspace/test_execve[01;32mqcqcqc@qcqcqc-ThinkCentre-M710q-N000[00m:[01;34m~/workspace/test_execve[00m$
|
||||
|
|
@ -18,12 +18,23 @@
|
|||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "struct.h"
|
||||
|
||||
#define CONFIG_FILE "/tmp/exec_hook/config/execve_rules.json"
|
||||
#define COMMAND_NOT_FOUND "/usr/lib/command-not-found"
|
||||
|
||||
#ifdef DEBUG //如果是debug模式,在本地目录生成log,方便debug
|
||||
|
||||
#define LOG_FILE "./logs/execve.log"
|
||||
#define LOG_OUT_FILE "./logs/execve_out.log"
|
||||
|
||||
#else
|
||||
|
||||
#define LOG_FILE "/tmp/exec_hook/logs/execve.log"
|
||||
#define LOG_OUT_FILE "/tmp/exec_hook/logs/execve_out.log"
|
||||
#define COMMAND_NOT_FOUND "/usr/lib/command-not-found"
|
||||
|
||||
#endif
|
||||
|
||||
#define ANSI_COLOR_RED "\033[31m"
|
||||
#define ANSI_COLOR_YELLOW "\033[33m"
|
||||
|
|
@ -37,4 +48,4 @@ extern int shm_id;
|
|||
extern time_t last_modified_time;
|
||||
// extern int is_initialized;
|
||||
|
||||
#endif // EXEC_HOOK_H
|
||||
#endif // EXEC_HOOK_H
|
||||
|
|
@ -23,84 +23,110 @@ time_t last_modified_time = 0;
|
|||
orig_execve_type orig_execve = NULL;
|
||||
|
||||
int execve(const char *filename, char *const argv[], char *const envp[]) {
|
||||
// if (!is_initialized) {
|
||||
// initialize();
|
||||
// }
|
||||
DEBUG_LOG("Intercepted execve for: %s", filename);
|
||||
DEBUG_LOG("argv[0] = %s", argv[0]);
|
||||
// if (!is_initialized) {
|
||||
// initialize();
|
||||
// }
|
||||
DEBUG_LOG("Intercepted execve for: %s", filename);
|
||||
DEBUG_LOG("argv[0] = %s", argv[0]);
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
// Load configuration (only if needed)
|
||||
load_config_if_needed();
|
||||
// Load configuration (only if needed)
|
||||
load_config_if_needed();
|
||||
|
||||
// Intercept only when execve is called from a shell terminal
|
||||
if (!is_terminal_shell()) {
|
||||
DEBUG_LOG("Not a terminal shell, bypassing interception.");
|
||||
return orig_execve(filename, argv, envp);
|
||||
}
|
||||
// Intercept only when execve is called from a shell terminal
|
||||
if (!is_terminal_shell()) {
|
||||
DEBUG_LOG("Not a terminal shell, bypassing interception.");
|
||||
return orig_execve(filename, argv, envp);
|
||||
}
|
||||
|
||||
// Current configuration information
|
||||
DEBUG_LOG("Current Config rule count : %d", shared_config->rule_count);
|
||||
// Current configuration information
|
||||
DEBUG_LOG("Current Config rule count : %d", shared_config->rule_count);
|
||||
|
||||
// If shared memory was not successfully loaded, execute directly
|
||||
if (shared_config == NULL) {
|
||||
DEBUG_LOG("Shared memory not initialized, bypassing interception.");
|
||||
return orig_execve(filename, argv, envp);
|
||||
}
|
||||
// If shared memory was not successfully loaded, execute directly
|
||||
if (shared_config == NULL) {
|
||||
DEBUG_LOG("Shared memory not initialized, bypassing interception.");
|
||||
return orig_execve(filename, argv, envp);
|
||||
}
|
||||
|
||||
// If the feature is disabled, execute directly
|
||||
if (!shared_config->enabled) {
|
||||
DEBUG_LOG("Not enabled.");
|
||||
return orig_execve(filename, argv, envp);
|
||||
}
|
||||
// If the feature is disabled, execute directly
|
||||
if (!shared_config->enabled) {
|
||||
DEBUG_LOG("Not enabled.");
|
||||
return orig_execve(filename, argv, envp);
|
||||
}
|
||||
|
||||
write_log(filename, argv);
|
||||
write_log(filename, argv);
|
||||
|
||||
const char *basename = argv[0];
|
||||
if (strcmp(filename, COMMAND_NOT_FOUND) == 0 && argv[2]) {
|
||||
basename = argv[2];
|
||||
}
|
||||
const char *basename = argv[0];
|
||||
if (strcmp(filename, COMMAND_NOT_FOUND) == 0 && argv[2]) {
|
||||
basename = argv[2];
|
||||
}
|
||||
|
||||
// Special handling for commands executed via shell.posix
|
||||
// Execute directly, without rule matching and output redirection
|
||||
if (argv[1] != NULL && strcmp(argv[1], "shell.posix") == 0) {
|
||||
return orig_execve(filename, argv, envp);
|
||||
}
|
||||
// Special handling for commands executed via shell.posix
|
||||
// Execute directly, without rule matching and output redirection
|
||||
if (argv[1] != NULL && strcmp(argv[1], "shell.posix") == 0) {
|
||||
return orig_execve(filename, argv, envp);
|
||||
}
|
||||
|
||||
for (int i = 0; i < shared_config->rule_count; i++) {
|
||||
if (strcmp(basename, shared_config->rules[i].cmd) == 0 &&
|
||||
args_match(argv, &shared_config->rules[i])) {
|
||||
DEBUG_LOG("Rule matched: %s (type: %s)",
|
||||
shared_config->rules[i].cmd,
|
||||
shared_config->rules[i].type);
|
||||
if (strcmp(shared_config->rules[i].type, "warn") == 0) {
|
||||
printf(ANSI_COLOR_YELLOW "[Warning] %s\n" ANSI_COLOR_RESET,
|
||||
shared_config->rules[i].msg);
|
||||
printf("按下 'Y' 继续执行, 或按任意键取消: ");
|
||||
char input = getchar();
|
||||
if (input != 'Y' && input != 'y') {
|
||||
printf("\nExecution cancelled.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
// return -1;
|
||||
}
|
||||
printf("\nContinuing execution...\n");
|
||||
} else if (strcmp(shared_config->rules[i].type, "error") == 0) {
|
||||
printf(ANSI_COLOR_RED "[Error] %s" ANSI_COLOR_RESET "\n",
|
||||
shared_config->rules[i].msg);
|
||||
exit(EXIT_FAILURE);
|
||||
// return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < shared_config->rule_count; i++) {
|
||||
if (strcmp(basename, shared_config->rules[i].cmd) == 0 &&
|
||||
args_match(argv, &shared_config->rules[i])) {
|
||||
DEBUG_LOG("Rule matched: %s (type: %s)",
|
||||
shared_config->rules[i].cmd,
|
||||
shared_config->rules[i].type);
|
||||
if (strcmp(shared_config->rules[i].type, "warn") == 0) {
|
||||
printf(ANSI_COLOR_YELLOW "[Warning] %s\n" ANSI_COLOR_RESET,
|
||||
shared_config->rules[i].msg);
|
||||
printf("按下 'Y' 继续执行, 或按任意键取消: ");
|
||||
char input = getchar();
|
||||
if (input != 'Y' && input != 'y') {
|
||||
printf("\nExecution cancelled.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
// return -1;
|
||||
}
|
||||
printf("\nContinuing execution...\n");
|
||||
} else if (strcmp(shared_config->rules[i].type, "error") == 0) {
|
||||
printf(ANSI_COLOR_RED "[Error] %s" ANSI_COLOR_RESET "\n",
|
||||
shared_config->rules[i].msg);
|
||||
exit(EXIT_FAILURE);
|
||||
// return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Duplicate stdout and stderr to the log file
|
||||
duplicate_output_to_log();
|
||||
// Duplicate stdout and stderr to the log file
|
||||
duplicate_output_to_log();
|
||||
|
||||
return orig_execve(filename, argv, envp);
|
||||
// 移除LD_PRELOAD
|
||||
|
||||
// 计算原环境变量数量
|
||||
size_t env_count = 0;
|
||||
while (envp && envp[env_count]) {
|
||||
env_count++;
|
||||
}
|
||||
|
||||
// 分配新的环境变量数组(最多比原来少一个)
|
||||
char **new_envp = malloc((env_count) * sizeof(char *));
|
||||
if (!new_envp) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 拷贝旧的 envp,跳过 LD_PRELOAD
|
||||
size_t i = 0;
|
||||
for (size_t j = 0; j < env_count; j++) {
|
||||
if (strncmp(envp[j], "LD_PRELOAD=", 11) != 0) {
|
||||
new_envp[i++] = envp[j];
|
||||
}
|
||||
}
|
||||
|
||||
// 确保新数组末尾是 NULL
|
||||
new_envp[i] = NULL;
|
||||
|
||||
return orig_execve(filename, argv, new_envp);
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "exec_hook.h"
|
||||
|
||||
static int log_fd = -1;
|
||||
|
||||
// 原始函数指针
|
||||
static ssize_t (*original_write)(int, const void *, size_t) = NULL;
|
||||
static ssize_t (*orig_writev)(int, const struct iovec *, int) = NULL;
|
||||
static size_t (*orig_fwrite)(const void *, size_t, size_t, FILE *) = NULL;
|
||||
static int (*orig_fflush)(FILE *) = NULL;
|
||||
static int (*orig_puts)(const char *) = NULL;
|
||||
static int (*orig_printf)(const char *, ...) = NULL;
|
||||
static int (*orig_vprintf)(const char *, va_list) = NULL;
|
||||
static int (*orig_vfprintf)(FILE *, const char *, va_list) = NULL;
|
||||
|
||||
void init_hook() {
|
||||
DEBUG_LOG("Initializing write hooks...");
|
||||
|
||||
original_write = dlsym(RTLD_NEXT, "write");
|
||||
orig_writev = dlsym(RTLD_NEXT, "writev");
|
||||
orig_fwrite = dlsym(RTLD_NEXT, "fwrite");
|
||||
orig_fflush = dlsym(RTLD_NEXT, "fflush");
|
||||
orig_puts = dlsym(RTLD_NEXT, "puts");
|
||||
orig_printf = dlsym(RTLD_NEXT, "printf");
|
||||
orig_vprintf = dlsym(RTLD_NEXT, "vprintf");
|
||||
orig_vfprintf = dlsym(RTLD_NEXT, "vfprintf");
|
||||
|
||||
log_fd = open(LOG_OUT_FILE, O_WRONLY | O_CREAT | O_APPEND, 0644);
|
||||
if (log_fd == -1) {
|
||||
perror("Failed to open log file");
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t write(int fd, const void *buf, size_t count) {
|
||||
DEBUG_LOG("Intercepted write to fd %d", fd);
|
||||
ssize_t result = original_write(fd, buf, count);
|
||||
|
||||
if (log_fd != -1 && (fd == STDOUT_FILENO || fd == STDERR_FILENO) && fd != log_fd) {
|
||||
original_write(log_fd, buf, count);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t writev(int fd, const struct iovec *iov, int iovcnt) {
|
||||
DEBUG_LOG("Intercepted writev to fd %d", fd);
|
||||
ssize_t result = orig_writev(fd, iov, iovcnt);
|
||||
|
||||
if (log_fd != -1 && (fd == STDOUT_FILENO || fd == STDERR_FILENO) && fd != log_fd) {
|
||||
for (int i = 0; i < iovcnt; ++i) {
|
||||
write(log_fd, iov[i].iov_base, iov[i].iov_len);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) {
|
||||
DEBUG_LOG("Intercepted fwrite to stream %p", stream);
|
||||
size_t result = orig_fwrite(ptr, size, nmemb, stream);
|
||||
int fd = fileno(stream);
|
||||
if (log_fd != -1 && (fd == STDOUT_FILENO || fd == STDERR_FILENO)) {
|
||||
write(log_fd, ptr, size * nmemb);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int puts(const char *s) {
|
||||
DEBUG_LOG("Intercepted puts: %s", s);
|
||||
int result = orig_puts(s);
|
||||
if (log_fd != -1) {
|
||||
write(log_fd, s, strlen(s));
|
||||
write(log_fd, "\n", 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int printf(const char *format, ...) {
|
||||
DEBUG_LOG("Intercepted printf: %s", format);
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int result = orig_vprintf(format, args);
|
||||
va_end(args);
|
||||
|
||||
// 再次获取 args 写入日志
|
||||
va_start(args, format);
|
||||
if (log_fd != -1) {
|
||||
char buffer[4096];
|
||||
int len = vsnprintf(buffer, sizeof(buffer), format, args);
|
||||
if (len > 0) {
|
||||
write(log_fd, buffer, len);
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
int vprintf(const char *format, va_list args) {
|
||||
DEBUG_LOG("Intercepted vprintf: %s", format);
|
||||
int result = orig_vprintf(format, args);
|
||||
if (log_fd != -1) {
|
||||
char buffer[4096];
|
||||
va_list args_copy;
|
||||
va_copy(args_copy, args);
|
||||
int len = vsnprintf(buffer, sizeof(buffer), format, args_copy);
|
||||
va_end(args_copy);
|
||||
if (len > 0) {
|
||||
write(log_fd, buffer, len);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int vfprintf(FILE *stream, const char *format, va_list args) {
|
||||
DEBUG_LOG("Intercepted vfprintf to stream %p: %s", stream, format);
|
||||
int result = orig_vfprintf(stream, format, args);
|
||||
|
||||
int fd = fileno(stream);
|
||||
if (log_fd != -1 && (fd == STDOUT_FILENO || fd == STDERR_FILENO)) {
|
||||
va_list args_copy;
|
||||
va_copy(args_copy, args);
|
||||
char buffer[4096];
|
||||
int len = vsnprintf(buffer, sizeof(buffer), format, args_copy);
|
||||
va_end(args_copy);
|
||||
if (len > 0) {
|
||||
write(log_fd, buffer, len);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int fflush(FILE *stream) {
|
||||
DEBUG_LOG("Intercepted fflush to stream %p", stream);
|
||||
return orig_fflush(stream);
|
||||
}
|
||||
|
||||
__attribute__((constructor)) void init() {
|
||||
DEBUG_LOG("Write hook library loaded.");
|
||||
init_hook();
|
||||
}
|
||||
|
||||
__attribute__((destructor)) void cleanup() {
|
||||
if (log_fd != -1) {
|
||||
close(log_fd);
|
||||
log_fd = -1;
|
||||
}
|
||||
DEBUG_LOG("Write hook library unloaded.");
|
||||
}
|
||||
|
|
@ -35,9 +35,9 @@ __attribute__((destructor)) void cleanup_shared_memory() {
|
|||
shared_config = NULL;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
print_stacktrace();
|
||||
// print_stacktrace();
|
||||
#endif
|
||||
// Note: We don't delete the shared memory segment here, as it might be
|
||||
// used by other processes. A separate mechanism would be needed to manage
|
||||
// the lifecycle of the shared memory if deletion is required.
|
||||
}
|
||||
}
|
||||
|
|
|
|||
304
src/logging.c
304
src/logging.c
|
|
@ -1,100 +1,262 @@
|
|||
#include "logging.h"
|
||||
#include "exec_hook.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h> // shutdown()
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "exec_hook.h"
|
||||
|
||||
// Write log
|
||||
void write_log(const char *filename, char *const argv[]) {
|
||||
DEBUG_LOG("Writing exec log for command: %s", filename);
|
||||
time_t now;
|
||||
time(&now);
|
||||
DEBUG_LOG("Writing exec log for command: %s", filename);
|
||||
time_t now;
|
||||
time(&now);
|
||||
|
||||
FILE *log = fopen(LOG_FILE, "a");
|
||||
if (!log) return;
|
||||
// Get the directory part of the log file path
|
||||
char *log_file_path =
|
||||
strdup(LOG_FILE); // Duplicate string as dirname might modify it
|
||||
if (!log_file_path) {
|
||||
perror("strdup failed");
|
||||
return;
|
||||
}
|
||||
char *log_dir = dirname(log_file_path);
|
||||
if (!log_dir) {
|
||||
perror("dirname failed");
|
||||
free(log_file_path);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(log, "[%s] Command: %s\n", ctime(&now), filename);
|
||||
// Check if the directory exists and is writable
|
||||
if (access(log_dir, W_OK) != 0) {
|
||||
if (errno == ENOENT) {
|
||||
DEBUG_LOG("Log directory '%s' does not exist, creating it...",
|
||||
log_dir);
|
||||
// Create the directory with appropriate permissions (e.g., 0755)
|
||||
if (mkdir(log_dir, 0755) == -1) {
|
||||
perror("mkdir failed");
|
||||
free(log_file_path);
|
||||
return;
|
||||
}
|
||||
DEBUG_LOG("Log directory '%s' created successfully.", log_dir);
|
||||
} else {
|
||||
perror("access failed for log directory");
|
||||
free(log_file_path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
free(log_file_path); // Free the duplicated string
|
||||
|
||||
for (int i = 0; argv[i]; i++) {
|
||||
fprintf(log, "arg[%d]: %s\n", i, argv[i]);
|
||||
}
|
||||
FILE *log = fopen(LOG_FILE, "a");
|
||||
if (!log) {
|
||||
perror("fopen failed for log file");
|
||||
return;
|
||||
}
|
||||
|
||||
fclose(log);
|
||||
fprintf(log, "[%s] Command: %s\n", ctime(&now), filename);
|
||||
|
||||
for (int i = 0; argv[i]; i++) {
|
||||
fprintf(log, "arg[%d]: %s\n", i, argv[i]);
|
||||
}
|
||||
|
||||
fclose(log);
|
||||
}
|
||||
|
||||
// Duplicate stdout/stderr to log file, while preserving terminal colors
|
||||
// 全局变量记录子进程 PID
|
||||
static pid_t g_child_pid = -1;
|
||||
|
||||
// 信号处理器:接收到 SIGINT(Ctrl+C)时,将其转发给子进程
|
||||
void handle_sigint(int sig) {
|
||||
if (g_child_pid > 0) {
|
||||
kill(g_child_pid, sig); // 向子进程发送 SIGINT
|
||||
}
|
||||
DEBUG_LOG("Received SIGINT, forwarded to child process %d", g_child_pid);
|
||||
exit(EXIT_FAILURE);
|
||||
// return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 本 hook 函数在 execve() 之前调用,
|
||||
* 利用 forkpty() 创建伪终端、fork 出子进程,
|
||||
* 子进程返回供后续调用 execve() 替换映像执行具体命令,
|
||||
* 父进程负责转发 STDIN 数据给伪终端,同时把伪终端输出写到 STDOUT 和日志文件。
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
int master_fd;
|
||||
// forkpty 创建伪终端并 fork 子进程
|
||||
pid_t pid = forkpty(&master_fd, NULL, NULL, NULL);
|
||||
if (pid < 0) {
|
||||
perror("forkpty failed");
|
||||
close(log_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
int master_fd, slave_fd;
|
||||
if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) == -1) {
|
||||
perror("openpty failed");
|
||||
close(log_fd);
|
||||
return;
|
||||
}
|
||||
if (pid == 0) {
|
||||
// 关闭 ECHO,避免重复显示输入字符
|
||||
struct termios ts;
|
||||
if (tcgetattr(STDIN_FILENO, &ts) == 0) {
|
||||
ts.c_lflag &= ~ECHO;
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &ts);
|
||||
}
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == -1) {
|
||||
perror("fork failed");
|
||||
close(log_fd);
|
||||
close(master_fd);
|
||||
close(slave_fd);
|
||||
return;
|
||||
}
|
||||
return; // execve 之后替换为目标程序
|
||||
}
|
||||
|
||||
if (pid == 0) { // Child process
|
||||
close(master_fd);
|
||||
// // 把父进程的输出改到/dev/null
|
||||
// int dev_null_fd = open("/dev/null", O_WRONLY);
|
||||
// if (dev_null_fd >= 0) {
|
||||
// dup2(dev_null_fd, STDOUT_FILENO);
|
||||
// dup2(dev_null_fd, STDERR_FILENO);
|
||||
// if (dev_null_fd > STDERR_FILENO) close(dev_null_fd);
|
||||
// }
|
||||
|
||||
// Connect slave_fd to standard input/output/error
|
||||
dup2(slave_fd, STDIN_FILENO);
|
||||
dup2(slave_fd, STDOUT_FILENO);
|
||||
dup2(slave_fd, STDERR_FILENO);
|
||||
close(slave_fd);
|
||||
// 父进程
|
||||
g_child_pid = pid;
|
||||
|
||||
// Child process does not output, only keeps the environment for execve
|
||||
return; // Will be replaced by the original execve call
|
||||
}
|
||||
// 安装 SIGINT 处理器
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = handle_sigint;
|
||||
sa.sa_flags = 0;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
if (sigaction(SIGINT, &sa, NULL) < 0) {
|
||||
perror("sigaction failed");
|
||||
close(log_fd);
|
||||
close(master_fd);
|
||||
return;
|
||||
}
|
||||
DEBUG_LOG("Signal handler for SIGINT installed.");
|
||||
|
||||
// Parent process (controller): read from master_fd and write to stdout + log
|
||||
close(slave_fd);
|
||||
// 父进程:负责 I/O 转发(日志记录与输出)
|
||||
char buffer[1024];
|
||||
ssize_t n;
|
||||
fd_set read_fds;
|
||||
int stdin_eof = 0; // 标识是否检测到 STDIN EOF
|
||||
int status;
|
||||
int max_fd = (master_fd > STDIN_FILENO) ? master_fd : STDIN_FILENO;
|
||||
|
||||
// Ignore child process exit signal
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
while (1) {
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(master_fd, &read_fds);
|
||||
if (!stdin_eof) {
|
||||
FD_SET(STDIN_FILENO, &read_fds);
|
||||
} else {
|
||||
DEBUG_LOG("STDIN EOF detected, not monitoring STDIN");
|
||||
}
|
||||
|
||||
char buffer[1024];
|
||||
ssize_t n;
|
||||
int has_error = 0;
|
||||
int ret = select(max_fd + 1, &read_fds, NULL, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
perror("select failed");
|
||||
break;
|
||||
}
|
||||
|
||||
while ((n = read(master_fd, buffer, sizeof(buffer))) > 0) {
|
||||
// Check for errors
|
||||
if (memmem(buffer, n, "error", 5) || memmem(buffer, n, "Error", 5) ||
|
||||
memmem(buffer, n, "ERROR", 5)) {
|
||||
has_error = 1;
|
||||
}
|
||||
// 若有用户输入,则转发到伪终端
|
||||
if (!stdin_eof && FD_ISSET(STDIN_FILENO, &read_fds)) {
|
||||
n = read(STDIN_FILENO, buffer, sizeof(buffer));
|
||||
if (n > 0) {
|
||||
if (write(master_fd, buffer, n) < 0) {
|
||||
perror("Failed to write user input to pty");
|
||||
}
|
||||
} else if (n == 0) {
|
||||
// 检测到 STDIN EOF:关闭写端,后续不再转发用户输入
|
||||
stdin_eof = 1;
|
||||
shutdown(master_fd, SHUT_WR);
|
||||
}
|
||||
}
|
||||
|
||||
// Write to log
|
||||
if (write(log_fd, buffer, n) == -1) {
|
||||
perror("Failed to write to log file");
|
||||
}
|
||||
}
|
||||
// 若伪终端有输出,则转发到 STDOUT 并写入日志文件
|
||||
if (FD_ISSET(master_fd, &read_fds)) {
|
||||
// n = read(master_fd, buffer, sizeof(buffer));
|
||||
// if (n > 0) {
|
||||
// if (write(STDOUT_FILENO, buffer, n) < 0) {
|
||||
// perror("Failed to write to stdout");
|
||||
// }
|
||||
// if (write(log_fd, buffer, n) < 0) {
|
||||
// perror("Failed to write to log file");
|
||||
// }
|
||||
// } else if (n == 0) {
|
||||
char *line_start = buffer;
|
||||
ssize_t n = read(master_fd, buffer, sizeof(buffer) - 1);
|
||||
if (n > 0) {
|
||||
buffer[n] = '\0'; // 确保字符串结束
|
||||
|
||||
if (has_error) {
|
||||
printf("\n检测到命令执行出错,已经上报北冥论坛~ \n");
|
||||
fflush(stdout);
|
||||
}
|
||||
// 按行处理输出
|
||||
while (line_start < buffer + n) {
|
||||
char *line_end = strchr(line_start, '\n');
|
||||
if (!line_end) {
|
||||
line_end = buffer + n; // 最后一行可能没有换行符
|
||||
} else {
|
||||
line_end++; // 包含换行符
|
||||
}
|
||||
|
||||
close(master_fd);
|
||||
close(log_fd);
|
||||
size_t line_len = line_end - line_start;
|
||||
|
||||
// 写入标准输出
|
||||
if (write(STDOUT_FILENO, line_start, line_len) < 0) {
|
||||
perror("Failed to write to stdout");
|
||||
}
|
||||
|
||||
// 写入日志文件
|
||||
if (write(log_fd, line_start, line_len) < 0) {
|
||||
perror("Failed to write to log file");
|
||||
}
|
||||
|
||||
line_start = line_end;
|
||||
}
|
||||
} else if (n == 0) {
|
||||
/*
|
||||
* 当伪终端返回 0 时,
|
||||
* 通过 waitpid(pid, …, WNOHANG) 检查子进程是否真的退出,
|
||||
* 如果 bash 仍活跃,则可能是暂时无数据,不退出转发循环。
|
||||
*/
|
||||
pid_t ret_pid = waitpid(pid, &status, WNOHANG);
|
||||
if (ret_pid == 0) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (n < 0) {
|
||||
if (errno == EIO) {
|
||||
// 伪终端关闭,退出循环
|
||||
break;
|
||||
} else {
|
||||
perror("Failed to read from pty");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end while 循环
|
||||
|
||||
// 等待子进程完全退出,并报告异常状态(如果有)
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
perror("waitpid failed");
|
||||
} else {
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
int status = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
|
||||
DEBUG_LOG("Child process exited abnormally (status: %d)", status);
|
||||
} else {
|
||||
DEBUG_LOG("Child process exited normally");
|
||||
}
|
||||
}
|
||||
|
||||
close(master_fd);
|
||||
close(log_fd);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,129 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pty.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
volatile sig_atomic_t terminate = 0;
|
||||
|
||||
void sig_handler(int sig) {
|
||||
terminate = 1;
|
||||
}
|
||||
|
||||
void createDup() {
|
||||
int master_fd;
|
||||
pid_t pid;
|
||||
|
||||
signal(SIGINT, sig_handler);
|
||||
signal(SIGCHLD, sig_handler);
|
||||
|
||||
pid = forkpty(&master_fd, NULL, NULL, NULL);
|
||||
if (pid < 0) {
|
||||
perror("forkpty");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
// 子进程设置:如果父进程退出,自动收到 SIGTERM
|
||||
prctl(PR_SET_PDEATHSIG, SIGTERM);
|
||||
return;
|
||||
} else {
|
||||
char buffer[1024];
|
||||
ssize_t num_read;
|
||||
|
||||
int output_fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (output_fd < 0) {
|
||||
perror("open output.txt");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
fd_set read_fds;
|
||||
int max_fd = (STDIN_FILENO > master_fd ? STDIN_FILENO : master_fd) + 1;
|
||||
|
||||
while (!terminate) {
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(STDIN_FILENO, &read_fds);
|
||||
FD_SET(master_fd, &read_fds);
|
||||
|
||||
int ret = select(max_fd, &read_fds, NULL, NULL, NULL);
|
||||
if (ret < 0 && errno != EINTR) {
|
||||
perror("select");
|
||||
break;
|
||||
}
|
||||
|
||||
if (terminate) break;
|
||||
|
||||
// 用户输入
|
||||
if (FD_ISSET(STDIN_FILENO, &read_fds)) {
|
||||
num_read = read(STDIN_FILENO, buffer, sizeof(buffer));
|
||||
if (num_read <= 0) break;
|
||||
write(master_fd, buffer, num_read);
|
||||
}
|
||||
|
||||
// 子进程输出
|
||||
if (FD_ISSET(master_fd, &read_fds)) {
|
||||
num_read = read(master_fd, buffer, sizeof(buffer));
|
||||
if (num_read <= 0) break;
|
||||
write(STDOUT_FILENO, buffer, num_read);
|
||||
write(output_fd, buffer, num_read);
|
||||
}
|
||||
}
|
||||
|
||||
kill(pid, SIGTERM); // 通知子进程退出
|
||||
waitpid(pid, NULL, 0);
|
||||
|
||||
close(output_fd);
|
||||
close(master_fd);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
createDup();
|
||||
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
perror("fork");
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (pid == 0) {
|
||||
// 子进程确保在父进程退出时自动结束
|
||||
prctl(PR_SET_PDEATHSIG, SIGTERM);
|
||||
printf("This is the child process.\n");
|
||||
fflush(stdout);
|
||||
} else {
|
||||
printf("This is the parent process.\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
// 测试输入
|
||||
char input[100];
|
||||
printf("Enter something: ");
|
||||
fflush(stdout);
|
||||
if (fgets(input, sizeof(input), stdin) == NULL) exit(0);
|
||||
printf("You entered: %s", input);
|
||||
fflush(stdout);
|
||||
|
||||
// 测试输出
|
||||
printf("This is a test output.\n");
|
||||
fflush(stdout);
|
||||
// 测试错误输出
|
||||
fprintf(stderr, "This is a test error output.\n");
|
||||
fflush(stderr);
|
||||
|
||||
char *const argv[] = {"bash", NULL, NULL};
|
||||
extern char **environ;
|
||||
execve("/usr/bin/bash", argv, environ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
This is the parent process.
|
||||
Enter something: This is the child process.
|
||||
Enter something: 123
|
||||
You entered: 123
|
||||
This is a test output.
|
||||
This is a test error output.
|
||||
[?2004h]0;qcqcqc@qcqcqc-ThinkCentre-M710q-N000: ~/workspace/test_execve/tests[01;32mqcqcqc@qcqcqc-ThinkCentre-M710q-N000[00m:[01;34m~/workspace/test_execve/tests[00m$ You entered: ll
|
||||
This is a test output.
|
||||
This is a test error output.
|
||||
[?2004h]0;qcqcqc@qcqcqc-ThinkCentre-M710q-N000: ~/workspace/test_execve/tests[01;32mqcqcqc@qcqcqc-ThinkCentre-M710q-N000[00m:[01;34m~/workspace/test_execve/tests[00m$ [?2004l
|
||||
exit
|
||||
[?2004l
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main() {
|
||||
const char *msg = "Hello, world!\n";
|
||||
|
||||
// 使用 write 系统调用向标准输出(文件描述符 1)写入数据
|
||||
ssize_t result = write(1, msg, 14);
|
||||
|
||||
if (result == -1) {
|
||||
perror("write failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Successfully wrote %zd bytes.\n", result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue