Hook技术-程序员宅基地

技术标签: C语言  linux  驱动开发  

1. Hook是什么        

        Hook挂钩是一种功能强大的编程技术,可以在不更改原始代码的情况下监视软件行为或扩展功能。 这个想法是拦截某些事件或系统调用,并使用它们来启动您自己的自定义代码。Hook的原理是利用自己创建的动态库相对于系统动态库有优先调用权,也就是在出现同名函数时优先使用自己定义或者封装的库函数,相当于屏蔽了系统自带的库函数。Hook在网络安全,数据采集和系统控制领域使用广泛。

        关于文件监控拦截,其实不管是Ring0的LKM开发(系统调用表)还是Ring3这种用户不需要考虑内核的操作思想都是类似的。在open等系统调用前进行劫持,根据用户的需求进行确定,是否继续调用真正的系统调用,是否进行其他操作。

        Ring0的内核驱动开发,需要汇编的知识,内核开发复杂难度大,所以本文采用ring3的hook技术(技术不到家T_T)。当然写驱动来进行文件监控更强(看了别人的资料有大佬写了驱动编译到内核实现文件监控模块,他们公司是这么做的)。别人的观点是不管ring0内核hook还是ring3用户hook都不那么完美(有静态编译,强制加载LD_PRELOAD为系统原有动态库等方法阻止),但人家有更好的方法。

        关于网络拦截的思路就是确定hook点在connect和accept这两个系统调用,只要hook了这两个系统调用,那么指定IP的来连接或者访问此IP都不能进行。

2. hook动态库的组织

        Hook代码经make得到了动态库libmyfilter.so后,我们需要根据准备使用的范围来确定将新创建的动态库默认加载在哪。

        LD_PRELOAD是个环境变量,用于动态库的加载,动态库加载的优先级最高。一般情况下,动态库加载顺序为LD_PRELOAD>LD_LIBRARY_PATH>/etc/ld.so.cache>/lib>/usr/lib。程序中我们经常要调用一些外部库的函数,以open()和execve()为例,如果我们有个自定义这两函数,把它编译成动态库后,通过LD_PRELOAD加载,当程序中调用open函数时,调用的其实是我们自定义的函数(这个其实就是hook啦),下面以一个例子说明。

2.1 基于CPP的尝试

//hello.cpp
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <iostream>
#include <unistd.h>
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()函数的第一个参数使用。

  • mmap主要完成.so文件到进程空间的映射
  • stat的原型是int stat(const char *path, struct stat *buf);用于获取文件或目录相关的信息
  • fstat获取文件状态
  • pread 对文件随机读
  • mprotect系统调用 的作用是设置虚拟内存区域访问权限
  • munmap系统调用是删除指定地址范围的映射,并导致对该范围内地址的进一步引用会生成无效的内存引用。 当进程终止时,该区域也会自动取消映射。 另一方面,关闭文件描述符不会取消区域映射
  • unlink系统调用用于删除指定文件,无法删除目录
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 <stdio.h>
#include <fcntl.h>

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 <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
 
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 +++

2.2 基于C的尝试

 hello.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
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技术

        hook是十分危险的技术,因为它已经在系统层面作用,控制不好会反噬其主,我也写了一个open的动态库,结果中间不小心产生了无限递归(open中不能再用open),导致系统开机就进不去了。我后面也写死了几个系统了,所以每次测试之前都要快照!!
我们假设某位不法人士将上面的程序改成任何目录和文件都是exit,那么你重启系统,系统就死掉了,这是无法挽回的后果!将网络拦截程序写成任意IP都不能访问,注入到你的电脑中,如果你不了解hook技术。那么你无论如何也找不出原因,不管如何调试你将无法上网!

让普通用户拥有root权限

//rootkit.c
#include <dlfcn.h>
#include <unistd.h>
#include <sys/types.h>
 
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命令跟踪系统调用_陈 洪 伟的博客-程序员宅基地_strace 查看系统调用

https://www.csdn.net/tags/MtzakgzsNTAyMjItYmxvZwO0O0OO0O0O.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/jinking01/article/details/126718873

智能推荐

什么是内部类?成员内部类、静态内部类、局部内部类和匿名内部类的区别及作用?_成员内部类和局部内部类的区别-程序员宅基地

文章浏览阅读3.4k次,点赞8次,收藏42次。一、什么是内部类?or 内部类的概念内部类是定义在另一个类中的类;下面类TestB是类TestA的内部类。即内部类对象引用了实例化该内部对象的外围类对象。public class TestA{ class TestB {}}二、 为什么需要内部类?or 内部类有什么作用?1、 内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据。2、内部类可以对同一个包中的其他类隐藏起来。3、 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。三、 内部类的分类成员内部_成员内部类和局部内部类的区别

分布式系统_分布式系统运维工具-程序员宅基地

文章浏览阅读118次。分布式系统要求拆分分布式思想的实质搭配要求分布式系统要求按照某些特定的规则将项目进行拆分。如果将一个项目的所有模板功能都写到一起,当某个模块出现问题时将直接导致整个服务器出现问题。拆分按照业务拆分为不同的服务器,有效的降低系统架构的耦合性在业务拆分的基础上可按照代码层级进行拆分(view、controller、service、pojo)分布式思想的实质分布式思想的实质是为了系统的..._分布式系统运维工具

