Hook-滴水逆向观看笔记
Hook
SSTD Hook
系统服务表 SystemServiceTable
如何访问系统服务表
SSDT有四个成员,每个成员16字节,一般后三个成员是空的,而第一个成员就是系统服务表
第一个4字节存储的是存储内核函数的一段内存的基址,第三个4字节存储的是存储内核函数的个数,第四个是内核函数参数的个数,注意第四个参数是byte数组
得到函数表地址
上面那个是系统服务表的结构体,下面是SSDT的结构体
通过页表基址修改页属性
通过修改CR0寄存器
ssdt hook是比较低级的hook,十分容易被发现。
inline hook
SSDT Hook的缺点
- 容易发现,容易绕过
- 只能hook系统服务表里有的函数
位置选择
地址的计算
code是jmp的二进制编码的后面几位的值
多核同步之临界区
前置知识
演示
LOCK
Lock指令可以保证一行汇编指令的原子性,也就是如果多个核同时执行这个汇编指令的话,结果不会是只执行了一次,而是他会先让一个核执行,然后再给其他核进行执行,依次类推。
多行代码原子操作
临界区
不过这串代码是有问题的。如果一个线程进入if,还没来得及修改dwFlag,另一个线程也进入if判断,就会出现错误。
自己实现临界区
多核同步之自旋锁
不同版本的内核文件
单核和多核的这几个文件,看似名字相同,但是操作系统会释放不一样的文件。因为单核和多核会涉及到一些Lock的操作不同。
Windows 自旋锁
下方部分,如果判断ecx是1,会执行pause指令,也就是降温指令,让cpu执行慢一些,然后跳回去反复执行。
总结
重载内核
解决的问题
重载内核的步骤
导入表结构
结构
PE文件加载前
PE文件加载后
INT表是导入名称表,IAT表是导入地址表
加载前,FirstThunk和OriginalFirstThunkzhi指向的位置是一样的,都是指向INT表,而加载后IAT表存储的是真正的函数地址。他会从INT中找到对应的模块的位置,然后在模块对应的导出表中找到对应的dll然后找到对应的函数地址,将地址填入IAT表之中。例如上图的user32.dll,当程序加载到内存之中,他会通过user32.dll这个名字去找到该模块,然后根据导出表的名字找到对应的函数地址然后填入IAT表之中。
修复IAT
我们直接把结构都对应上,也是无法运行的,因为IAT表没有更新,还是原来的指向名字的那个表,所以我们得手动将其更新成函数的地址。
具体修复过程就是根据对应的模块,通过函数的名字,去模块里找地址然后填入IAT表,没了。
重载后的使用
首先必须山寨一个系统服务表。因为系统服务表存储的Nt的一堆内核函数,而要调用这些函数得去那里找,而我们不能用原来那个,必须自己整个新的系统服务表,同时开辟一段新内存作为内核,然后通过Hook KiFastCallEntry,让系统调用那些函数的时候去找我们的系统服务表而不是原来那个。
重载内核的弊端
随便搜一下硬编码就可以判断是否受到内核重载,如果搜内核函数每次都能搜到两份,谁都猜得出来是重载了内核。