利用ptrace实现文件读写等系统调用的hook:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/reg.h>
#include <sys/user.h>
#include <unistd.h>
#include <errno.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <memory.h>
#include <sys/uio.h>
#include "util.h"
//#if defined(__x86_64__)
//#define REGX ORIG_RAX * 8
//#else
//#define REGX ORIG_EAX * 4
//#endif
#define RECORD_BEFORE_EXE(a) static bool arrRunRecord[4194500] = { 0 }; \
if (bClean) { \
arrRunRecord[a] = false; \
return; \
} \
if (arrRunRecord[a]) { \
arrRunRecord[a] = false; \
return; \
} \
arrRunRecord[a] = true;
#define RECORD_AFTER_EXE(a) static bool arrRunRecord[4194500] = { 0 }; \
if (bClean) { \
arrRunRecord[a] = false; \
return; \
} \
if (!arrRunRecord[a]) { \
arrRunRecord[a] = true; \
return; \
} \
arrRunRecord[a] = false;
struct i386_user_regs_struct {
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
unsigned int esi;
unsigned int edi;
unsigned int ebp;
unsigned int eax;
unsigned int xds;
unsigned int xes;
unsigned int xfs;
unsigned int xgs;
unsigned int orig_eax;
unsigned int eip;
unsigned int xcs;
unsigned int eflags;
unsigned int esp;
unsigned int xss;
};
typedef union _UN_REGS {
struct user_regs_struct x86_64_r;
struct i386_user_regs_struct i386_r;
} UN_REGS;
typedef struct _PROCESS_INFO {
bool bLinux32;
int nSysCallId;
unsigned long nParam1;
unsigned long nParam2;
unsigned long nParam3;
unsigned long nParam4;
unsigned long nParam5;
unsigned long nParam6;
} ST_PROCESS_INFO;
typedef void(*pSysCallProcFun)(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean);
static pSysCallProcFun g_afuncProcessor64[4000] = { 0 };
static pSysCallProcFun g_afuncProcessor32[4000] = { 0 };
bool g_bArrProcessInfo[4194500] = { 0 };
bool g_bArrProcessLogged[4194500] = { 0 };
long g_nPrograms = 0;
static inline void get_syscall_args(pid_t pid, ST_PROCESS_INFO *pData)
{
struct iovec iov;
UN_REGS regs;
iov.iov_base = ®s;
iov.iov_len = sizeof(regs);
ptrace(PTRACE_GETREGSET, pid, 1, &iov);
if (iov.iov_len == sizeof(i386_user_regs_struct)) {
// 32-bit
pData->bLinux32 = true;
pData->nSysCallId = (unsigned long)((UN_REGS *)iov.iov_base)->i386_r.orig_eax;
pData->nParam1 = (unsigned long)((UN_REGS *)iov.iov_base)->i386_r.ebx;
pData->nParam2 = (unsigned long)((UN_REGS *)iov.iov_base)->i386_r.ecx;
pData->nParam3 = (unsigned long)((UN_REGS *)iov.iov_base)->i386_r.edx;
pData->nParam4 = (unsigned long)((UN_REGS *)iov.iov_base)->i386_r.esi;
pData->nParam5 = (unsigned long)((UN_REGS *)iov.iov_base)->i386_r.edi;
pData->nParam6 = (unsigned long)((UN_REGS *)iov.iov_base)->i386_r.ebp;
}
else {
// 64-bit
pData->bLinux32 = false;
pData->nSysCallId = ((UN_REGS *)iov.iov_base)->x86_64_r.orig_rax;
pData->nParam1 = (unsigned long)((UN_REGS *)iov.iov_base)->x86_64_r.rdi;
pData->nParam2 = (unsigned long)((UN_REGS *)iov.iov_base)->x86_64_r.rsi;
pData->nParam3 = (unsigned long)((UN_REGS *)iov.iov_base)->x86_64_r.rdx;
pData->nParam4 = (unsigned long)((UN_REGS *)iov.iov_base)->x86_64_r.r10;
pData->nParam5 = (unsigned long)((UN_REGS *)iov.iov_base)->x86_64_r.r8;
pData->nParam6 = (unsigned long)((UN_REGS *)iov.iov_base)->x86_64_r.r9;
}
}
static inline void ptrace_continue(pid_t pid, int signum)
{
ptrace(PTRACE_SYSCALL, pid, 0, signum);
}
static inline void ptrace_trace_child(pid_t pid)
{
ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACEEXIT | //PTRACE_O_TRACEEXEC | PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACECLONE | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEFORK);
}
static inline void ptrace_detach(pid_t pid, int signum)
{
ptrace(PTRACE_DETACH, pid, 0, signum);
}
static inline long ptrace_get_child(pid_t pid)
{
long child = 0;
ptrace(PTRACE_GETEVENTMSG, pid, 0, &child); return child;
}
static inline void ptrace_get_regs(pid_t pid, struct user_regs_struct *regs)
{
ptrace(PTRACE_GETREGS, pid, NULL, regs);
}
static inline void record_read_syscall(pid_t pid, int fd)
{
char abs_file[MY_PATH_MAX] = { '\0' };
ssize_t parese_ret = parse_fd_to_filename(abs_file, sizeof(abs_file), fd, pid);
if (parese_ret != -1) {
if (!is_directory(abs_file)) {
print_dep_file("read", abs_file, "Read", pid);
}
}
}
static inline void record_write_syscall(pid_t pid, int fd)
{
char abs_file[MY_PATH_MAX] = { '\0' };
ssize_t parese_ret = parse_fd_to_filename(abs_file, sizeof(abs_file), fd, pid);
if (parese_ret != -1) {
if (!is_directory(abs_file)) {
print_dep_file("write", abs_file, "Write", pid);
}
}
}
static inline void record_read_link(pid_t pid, const char *filename)
{
char abs_file[MY_PATH_MAX];
parse_to_abs_filepath(abs_file, filename, pid);
if (!is_directory(abs_file)) {
print_dep_file("read", abs_file, "Read", pid);
}
}
static inline void record_read_linkat(pid_t pid, int dirfd, const char *filename)
{
char abs_file[MY_PATH_MAX];
parse_to_abs_filepath_with_dirfd(abs_file, dirfd, filename, pid);
if (!is_directory(abs_file)) {
print_dep_file("read", abs_file, "Read", pid);
}
}
static inline void record_mmap_syscall(pid_t pid, int prob, int fd) {
if (prob & PROT_READ) {
char abs_file[MY_PATH_MAX] = { '\0' };
ssize_t parese_ret = parse_fd_to_filename(abs_file, sizeof(abs_file), fd, pid);
if (parese_ret != -1) {
if (!is_directory(abs_file)) {
print_dep_file("read", abs_file, "Read", pid);
}
}
}
//if (prob & PROT_WRITE) {
// char abs_file[MY_PATH_MAX] = { '\0' };
// ssize_t parese_ret = parse_fd_to_filename(abs_file, sizeof(abs_file), fd, pid);
// if (parese_ret != -1) {
// if (!is_directory(abs_file)) {
// print_dep_file("write", abs_file, "Write", pid);
// }
// }
//}
}
static inline void record_rename_syscall(pid_t pid, const char *old, const char *new_name)
{
char abs_old_file[MY_PATH_MAX];
parse_to_abs_filepath(abs_old_file, old, pid);
char abs_new_file[MY_PATH_MAX];
parse_to_abs_filepath(abs_new_file, new_name, pid);
if (!is_directory(abs_new_file)) {
print_rename_file("rename", abs_old_file, abs_new_file, "Rename", pid);
return;
}
print_rename_files_in_dir(abs_new_file, abs_old_file, abs_new_file, pid);
}
static inline void record_renameat_syscall(pid_t pid, int olddirfd, const char *old_name, int newdirfd, const char *new_name)
{
char abs_old_file[MY_PATH_MAX];
parse_to_abs_filepath_with_dirfd(abs_old_file, olddirfd, old_name, pid);
char abs_new_file[MY_PATH_MAX];
parse_to_abs_filepath_with_dirfd(abs_new_file, newdirfd, new_name, pid);
if (!is_directory(abs_new_file)) {
print_rename_file("renameat", abs_old_file, abs_new_file, "Rename", pid);
return;
}
print_rename_files_in_dir(abs_new_file, abs_old_file, abs_new_file, pid);
}
static inline void record_rmdir_syscall(pid_t pid, const char *file_path) {
char abs_file[MY_PATH_MAX] = { 0 };
parse_to_abs_filepath(abs_file,
//print_delete_files_in_dir_by_regex("rmdir", abs_file, pid); return;
}
print_delete_files_in_dir("rmdir", abs_file, abs_file, pid);
}
static inline void record_unlink_syscall(pid_t pid, const char *file_path)
{
char abs_file[MY_PATH_MAX] = { 0 };
parse_to_abs_filepath(abs_file, file_path, pid);
if (!is_directory(abs_file)) {
print_dep_file("unlink", abs_file, "Delete", pid);
//print_delete_files_in_dir_by_regex("unlink", abs_file, pid); return;
}
print_delete_files_in_dir("unlink", abs_file, abs_file, pid);
}
static inline void record_unlinkat_syscall(pid_t pid, int dirfd, const char *file_path)
{
char abs_file[MY_PATH_MAX] = { 0 };
parse_to_abs_filepath_with_dirfd(abs_file, dirfd, file_path, pid);
if (!is_directory(abs_file)) {
print_dep_file("unlinkat", abs_file, "Delete", pid);
//print_delete_files_in_dir_by_regex("unlinkat", abs_file, pid);
return;
}
print_delete_files_in_dir("unlinkat", abs_file, abs_file, pid);
}
static inline void record_process_info(pid_t pid) {
print_dep_file("process", "", "Process", pid);
}
void sys_execve_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_AFTER_EXE(pid);
activate(pid);
record_process_info(pid);
g_bArrProcessLogged[pid] = true;
}
void sys_write_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_BEFORE_EXE(pid);
record_write_syscall(pid, (int)pParam->nParam1);
}
void sys_pwrite64_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_BEFORE_EXE(pid);
record_write_syscall(pid, (int)pParam->nParam1);
}
void sys_writev_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_BEFORE_EXE(pid);
record_write_syscall(pid, (int)pParam->nParam1);
}
void sys_pwritev_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_BEFORE_EXE(pid);
record_write_syscall(pid, (int)pParam->nParam1);
}
void sys_read_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_BEFORE_EXE(pid);
record_read_syscall(pid, (int)pParam->nParam1);
}
void sys_readv_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_BEFORE_EXE(pid);
record_read_syscall(pid, (int)pParam->nParam1);
}
void sys_preadv_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_BEFORE_EXE(pid);
record_read_syscall(pid, (int)pParam->nParam1);
}
void sys_pread64_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_BEFORE_EXE(pid);
record_read_syscall(pid, (int)pParam->nParam1);
}
void sys_readlink_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_BEFORE_EXE(pid);
char file_name[MY_PATH_MAX] = { '\0' };
read_string(pid, pParam->nParam1, file_name);
record_read_link(pid, file_name);
}
void sys_readlinkat_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_BEFORE_EXE(pid);
char file_name[MY_PATH_MAX] = { '\0' };
read_string(pid, pParam->nParam2, file_name);
record_read_linkat(pid, (int)pParam->nParam1, file_name);
}
void sys_mmap_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_BEFORE_EXE(pid);
record_mmap_syscall(pid, pParam->nParam3, pParam->nParam5);
}
void sys_rename_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_AFTER_EXE(pid);
char old_file[MY_PATH_MAX] = { '\0' };
read_string(pid, pParam->nParam1, old_file);
char new_file[MY_PATH_MAX] = { '\0' };
read_string(pid, pParam->nParam2, new_file);
record_rename_syscall(pid, old_file, new_file);
}
void sys_renameat_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_AFTER_EXE(pid);
char old_file[MY_PATH_MAX] = { '\0' };
read_string(pid, pParam->nParam2, old_file);
char new_file[MY_PATH_MAX] = { '\0' };
read_string(pid, pParam->nParam4, new_file);
record_renameat_syscall(pid, pParam->nParam1, old_file, pParam->nParam3, new_file);
}
void sys_rmdir_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_BEFORE_EXE(pid);
char file_path[MY_PATH_MAX] = { '\0' };
read_string(pid, pParam->nParam1, file_path);
record_rmdir_syscall(pid, file_path);
}
void sys_unlink_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_BEFORE_EXE(pid);
char file_path[MY_PATH_MAX] = { '\0' };
read_string(pid, pParam->nParam1, file_path);
record_unlink_syscall(pid, file_path);
}
void sys_unlinkat_processor(ST_PROCESS_INFO *pParam, pid_t pid, bool bClean)
{
RECORD_BEFORE_EXE(pid);
char file_path[MY_PATH_MAX] = { '\0' };
read_string(pid, pParam->nParam2, file_path);
record_unlinkat_syscall(pid, (int)pParam->nParam1, file_path);
}
int main(int argc, char *argv[])
{
if (argc < 3) {
return -1;
}
pid_t pid_fock = 0;
switch (pid_fock = fork()) {
case -1:
break;
case 0:
{
//子进程
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
//execvp(argv[2], &argv[2]);
//execvp(argv[1], &argv[1]);
execlp(argv[1], argv[1], NULL);
break;
}
default:
{
//父进程
int status = 0;
//init(argv[2], argv[1]);
init(argv[1], argv[2]);
g_nPrograms = 0;
g_afuncProcessor64[SYS_execve] = sys_execve_processor;
g_afuncProcessor32[11] = sys_execve_processor;
g_afuncProcessor64[SYS_write] = sys_write_processor;
g_afuncProcessor32[4] = sys_write_processor;
g_afuncProcessor64[SYS_pwrite64] = sys_pwrite64_processor;
g_afuncProcessor32[181] = sys_pwrite64_processor;
g_afuncProcessor64[SYS_writev] = sys_writev_processor;
g_afuncProcessor32[146] = sys_writev_processor;
g_afuncProcessor64[SYS_pwritev] = sys_pwritev_processor;
g_afuncProcessor32[334] = sys_pwritev_processor;
g_afuncProcessor64[SYS_read] = sys_read_processor;
g_afuncProcessor32[3] = sys_read_processor;
g_afuncProcessor64[SYS_readv] = sys_readv_processor;
g_afuncProcessor32[145] = sys_readv_processor;
g_afuncProcessor64[SYS_preadv] = sys_preadv_processor;
g_afuncProcessor32[333] = sys_preadv_processor;
g_afuncProcessor64[SYS_pread64] = sys_pread64_processor;
g_afuncProcessor32[180] = sys_pread64_processor;
g_afuncProcessor64[SYS_readlink] = sys_readlink_processor;
g_afuncProcessor32[85] = sys_readlink_processor;
g_afuncProcessor64[SYS_readlinkat] = sys_readlinkat_processor;
g_afuncProcessor32[305] = sys_readlinkat_processor;
g_afuncProcessor64[SYS_mmap] = sys_mmap_processor;
g_afuncProcessor32[192] = sys_mmap_processor;
g_afuncProcessor64[SYS_rename] = sys_rename_processor;
g_afuncProcessor32[38] = sys_rename_processor;
g_afuncProcessor64[SYS_renameat] = sys_renameat_processor;
g_afuncProcessor32[302] = sys_renameat_processor;
g_afuncProcessor64[SYS_rmdir] = sys_rmdir_processor;
g_afuncProcessor32[40] = sys_rmdir_processor;
g_afuncProcessor64[SYS_unlink] = sys_unlink_processor;
g_afuncProcessor32[10] = sys_unlink_processor;
g_afuncProcessor64[SYS_unlinkat] = sys_unlinkat_processor;
g_afuncProcessor32[301] = sys_unlinkat_processor;
while (true) {
pid_t pid = wait3(&status, __WALL, NULL);
if (pid < 0 || pid >= 4194499) {
continue;
}
if (!g_bArrProcessInfo[pid]) {
g_nPrograms++;
g_bArrProcessInfo[pid] = true;
ptrace_trace_child(pid);
ptrace_continue(pid, 0);
activate(pid);
if (pid_fock == pid) {
record_process_info(pid_fock);
}
}
// process exit
if (WIFEXITED(status) || WIFSIGNALED(status)) {
if (g_bArrProcessInfo[pid])
--g_nPrograms;
g_bArrProcessInfo[pid] = false;
g_bArrProcessLogged[pid] = false;
print_pid_write_record(pid);
remove_useless_rnode_by_pid(pid);
if (g_nPrograms > 0) {
clean(pid);
continue;
}
print_all_write_record();
free_all_data();
printf("Finished!\n");
break;
}
if (WIFSTOPPED(status)) {
unsigned int event = (status >> 16);
unsigned int sig = WSTOPSIG(status);
// trace exit: clean related context
if (event == PTRACE_EVENT_EXIT) {
sys_execve_processor(NULL, pid, true);
sys_write_processor(NULL, pid, true);
sys_pwrite64_processor(NULL, pid, true);
sys_writev_processor(NULL, pid, true);
sys_pwritev_processor(NULL, pid, true);
sys_read_processor(NULL, pid, true);
sys_readv_processor(NULL, pid, true);
sys_preadv_processor(NULL, pid, true);
sys_pread64_processor(NULL, pid, true);
sys_readlink_processor(NULL, pid, true);
sys_readlinkat_processor(NULL, pid, true);
sys_mmap_processor(NULL, pid, true);
sys_rename_processor(NULL, pid, true);
sys_renameat_processor(NULL, pid, true);
sys_rmdir_processor(NULL, pid, true);
sys_unlink_processor(NULL, pid, true);
sys_unlinkat_processor(NULL, pid, true);
if (!g_bArrProcessLogged[pid]) {
record_process_info(pid);
remove_useless_rnode_by_pid(pid);
}
ptrace_continue(pid, 0);
continue;
}
//if ((event == PTRACE_EVENT_FORK)
// || (event == PTRACE_EVENT_VFORK)
// || (event == PTRACE_EVENT_CLONE)
// /*|| (event == PTRACE_EVENT_VFORK_DONE)*/) {
// long child_pid = ptrace_get_child(pid);
// if(child_pid) {
// //activate(child_pid);
// //ptrace_trace_child(child_pid);
// printf("parent: %d child: %d\n", child_pid);
// }
// //ptrace(PTRACE_ATTACH, child_pid, 0, 0);
// //ptrace_continue(child_pid, 0);
// //ptrace_continue(pid, sig);
// //continue;
//}
// other signal, not syscall interrupt
if (0 == (sig & 0x80)) {
if (5 != sig)
ptrace_continue(pid, sig);
else
ptrace_continue(pid, 0);
continue;
}
//printf("%d callid: %d %d\n", pid, stProcessInfo.bLinux32, stProcessInfo.nSysCallId);
ST_PROCESS_INFO stProcessInfo = { 0 };
get_syscall_args(pid, &stProcessInfo);
if (stProcessInfo.nSysCallId >= 0) {
if (!stProcessInfo.bLinux32) {
// 64-bit process
if (g_afuncProcessor64[stProcessInfo.nSysCallId])
g_afuncProcessor64[stProcessInfo.nSysCallId](&stProcessInfo, pid, false);
}
else {
// 32-bit process
if (g_afuncProcessor32[stProcessInfo.nSysCallId])
g_afuncProcessor32[stProcessInfo.nSysCallId](&stProcessInfo, pid, false);
}
}
ptrace_continue(pid, 0);
continue;
}
printf("strange status: %d!\n", status);
ptrace_continue(pid, 0);
}
}
}
return 0;
}