用Exce分析l数据极简入门_exce l趋势分析数据量-程序员宅基地

文章浏览阅读174次。1.数据源准备2.数据处理step1:数据表处理应用函数:①VLOOKUP函数; ② CONCATENATE函数终表:step2:数据透视表统计分析(1) 透视表汇总不同渠道用户数, 金额(2)透视表汇总不同日期购买用户数,金额(3)透视表汇总不同用户购买订单数,金额step3:讲第二步结果可视化, 比如, 柱形图(1)不同渠道用户数, 金额(2)不同日期..._exce l趋势分析数据量

宁盾堡垒机双因素认证方案_horizon宁盾双因素配置-程序员宅基地

文章浏览阅读3.3k次。堡垒机可以为企业实现服务器、网络设备、数据库、安全设备等的集中管控和安全可靠运行,帮助IT运维人员提高工作效率。通俗来说,就是用来控制哪些人可以登录哪些资产(事先防范和事中控制),以及录像记录登录资产后做了什么事情(事后溯源)。由于堡垒机内部保存着企业所有的设备资产和权限关系,是企业内部信息安全的重要一环。但目前出现的以下问题产生了很大安全隐患:密码设置过于简单,容易被暴力破解;为方便记忆,设置统一的密码,一旦单点被破,极易引发全面危机。在单一的静态密码验证机制下,登录密码是堡垒机安全的唯一_horizon宁盾双因素配置

谷歌浏览器安装(Win、Linux、离线安装)_chrome linux debian离线安装依赖-程序员宅基地

文章浏览阅读7.7k次,点赞4次,收藏16次。Chrome作为一款挺不错的浏览器,其有着诸多的优良特性,并且支持跨平台。其支持(Windows、Linux、Mac OS X、BSD、Android),在绝大多数情况下,其的安装都很简单,但有时会由于网络原因,无法安装,所以在这里总结下Chrome的安装。Windows下的安装:在线安装:离线安装:Linux下的安装:在线安装:离线安装:..._chrome linux debian离线安装依赖

烤仔TVの尚书房 | 逃离北上广?不如押宝越南“北上广”-程序员宅基地

文章浏览阅读153次。中国发达城市榜单每天都在刷新,但无非是北上广轮流坐庄。北京拥有最顶尖的文化资源,上海是“摩登”的国际化大都市,广州是活力四射的千年商都。GDP和发展潜力是衡量城市的数字指...

随便推点

java spark的使用和配置_使用java调用spark注册进去的程序-程序员宅基地

文章浏览阅读3.3k次。前言spark在java使用比较少,多是scala的用法,我这里介绍一下我在项目中使用的代码配置详细算法的使用请点击我主页列表查看版本jar版本说明spark3.0.1scala2.12这个版本注意和spark版本对应,只是为了引jar包springboot版本2.3.2.RELEASEmaven<!-- spark --> <dependency> <gro_使用java调用spark注册进去的程序

汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用_uds协议栈 源代码-程序员宅基地

文章浏览阅读4.8k次。汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用,代码精简高效,大厂出品有量产保证。:139800617636213023darcy169_uds协议栈 源代码

AUTOSAR基础篇之OS(下)_autosar 定义了 5 种多核支持类型-程序员宅基地

文章浏览阅读4.6k次,点赞20次,收藏148次。AUTOSAR基础篇之OS(下)前言首先,请问大家几个小小的问题,你清楚:你知道多核OS在什么场景下使用吗?多核系统OS又是如何协同启动或者关闭的呢?AUTOSAR OS存在哪些功能安全等方面的要求呢?多核OS之间的启动关闭与单核相比又存在哪些异同呢?。。。。。。今天,我们来一起探索并回答这些问题。为了便于大家理解,以下是本文的主题大纲:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JCXrdI0k-1636287756923)(https://gite_autosar 定义了 5 种多核支持类型

VS报错无法打开自己写的头文件_vs2013打不开自己定义的头文件-程序员宅基地

文章浏览阅读2.2k次,点赞6次,收藏14次。原因:自己写的头文件没有被加入到方案的包含目录中去,无法被检索到,也就无法打开。将自己写的头文件都放入header files。然后在VS界面上,右键方案名,点击属性。将自己头文件夹的目录添加进去。_vs2013打不开自己定义的头文件

【Redis】Redis基础命令集详解_redis命令-程序员宅基地

文章浏览阅读3.3w次,点赞80次,收藏342次。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。当数据量很大时,count 的数量的指定可能会不起作用,Redis 会自动调整每次的遍历数目。_redis命令

URP渲染管线简介-程序员宅基地

文章浏览阅读449次,点赞3次,收藏3次。URP的设计目标是在保持高性能的同时,提供更多的渲染功能和自定义选项。与普通项目相比,会多出Presets文件夹,里面包含着一些设置,包括本色,声音,法线,贴图等设置。全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,主光源和附加光源在一次Pass中可以一起着色。URP:全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,一次Pass可以计算多个光源。可编程渲染管线:渲染策略是可以供程序员定制的,可以定制的有:光照计算和光源,深度测试,摄像机光照烘焙,后期处理策略等等。_urp渲染管线

推荐文章

热门文章

相关标签