Hook技术

这篇具有很好参考价值的文章主要介绍了Hook技术。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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。

hook技术,linux,C语言,驱动开发

export LD_PRELOAD = /home/ok/test/hook/libmyfilter.so,这一句要加在环境变量中,而环境变量有三种:shell环境变量,用户环境变量和系统环境变量。影响的范围是层层递进的,当我们执行这句命令就是在加载到当前shell中,若退出当前终端,动态库就不能生效了(通常需求的范围不会这么小),若我们需要在某个用户下达到hook的效果,那么就在当前用户的profile中添加这句。(当然不同架构,不同系统的文件名不同,但都不难找,就在用户目录中的某个隐藏文件),当我们需要在整个系统生效时,我们就需要在/etc/profile配置文件中加入这句(这是使用场景最多的)。重启电脑后就能看见效果:指定的目录的具有关键字文件不能打开(双击,cat都不能打开文件,但是vim可以,为什么呢,因为vim不是用open打开文件,需要我们再次确定hook点, 这里深入了解请百度strace),指定的IP不能访问也不能主动连接本机(浏览器,wget等均不能连接)。

hook技术,linux,C语言,驱动开发

 重新启动./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

 结果如下:

hook技术,linux,C语言,驱动开发

 但是使用ldd查看,发现并没有我们新编译的库哦。hook技术,linux,C语言,驱动开发

 重新使用LD_PRELOAD后又出现了我们的库。但是并不影响运行。应该是前面已经export过了。hook技术,linux,C语言,驱动开发

 使用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);	

hook技术,linux,C语言,驱动开发

 这次发现起作用了。

        我猜测应该是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;}

 加载进去前:

hook技术,linux,C语言,驱动开发

 加载后:

hook技术,linux,C语言,驱动开发

参考链接:

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文章来源地址https://www.toymoban.com/news/detail-724883.html

到了这里,关于Hook技术的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 『网络安全科普』Windows安全之HOOK技术机制

    如你所知,Windows系统是建立在事件驱动的机制上的,而每一个事件就是一个消息,每个运行中的程序,也就是所谓的进程,都维护着一个或多个消息队列(消息队列的个数取决于进程内包含的线程的个数)。 网络安全重磅福利:入门进阶全套282G学习资源包免费分享! typed

    2024年02月03日
    浏览(40)
  • APP攻防--安卓逆向&JEB动态调试&LSPosed模块&算法提取&Hook技术

    安装java环境变量(最好jdk11) 安装adb环境变量 设置adb环境变量最好以Android命名 启动开发者模式 设置--关于平板电脑--版本号(单机五次) 开启USB调试 设置--系统--高级--开发者选项--USB调试 开启USB调试目的是为了后续让JEB能够获取模拟器上的进程 安装激活JEB 软件安装包和破解参

    2024年02月05日
    浏览(66)
  • 【《React Hooks实战》——指导你使用hook开发性能优秀可复用性高的React组件】

    使用React Hooks后,你很快就会发现,代码变得更具有组织性且更易于维护。React Hooks是旨在为用户提供跨组件的重用功能和共享功能的JavaScript函数。利用React Hooks, 可以将组件分成多个函数、管理状态和副作用,并且不必声明类即可调用React内置的功能。而且,上述所有的操作

    2024年02月14日
    浏览(35)
  • 测试框架pytest教程(6)钩子函数hook开发pytest插件

    pytest hook 函数也叫钩子函数,pytest 提供了大量的钩子函数,可以在用例的不同生命周期自动调用。 比如,在测试用例收集阶段,可利用 hook 函数修改测试用例名称的编码。 pytest的hook是基于Python的插件系统实现的,使用特定的命名规范和装饰器来定义钩子函数。你可以在py

    2024年02月12日
    浏览(37)
  • 企业微信hook接口,朋友圈功能开发教程,逆向开发,企业微信营销开发

    【技术支持】 支持语言 操作码 110001 请求说明 参数名 必选 类型 说明 syncKey 是 string 同步key 请求示例 返回示例 简要描述 110003 请求说明 参数名 必选 类型 说明 syncKey 是 string 同步key 请求示例 返回示例 基本实现企业微信pc端所有功能。 1.登陆模块: 接收登录二维码,登录成

    2024年02月11日
    浏览(44)
  • 20230529----重返学习-复合组件通信redux-redux源码-redux工程化开发-自定义hook

    要想实现复合组件通信,一般采用公共状态管理方案。 常见的公共状态管理方案: 官方推荐的:redux。 redux + react-redux + redux-logger / redux-promise / redux-saga / redux-thunk :中间件。 代表:dva「redux-saga 」或 umi。 @reduxjs/toolkit :工具类。 mobx 。 zustand 。 … redux的应用场景 redux 在以

    2024年02月06日
    浏览(55)
  • 【Pytorch】提取模型中间层输出(hook, .register_forward_hook(hook=hook))

    需要转换的对象 模型 损失函数 数据(特征数据、标签) 4.3.1 单进程多GPU训练(DP)模式 torch.nn.DataParallel 并行的多卡都是由一个进程进行控制,在进行梯度的传播时,是在主GPU上进行的。 将模型布置到多个指定GPU上 model = torch.nn.DataParallel(model,device_ids=device_list) 指定模型布置的

    2024年02月13日
    浏览(37)
  • React hook 10种常见 Hook

    React官网是这么介绍的: Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 完全可选的 你无需重写任何已有代码就可以在一些组件中尝试 Hook。但是如果你不想,你不必现在就去学习或使用 Hook。 100% 向后兼容的 Hook 不包含任何

    2024年02月10日
    浏览(37)
  • Linux驱动开发:技术、实践与Linux的历史

    Linux,这个开源的操作系统,已经在全球范围内赢得了开发者和企业的广泛支持。它的强大之处在于其内核以及无数的驱动程序,这些驱动程序使得各种硬件设备可以在Linux操作系统上运行。本篇文章将深入探讨Linux驱动开发,包括其技术、实践以及Linux的历史。 Linux的起源可

    2024年02月11日
    浏览(40)
  • 带你看懂 Vue Hook和React Hook

    react Hook React Hook 是 React 16.8 版本引入的一项新特性,它能够让函数组件拥有类组件中的状态(state)和生命周期方法(lifecycle methods)等功能。React Hook 包括了多个钩子函数(hook functions),如 useState、useEffect、useContext 等,在函数组件中使用这些钩子函数可以实现一系列常见的功能,

    2023年04月26日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包