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

智能推荐

使用nginx解决浏览器跨域问题_nginx不停的xhr-程序员宅基地

文章浏览阅读1k次。通过使用ajax方法跨域请求是浏览器所不允许的,浏览器出于安全考虑是禁止的。警告信息如下:不过jQuery对跨域问题也有解决方案,使用jsonp的方式解决,方法如下:$.ajax({ async:false, url: 'http://www.mysite.com/demo.do', // 跨域URL ty..._nginx不停的xhr

在 Oracle 中配置 extproc 以访问 ST_Geometry-程序员宅基地

文章浏览阅读2k次。关于在 Oracle 中配置 extproc 以访问 ST_Geometry,也就是我们所说的 使用空间SQL 的方法,官方文档链接如下。http://desktop.arcgis.com/zh-cn/arcmap/latest/manage-data/gdbs-in-oracle/configure-oracle-extproc.htm其实简单总结一下,主要就分为以下几个步骤。..._extproc

Linux C++ gbk转为utf-8_linux c++ gbk->utf8-程序员宅基地

文章浏览阅读1.5w次。linux下没有上面的两个函数,需要使用函数 mbstowcs和wcstombsmbstowcs将多字节编码转换为宽字节编码wcstombs将宽字节编码转换为多字节编码这两个函数,转换过程中受到系统编码类型的影响,需要通过设置来设定转换前和转换后的编码类型。通过函数setlocale进行系统编码的设置。linux下输入命名locale -a查看系统支持的编码_linux c++ gbk->utf8

IMP-00009: 导出文件异常结束-程序员宅基地

文章浏览阅读750次。今天准备从生产库向测试库进行数据导入,结果在imp导入的时候遇到“ IMP-00009:导出文件异常结束” 错误,google一下,发现可能有如下原因导致imp的数据太大,没有写buffer和commit两个数据库字符集不同从低版本exp的dmp文件,向高版本imp导出的dmp文件出错传输dmp文件时,文件损坏解决办法:imp时指定..._imp-00009导出文件异常结束

python程序员需要深入掌握的技能_Python用数据说明程序员需要掌握的技能-程序员宅基地

文章浏览阅读143次。当下是一个大数据的时代,各个行业都离不开数据的支持。因此,网络爬虫就应运而生。网络爬虫当下最为火热的是Python,Python开发爬虫相对简单,而且功能库相当完善,力压众多开发语言。本次教程我们爬取前程无忧的招聘信息来分析Python程序员需要掌握那些编程技术。首先在谷歌浏览器打开前程无忧的首页,按F12打开浏览器的开发者工具。浏览器开发者工具是用于捕捉网站的请求信息,通过分析请求信息可以了解请..._初级python程序员能力要求

Spring @Service生成bean名称的规则(当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致)_@service beanname-程序员宅基地

文章浏览阅读7.6k次,点赞2次,收藏6次。@Service标注的bean,类名:ABDemoService查看源码后发现,原来是经过一个特殊处理:当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致public class AnnotationBeanNameGenerator implements BeanNameGenerator { private static final String C..._@service beanname

随便推点

二叉树的各种创建方法_二叉树的建立-程序员宅基地

文章浏览阅读6.9w次,点赞73次,收藏463次。1.前序创建#include&lt;stdio.h&gt;#include&lt;string.h&gt;#include&lt;stdlib.h&gt;#include&lt;malloc.h&gt;#include&lt;iostream&gt;#include&lt;stack&gt;#include&lt;queue&gt;using namespace std;typed_二叉树的建立

解决asp.net导出excel时中文文件名乱码_asp.net utf8 导出中文字符乱码-程序员宅基地

文章浏览阅读7.1k次。在Asp.net上使用Excel导出功能,如果文件名出现中文,便会以乱码视之。 解决方法: fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8);_asp.net utf8 导出中文字符乱码

笔记-编译原理-实验一-词法分析器设计_对pl/0作以下修改扩充。增加单词-程序员宅基地

文章浏览阅读2.1k次,点赞4次,收藏23次。第一次实验 词法分析实验报告设计思想词法分析的主要任务是根据文法的词汇表以及对应约定的编码进行一定的识别,找出文件中所有的合法的单词,并给出一定的信息作为最后的结果,用于后续语法分析程序的使用;本实验针对 PL/0 语言 的文法、词汇表编写一个词法分析程序,对于每个单词根据词汇表输出: (单词种类, 单词的值) 二元对。词汇表:种别编码单词符号助记符0beginb..._对pl/0作以下修改扩充。增加单词

android adb shell 权限,android adb shell权限被拒绝-程序员宅基地

文章浏览阅读773次。我在使用adb.exe时遇到了麻烦.我想使用与bash相同的adb.exe shell提示符,所以我决定更改默认的bash二进制文件(当然二进制文件是交叉编译的,一切都很完美)更改bash二进制文件遵循以下顺序> adb remount> adb push bash / system / bin /> adb shell> cd / system / bin> chm..._adb shell mv 权限

投影仪-相机标定_相机-投影仪标定-程序员宅基地

文章浏览阅读6.8k次,点赞12次,收藏125次。1. 单目相机标定引言相机标定已经研究多年,标定的算法可以分为基于摄影测量的标定和自标定。其中,应用最为广泛的还是张正友标定法。这是一种简单灵活、高鲁棒性、低成本的相机标定算法。仅需要一台相机和一块平面标定板构建相机标定系统,在标定过程中,相机拍摄多个角度下(至少两个角度,推荐10~20个角度)的标定板图像(相机和标定板都可以移动),即可对相机的内外参数进行标定。下面介绍张氏标定法(以下也这么称呼)的原理。原理相机模型和单应矩阵相机标定,就是对相机的内外参数进行计算的过程,从而得到物体到图像的投影_相机-投影仪标定

Wayland架构、渲染、硬件支持-程序员宅基地

文章浏览阅读2.2k次。文章目录Wayland 架构Wayland 渲染Wayland的 硬件支持简 述: 翻译一篇关于和 wayland 有关的技术文章, 其英文标题为Wayland Architecture .Wayland 架构若是想要更好的理解 Wayland 架构及其与 X (X11 or X Window System) 结构;一种很好的方法是将事件从输入设备就开始跟踪, 查看期间所有的屏幕上出现的变化。这就是我们现在对 X 的理解。 内核是从一个输入设备中获取一个事件,并通过 evdev 输入_wayland

推荐文章

热门文章

相关标签