Hook挂钩是一种功能强大的编程技术,可以在不更改原始代码的情况下监视软件行为或扩展功能。 这个想法是拦截某些事件或系统调用,并使用它们来启动您自己的自定义代码。Hook的原理是利用自己创建的动态库相对于系统动态库有优先调用权,也就是在出现同名函数时优先使用自己定义或者封装的库函数,相当于屏蔽了系统自带的库函数。Hook在网络安全,数据采集和系统控制领域使用广泛。
关于文件监控拦截,其实不管是Ring0的LKM开发(系统调用表)还是Ring3这种用户不需要考虑内核的操作思想都是类似的。在open等系统调用前进行劫持,根据用户的需求进行确定,是否继续调用真正的系统调用,是否进行其他操作。
Ring0的内核驱动开发,需要汇编的知识,内核开发复杂难度大,所以本文采用ring3的hook技术(技术不到家T_T)。当然写驱动来进行文件监控更强(看了别人的资料有大佬写了驱动编译到内核实现文件监控模块,他们公司是这么做的)。别人的观点是不管ring0内核hook还是ring3用户hook都不那么完美(有静态编译,强制加载LD_PRELOAD为系统原有动态库等方法阻止),但人家有更好的方法。
关于网络拦截的思路就是确定hook点在connect和accept这两个系统调用,只要hook了这两个系统调用,那么指定IP的来连接或者访问此IP都不能进行。
Hook代码经make得到了动态库libmyfilter.so后,我们需要根据准备使用的范围来确定将新创建的动态库默认加载在哪。
LD_PRELOAD是个环境变量,用于动态库的加载,动态库加载的优先级最高。一般情况下,动态库加载顺序为LD_PRELOAD>LD_LIBRARY_PATH>/etc/ld.so.cache>/lib>/usr/lib。程序中我们经常要调用一些外部库的函数,以open()和execve()为例,如果我们有个自定义这两函数,把它编译成动态库后,通过LD_PRELOAD加载,当程序中调用open函数时,调用的其实是我们自定义的函数(这个其实就是hook啦),下面以一个例子说明。
- //hello.cpp
- #include
- #include
- #include
- #include
- #include
- #include
- using namespace std;
-
- int main(int argc,char *argv[])
- {
- int fd;
- char *args[] = {"", NULL};
-
- if(execve("/bin/date",args,NULL) == -1)
- {
- perror ("execve");
- exit(EXIT_FAILURE);
- }
-
- if(fd=open("/home/ok/test/hookTest/hello.c",O_RDONLY)!=-1)
- {
- fprintf(stdout,"openfile successed!\n");
- }
- else
- {
- fprintf(stderr,"openfile error!\n");
- }
- close(fd);
- return 0;
- }
通过编译和ldd查看,当前依赖的是libc.so.6这个库,通过strace可以查看hello运行时调用的系统调用过程,这里面包括了系统去找各个.so的查找顺序,从这里也可以看出优先级。strace是一个父进程,它会创建一个子进程,子进程就就是对应的应用程序。当然,也可以在程序里面使用ptrace系统调用跟踪函数调用过程。
在.so加载过程中,open --read--mmap--close等是一套过程。
open和openat都是打开文件的系统调用,其主要参数为pathname,为文件打开路径。当传给函数的路径名是绝对路径时,二者无区别.(openat()自动忽略第一个参数dirfd)。当传给函数的是相对路径时,如果openat()函数的第一个参数dirfd是常量AT_FDCWD时,则其后的第二个参数路径名以当前工作目录为基址;否则以dirfd指定的目录文件描述符为基址。目录文件描述符的取得通常分为两步,先用opendir()函数获得对应的DIR结构的目录指针,再使用int dirfd(DIR*)函数将其转换成目录描述符,此时就可以作为openat()函数的第一个参数使用。
- ok@u20:~/test/hookTest$ g++ hello.cpp -o hello
- hello.cpp: In function ‘int main(int, char**)’:
- hello.cpp:12:18: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
- 12 | char *args[] = {"", NULL};
- | ^~
- ok@u20:~/test/hookTest$ ldd hello
- linux-vdso.so.1 (0x00007ffc9ade9000)
- libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007efc9ec88000)
- libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007efc9ea96000)
- libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007efc9e947000)
- /lib64/ld-linux-x86-64.so.2 (0x00007efc9ee89000)
- libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007efc9e92c000)
- ok@u20:~/test/hookTest$ strace
- strace strace-log-merge
- ok@u20:~/test/hookTest$ strace ./hello
- execve("./hello", ["./hello"], 0x7ffe35fc5540 /* 53 vars */) = 0
- brk(NULL) = 0x56516b945000
- arch_prctl(0x3001 /* ARCH_??? */, 0x7fffef521c70) = -1 EINVAL (无效的参数)
- access("/etc/ld.so.preload", R_OK) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "tls/haswell/x86_64/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "tls/haswell/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "tls/x86_64/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "tls/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "haswell/x86_64/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "haswell/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "x86_64/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/tls/haswell/x86_64/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- stat("/usr/local/lib/tls/haswell/x86_64", 0x7fffef520ec0) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/tls/haswell/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- stat("/usr/local/lib/tls/haswell", 0x7fffef520ec0) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/tls/x86_64/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- stat("/usr/local/lib/tls/x86_64", 0x7fffef520ec0) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/tls/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- stat("/usr/local/lib/tls", 0x7fffef520ec0) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/haswell/x86_64/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- stat("/usr/local/lib/haswell/x86_64", 0x7fffef520ec0) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/haswell/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- stat("/usr/local/lib/haswell", 0x7fffef520ec0) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/x86_64/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- stat("/usr/local/lib/x86_64", 0x7fffef520ec0) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- stat("/usr/local/lib", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
- openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
- fstat(3, {st_mode=S_IFREG|0644, st_size=95136, ...}) = 0
- mmap(NULL, 95136, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f97d0ebc000
- close(3) = 0
- openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
- read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\341\t\0\0\0\0\0"..., 832) = 832
- fstat(3, {st_mode=S_IFREG|0644, st_size=1956992, ...}) = 0
- mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f97d0eba000
- mmap(NULL, 1972224, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f97d0cd8000
- mprotect(0x7f97d0d6e000, 1290240, PROT_NONE) = 0
- mmap(0x7f97d0d6e000, 987136, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x96000) = 0x7f97d0d6e000
- mmap(0x7f97d0e5f000, 299008, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x187000) = 0x7f97d0e5f000
- mmap(0x7f97d0ea9000, 57344, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1d0000) = 0x7f97d0ea9000
- mmap(0x7f97d0eb7000, 10240, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f97d0eb7000
- close(3) = 0
- openat(AT_FDCWD, "tls/haswell/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "tls/haswell/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "haswell/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "haswell/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
- read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360A\2\0\0\0\0\0"..., 832) = 832
- pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
- pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
- pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\237\333t\347\262\27\320l\223\27*\202C\370T\177"..., 68, 880) = 68
- fstat(3, {st_mode=S_IFREG|0755, st_size=2029560, ...}) = 0
- pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
- pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
- pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\237\333t\347\262\27\320l\223\27*\202C\370T\177"..., 68, 880) = 68
- mmap(NULL, 2037344, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f97d0ae6000
- mmap(0x7f97d0b08000, 1540096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7f97d0b08000
- mmap(0x7f97d0c80000, 319488, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19a000) = 0x7f97d0c80000
- mmap(0x7f97d0cce000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f97d0cce000
- mmap(0x7f97d0cd4000, 13920, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f97d0cd4000
- close(3) = 0
- openat(AT_FDCWD, "tls/haswell/x86_64/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "tls/haswell/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "tls/x86_64/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "tls/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "haswell/x86_64/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "haswell/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "x86_64/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
- read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300\323\0\0\0\0\0\0"..., 832) = 832
- fstat(3, {st_mode=S_IFREG|0644, st_size=1369352, ...}) = 0
- mmap(NULL, 1368336, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f97d0997000
- mmap(0x7f97d09a4000, 684032, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xd000) = 0x7f97d09a4000
- mmap(0x7f97d0a4b000, 626688, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xb4000) = 0x7f97d0a4b000
- mmap(0x7f97d0ae4000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x14c000) = 0x7f97d0ae4000
- close(3) = 0
- openat(AT_FDCWD, "tls/haswell/x86_64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "tls/haswell/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "tls/x86_64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "tls/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "haswell/x86_64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "haswell/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "x86_64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
- read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\3405\0\0\0\0\0\0"..., 832) = 832
- fstat(3, {st_mode=S_IFREG|0644, st_size=104984, ...}) = 0
- mmap(NULL, 107592, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f97d097c000
- mmap(0x7f97d097f000, 73728, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3000) = 0x7f97d097f000
- mmap(0x7f97d0991000, 16384, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x15000) = 0x7f97d0991000
- mmap(0x7f97d0995000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x18000) = 0x7f97d0995000
- close(3) = 0
- mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f97d097a000
- arch_prctl(ARCH_SET_FS, 0x7f97d097af40) = 0
- mprotect(0x7f97d0cce000, 16384, PROT_READ) = 0
- mprotect(0x7f97d0995000, 4096, PROT_READ) = 0
- mprotect(0x7f97d0ae4000, 4096, PROT_READ) = 0
- mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f97d0978000
- mprotect(0x7f97d0ea9000, 45056, PROT_READ) = 0
- mprotect(0x56516b200000, 4096, PROT_READ) = 0
- mprotect(0x7f97d0f01000, 4096, PROT_READ) = 0
- munmap(0x7f97d0ebc000, 95136) = 0
- brk(NULL) = 0x56516b945000
- brk(0x56516b966000) = 0x56516b966000
- execve("/bin/date", [""], NULL) = 0
- brk(NULL) = 0x55e7d01b8000
- arch_prctl(0x3001 /* ARCH_??? */, 0x7ffc36455540) = -1 EINVAL (无效的参数)
- access("/etc/ld.so.preload", R_OK) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
- fstat(3, {st_mode=S_IFREG|0644, st_size=95136, ...}) = 0
- mmap(NULL, 95136, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f42e2842000
- close(3) = 0
- openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
- read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360A\2\0\0\0\0\0"..., 832) = 832
- pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
- pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
- pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\237\333t\347\262\27\320l\223\27*\202C\370T\177"..., 68, 880) = 68
- fstat(3, {st_mode=S_IFREG|0755, st_size=2029560, ...}) = 0
- mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f42e2840000
- pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
- pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
- pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\237\333t\347\262\27\320l\223\27*\202C\370T\177"..., 68, 880) = 68
- mmap(NULL, 2037344, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f42e264e000
- mmap(0x7f42e2670000, 1540096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7f42e2670000
- mmap(0x7f42e27e8000, 319488, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19a000) = 0x7f42e27e8000
- mmap(0x7f42e2836000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f42e2836000
- mmap(0x7f42e283c000, 13920, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f42e283c000
- close(3) = 0
- arch_prctl(ARCH_SET_FS, 0x7f42e2841580) = 0
- mprotect(0x7f42e2836000, 16384, PROT_READ) = 0
- mprotect(0x55e7cfd37000, 8192, PROT_READ) = 0
- mprotect(0x7f42e2887000, 4096, PROT_READ) = 0
- munmap(0x7f42e2842000, 95136) = 0
- brk(NULL) = 0x55e7d01b8000
- brk(0x55e7d01d9000) = 0x55e7d01d9000
- openat(AT_FDCWD, "/etc/localtime", O_RDONLY|O_CLOEXEC) = 3
- fstat(3, {st_mode=S_IFREG|0644, st_size=573, ...}) = 0
- fstat(3, {st_mode=S_IFREG|0644, st_size=573, ...}) = 0
- read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\3\0\0\0\0"..., 4096) = 573
- lseek(3, -348, SEEK_CUR) = 225
- read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\3\0\0\0\0"..., 4096) = 348
- close(3) = 0
- fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x1), ...}) = 0
- write(1, "Tue Sep 6 10:34:09 CST 2022\n", 29Tue Sep 6 10:34:09 CST 2022
- ) = 29
- close(1) = 0
- close(2) = 0
- exit_group(0) = ?
- +++ exited with 0 +++
- ok@u20:~/test/hookTest$
编写hook函数
- //hook.cpp
- #include
- #include
-
- extern int __open(char *,int,int);
- //参数3:环境设备配置
- extern int execv(char *,char *[],char *envp[]);
- //打开文件
- int open(char * path,int flags,int mode)
- {
- //输出打开的文件名
- printf("open :%s\n",path);
- return __open(path,flags,mode);
- }
- //启动程序
- int execve(char * path,char* args[],char * envp[])
- {
- printf("execv :%s\n",path);
- return execv(path,args,envp);
- }
加载动态链接库后:
- g++ -fpic -c -ldl hook.cpp
- g++ -shared -lc -o hook.so hook.o
- export LD_PRELOAD=./hook.so //加载库
- export LD_PRELOAD=NULL; //卸载库
前后对比后发现,hello依赖的库发生了变化,多了./hook.so。
export LD_PRELOAD = /home/ok/test/hook/libmyfilter.so,这一句要加在环境变量中,而环境变量有三种:shell环境变量,用户环境变量和系统环境变量。影响的范围是层层递进的,当我们执行这句命令就是在加载到当前shell中,若退出当前终端,动态库就不能生效了(通常需求的范围不会这么小),若我们需要在某个用户下达到hook的效果,那么就在当前用户的profile中添加这句。(当然不同架构,不同系统的文件名不同,但都不难找,就在用户目录中的某个隐藏文件),当我们需要在整个系统生效时,我们就需要在/etc/profile配置文件中加入这句(这是使用场景最多的)。重启电脑后就能看见效果:指定的目录的具有关键字文件不能打开(双击,cat都不能打开文件,但是vim可以,为什么呢,因为vim不是用open打开文件,需要我们再次确定hook点, 这里深入了解请百度strace),指定的IP不能访问也不能主动连接本机(浏览器,wget等均不能连接)。
重新启动./hello后发现并没有起作用。我推测是不是因为是用的g++,而不是gcc造成的。
(本段是后补的)
实际上,使用g++也没关系,这里针对open的hook之所以没有成功,是因为execv系统调用和fork系统调用不同。fork生成子进程时会复制父进程的相关资源,子进程和父进程资源在fork后的初始时是一样的。但是execv却是覆盖了父进程的相关资源,父进程后面的代码不会执行。我们调整一下hello.cpp中open和execv的位置:
- #include
- #include
- #include
- #include
- #include
-
- int main(int argc,char *argv[])
- {
- int fd;
- char *args[] = {"", NULL};
-
- printf("I am here\n");
-
- if(fd=open("/home/ok/test/hookTest/hello.cpp",O_RDONLY)!=-1)
- {
- fprintf(stdout,"openfile successed!\n");
- }
- else
- {
- fprintf(stderr,"openfile error!\n");
- }
- close(fd);
-
- if(execve("/bin/date",args,NULL) == -1)
- {
- sleep(1);
- printf("here 1\n");
- perror ("execve");
- _exit(1);
- }
-
- return 0;
- }
再写一个build.sh并赋予可运行权限:
- #! /bin/bash
-
- g++ -shared -fPIC -o libhook.so hook.cpp
- g++ hello.cpp
- echo -e "**** start run ****\n"
- LD_PRELOAD=${PWD}/libhook.so ./a.out
结果如下:
但是使用ldd查看,发现并没有我们新编译的库哦。
重新使用LD_PRELOAD后又出现了我们的库。但是并不影响运行。应该是前面已经export过了。
使用strace发现这里确实使用了libhook.so中的open函数。
- ok@u20:~/test/hookTest$ strace ./a.out
- execve("./a.out", ["./a.out"], 0x7fffcdab04d0 /* 54 vars */) = 0
- brk(NULL) = 0x55dd44cec000
- arch_prctl(0x3001 /* ARCH_??? */, 0x7ffc5ad18860) = -1 EINVAL (无效的参数)
- openat(AT_FDCWD, "./libhook.so", O_RDONLY|O_CLOEXEC) = 3
- read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\20\0\0\0\0\0\0"..., 832) = 832
- fstat(3, {st_mode=S_IFREG|0775, st_size=16344, ...}) = 0
- mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd78c661000
- getcwd("/home/ok/test/hookTest", 128) = 23
- mmap(NULL, 16448, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fd78c65c000
- mmap(0x7fd78c65d000, 4096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1000) = 0x7fd78c65d000
- mmap(0x7fd78c65e000, 4096, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7fd78c65e000
- mmap(0x7fd78c65f000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7fd78c65f000
- close(3) = 0
- access("/etc/ld.so.preload", R_OK) = 0
- openat(AT_FDCWD, "/etc/ld.so.preload", O_RDONLY|O_CLOEXEC) = 3
- fstat(3, {st_mode=S_IFREG|0644, st_size=1, ...}) = 0
- mmap(NULL, 1, PROT_READ|PROT_WRITE, MAP_PRIVATE, 3, 0) = 0x7fd78c68f000
- close(3) = 0
- munmap(0x7fd78c68f000, 1) = 0
- openat(AT_FDCWD, "tls/haswell/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "tls/haswell/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "haswell/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "haswell/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/tls/haswell/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- stat("/usr/local/lib/tls/haswell/x86_64", 0x7ffc5ad17a90) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/tls/haswell/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- stat("/usr/local/lib/tls/haswell", 0x7ffc5ad17a90) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- stat("/usr/local/lib/tls/x86_64", 0x7ffc5ad17a90) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- stat("/usr/local/lib/tls", 0x7ffc5ad17a90) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/haswell/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- stat("/usr/local/lib/haswell/x86_64", 0x7ffc5ad17a90) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/haswell/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- stat("/usr/local/lib/haswell", 0x7ffc5ad17a90) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- stat("/usr/local/lib/x86_64", 0x7ffc5ad17a90) = -1 ENOENT (没有那个文件或目录)
- openat(AT_FDCWD, "/usr/local/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录)
- stat("/usr/local/lib", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
- openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
- fstat(3, {st_mode=S_IFREG|0644, st_size=95136, ...}) = 0
- mmap(NULL, 95136, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fd78c644000
- close(3) = 0
- openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
- read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360A\2\0\0\0\0\0"..., 832) = 832
- pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
- pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
- pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\237\333t\347\262\27\320l\223\27*\202C\370T\177"..., 68, 880) = 68
- fstat(3, {st_mode=S_IFREG|0755, st_size=2029560, ...}) = 0
- pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
- pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
- pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\237\333t\347\262\27\320l\223\27*\202C\370T\177"..., 68, 880) = 68
- mmap(NULL, 2037344, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fd78c452000
- mmap(0x7fd78c474000, 1540096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7fd78c474000
- mmap(0x7fd78c5ec000, 319488, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19a000) = 0x7fd78c5ec000
- mmap(0x7fd78c63a000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7fd78c63a000
- mmap(0x7fd78c640000, 13920, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fd78c640000
- close(3) = 0
- mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd78c44f000
- arch_prctl(ARCH_SET_FS, 0x7fd78c44f740) = 0
- mprotect(0x7fd78c63a000, 16384, PROT_READ) = 0
- mprotect(0x7fd78c65f000, 4096, PROT_READ) = 0
- mprotect(0x55dd42d1d000, 4096, PROT_READ) = 0
- mprotect(0x7fd78c690000, 4096, PROT_READ) = 0
- munmap(0x7fd78c644000, 95136) = 0
- fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x2), ...}) = 0
- brk(NULL) = 0x55dd44cec000
- brk(0x55dd44d0d000) = 0x55dd44d0d000
- write(1, "I am here\n", 10I am here
- ) = 10
- openat(AT_FDCWD, "/home/ok/test/hookTest/hello.cpp", O_RDONLY) = 3
- write(1, "openfile successed!\n", 20openfile successed!
- ) = 20
- close(1) = 0
- execve("/bin/date", [""], NULL) = 0
- brk(NULL) = 0x55d4c834f000
- arch_prctl(0x3001 /* ARCH_??? */, 0x7ffe2aa48fa0) = -1 EINVAL (无效的参数)
- access("/etc/ld.so.preload", R_OK) = 0
- openat(AT_FDCWD, "/etc/ld.so.preload", O_RDONLY|O_CLOEXEC) = 1
- fstat(1, {st_mode=S_IFREG|0644, st_size=1, ...}) = 0
- mmap(NULL, 1, PROT_READ|PROT_WRITE, MAP_PRIVATE, 1, 0) = 0x7f5b7cf44000
- close(1) = 0
- munmap(0x7f5b7cf44000, 1) = 0
- openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 1
- fstat(1, {st_mode=S_IFREG|0644, st_size=95136, ...}) = 0
- mmap(NULL, 95136, PROT_READ, MAP_PRIVATE, 1, 0) = 0x7f5b7cf00000
- close(1) = 0
- openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 1
- read(1, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360A\2\0\0\0\0\0"..., 832) = 832
- pread64(1, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
- pread64(1, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
- pread64(1, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\237\333t\347\262\27\320l\223\27*\202C\370T\177"..., 68, 880) = 68
- fstat(1, {st_mode=S_IFREG|0755, st_size=2029560, ...}) = 0
- mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5b7cefe000
- pread64(1, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
- pread64(1, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
- pread64(1, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\237\333t\347\262\27\320l\223\27*\202C\370T\177"..., 68, 880) = 68
- mmap(NULL, 2037344, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 1, 0) = 0x7f5b7cd0c000
- mmap(0x7f5b7cd2e000, 1540096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 1, 0x22000) = 0x7f5b7cd2e000
- mmap(0x7f5b7cea6000, 319488, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 1, 0x19a000) = 0x7f5b7cea6000
- mmap(0x7f5b7cef4000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 1, 0x1e7000) = 0x7f5b7cef4000
- mmap(0x7f5b7cefa000, 13920, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f5b7cefa000
- close(1) = 0
- arch_prctl(ARCH_SET_FS, 0x7f5b7ceff580) = 0
- mprotect(0x7f5b7cef4000, 16384, PROT_READ) = 0
- mprotect(0x55d4c6d88000, 8192, PROT_READ) = 0
- mprotect(0x7f5b7cf45000, 4096, PROT_READ) = 0
- munmap(0x7f5b7cf00000, 95136) = 0
- brk(NULL) = 0x55d4c834f000
- brk(0x55d4c8370000) = 0x55d4c8370000
- openat(AT_FDCWD, "/etc/localtime", O_RDONLY|O_CLOEXEC) = 1
- fstat(1, {st_mode=S_IFREG|0644, st_size=573, ...}) = 0
- fstat(1, {st_mode=S_IFREG|0644, st_size=573, ...}) = 0
- read(1, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\3\0\0\0\0"..., 4096) = 573
- lseek(1, -348, SEEK_CUR) = 225
- read(1, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\3\0\0\0\0"..., 4096) = 348
- close(1) = 0
- fstat(1, 0x7ffe2aa48710) = -1 EBADF (错误的文件描述符)
- write(1, "Tue Sep 6 16:33:54 CST 2022\n", 29) = -1 EBADF (错误的文件描述符)
- close(1) = -1 EBADF (错误的文件描述符)
- write(2, ": ", 2: ) = 2
- write(2, "write error", 11write error) = 11
- write(2, ": Bad file descriptor", 21: Bad file descriptor) = 21
- write(2, "\n", 1
- ) = 1
- exit_group(1) = ?
- +++ exited with 1 +++
hello.c
- #include
- #include
- #include
- #include
-
- int main(int argc,char *argv[])
- {
- int fd;
- execve("/bin/date","",NULL);
- if(fd=open("/home/ok/hookTest/test/hello.c",O_RDONLY)!=-1)
- {
- fprintf(stdout,"openfile successed!\n");
- }
- else
- {
- fprintf(stderr,"openfile error!\n");
- }
- close(fd);
- return 0;
- }
hack.c
- extern int __open(char *,int,int);
- //参数3:环境设备配置
- extern int execv(char *,char *[],char *envp[]);
- //打开文件
- int open(char * path,int flags,int mode)
- {
- //输出打开的文件名
- printf("open :%s\n",path);
- return __open(path,flags,mode);
- }
- //启动程序
- int execve(char * path,char* args[],char * envp[])
- {
- printf("execv :%s\n",path);
- return execv(path,args,envp);
这次发现起作用了。
我猜测应该是open这个函数其实是libc.so提供的函数,应该是gcc编译成的库,而前面基于c++的尝试用的是g++编译形成的动态库,这两者虽然函数名相同,但是g++的open并没有起作用。(这一段猜错了,不用看这一段了)
hook是十分危险的技术,因为它已经在系统层面作用,控制不好会反噬其主,我也写了一个open的动态库,结果中间不小心产生了无限递归(open中不能再用open),导致系统开机就进不去了。我后面也写死了几个系统了,所以每次测试之前都要快照!!
我们假设某位不法人士将上面的程序改成任何目录和文件都是exit,那么你重启系统,系统就死掉了,这是无法挽回的后果!将网络拦截程序写成任意IP都不能访问,注入到你的电脑中,如果你不了解hook技术。那么你无论如何也找不出原因,不管如何调试你将无法上网!
让普通用户拥有root权限
- //rootkit.c
- #include
- #include
- #include
-
- uid_t geteuid(void){return 0;}
- uid_t getuid(void){return 0;}
- uid_t getgid(void){return 0;}
加载进去前:
加载后:
https://blog.csdn.net/m0_37806112/article/details/80560235
https://blog.csdn.net/weixin_45646368/article/details/111403378
Linux应用调试之使用strace命令跟踪系统调用_陈 洪 伟的博客-CSDN博客_strace 查看系统调用
https://www.csdn.net/tags/MtzakgzsNTAyMjItYmxvZwO0O0OO0O0O.html