Hook

SSTD Hook

系统服务表 SystemServiceTable

image-20220927111922686

如何访问系统服务表

image-20220927111956515

SSDT有四个成员,每个成员16字节,一般后三个成员是空的,而第一个成员就是系统服务表

image-20220927114515872

第一个4字节存储的是存储内核函数的一段内存的基址,第三个4字节存储的是存储内核函数的个数,第四个是内核函数参数的个数,注意第四个参数是byte数组

image-20220927114702813

得到函数表地址

image-20220927121701663

上面那个是系统服务表的结构体,下面是SSDT的结构体

通过页表基址修改页属性

image-20220927133252604

通过修改CR0寄存器

image-20220927134115898

image-20220927134219268

ssdt hook是比较低级的hook,十分容易被发现。

inline hook

SSDT Hook的缺点

  • 容易发现,容易绕过
  • 只能hook系统服务表里有的函数

位置选择

image-20220927141533800

地址的计算

image-20220927141803385

code是jmp的二进制编码的后面几位的值

image-20220927141856024

多核同步之临界区

前置知识

image-20220927142124556

演示

image-20220927142456143

LOCK

image-20220927144743302

Lock指令可以保证一行汇编指令的原子性,也就是如果多个核同时执行这个汇编指令的话,结果不会是只执行了一次,而是他会先让一个核执行,然后再给其他核进行执行,依次类推。

多行代码原子操作

image-20220927151313333

临界区

image-20220927151533602

不过这串代码是有问题的。如果一个线程进入if,还没来得及修改dwFlag,另一个线程也进入if判断,就会出现错误。

自己实现临界区

image-20220927151923078

多核同步之自旋锁

不同版本的内核文件

image-20220927152925908

单核和多核的这几个文件,看似名字相同,但是操作系统会释放不一样的文件。因为单核和多核会涉及到一些Lock的操作不同。

Windows 自旋锁

image-20220927153547459

image-20220927154044868

下方部分,如果判断ecx是1,会执行pause指令,也就是降温指令,让cpu执行慢一些,然后跳回去反复执行。

总结

image-20220927172601551

重载内核

解决的问题

image-20220927172850424

重载内核的步骤

image-20220927190422524

导入表结构

结构

image-20220927200112613

PE文件加载前

image-20220927193114989

PE文件加载后

image-20220927193220381

INT表是导入名称表,IAT表是导入地址表

加载前,FirstThunk和OriginalFirstThunkzhi指向的位置是一样的,都是指向INT表,而加载后IAT表存储的是真正的函数地址。他会从INT中找到对应的模块的位置,然后在模块对应的导出表中找到对应的dll然后找到对应的函数地址,将地址填入IAT表之中。例如上图的user32.dll,当程序加载到内存之中,他会通过user32.dll这个名字去找到该模块,然后根据导出表的名字找到对应的函数地址然后填入IAT表之中。

修复IAT

image-20220927200941973

我们直接把结构都对应上,也是无法运行的,因为IAT表没有更新,还是原来的指向名字的那个表,所以我们得手动将其更新成函数的地址。

具体修复过程就是根据对应的模块,通过函数的名字,去模块里找地址然后填入IAT表,没了。

重载后的使用

image-20220927194713569

image-20220927201404771

首先必须山寨一个系统服务表。因为系统服务表存储的Nt的一堆内核函数,而要调用这些函数得去那里找,而我们不能用原来那个,必须自己整个新的系统服务表,同时开辟一段新内存作为内核,然后通过Hook KiFastCallEntry,让系统调用那些函数的时候去找我们的系统服务表而不是原来那个。

重载内核的弊端

image-20220927195631606

随便搜一下硬编码就可以判断是否受到内核重载,如果搜内核函数每次都能搜到两份,谁都猜得出来是重载了内核。