Overall:
目前支持功能:
R0权限的用户进程内存遍历工具,能过大部分反作弊探测:
1)搜索前提:
首次搜索
后继搜索(精确值搜索/变大值/变小值/不变值/增大指定值/减少指定值/范围搜索).
2)搜索类型:
首次支持:精确值搜索/范围值搜索/模式串;
后继支持:精确值搜索/范围值搜索/变大值/变小值/不变值/增大指定值/减少指定值.
3)支持的数据类型:
单字节;
双字节;
四字节;
八字节;
模式匹配;
IEEE754 4字节单浮点数;
IEEE754 8字节双浮点数.
4)数据结构:
和之前一样仍然是双向循环链表.
5)符号:
默认是有符号数据的搜索。
驱动DLL注入;
进程模块遍历;
进程线程遍历;
驱动模块遍历;
读写R3虚拟内存;
读写R0虚拟内存;
读写物理内存;
进程隐藏;
驱动隐藏;
进程傀儡;
SSDT Inline Hook和劫持;
以及基于此的:
进程保护;
全局变速;
进程强杀;
转移CALL.
IDT Inline Hook;
劫持除零异常隐蔽调用驱动函数;
PE文件导出表解析(内核用户通用汇编指令):
导出的函数个数;
导出函数名字;
导出函数地址;
驱动程序浮点数解释器.
经测试,所有功能调用都没有内存泄露出现
2025/2/10:
再次重构了内存搜索逻辑;
加入了用户层的程序代码,实现驱动用户的交互;
在驱动层,使用了更安全地MDL操作函数来处理用户层内存;
对驱动层地址和用户层地址的存取统一使用物理内存映射方法读取;
经大量测试,没有蓝屏和内存泄漏出现!
所有的内存分分配的Tag现在都为'z+aa'!
2025/1/10:
现在支持驱动级DLL注入,原理是线程注入方法。
2024/10/23:
现在支持读写物理内存。
2024/10/16:
现在对IEEE 754标准的4字节单精度浮点和8字节双精度浮点提供了支持;
并且支持模糊搜索,顺便写了两个浮点数解释器:
DbgPrintF和DbgPrintD;
用这两个解释器可以轻松地在内核中打印浮点数;
解释器最大精度限制为1000000;
另外加了一些非常常用的读取寄存器过程;
对常用的字节读取函数进行了封装。
2024/10/15:
重构了全部文件结构,由于之前把所有功能都合在一起导致维护起来太过混乱;
重构了搜索逻辑,准备完全支持Cheat Engine的搜索模式;
直接输入数值或者最小最大范围搜索,不像之前的硬编码字节输入;
重构/新增了大量的数据结构,尤其是关于输入的结构联合;
又挖了一个大坑!!!
2024/10/13:
支持了内核DbgPrint打印IEEE 754单精度浮点数(float)的功能;
输入该浮点数的地址,在DbgView中就可以打印出此浮点数;
最高支持6位浮点精度。
2024/10/6:
把SSDT_HOOK的功能集成到了函数中,并对一些常用的功能分离开来;
支持输入调用号和新的函数指针直接HOOK,简化了步骤;
而且对诸如获取SSDT指针、SSDT函数地址等常用功能进行了单独封装;
可以直接调用。
新增全局变速,基于SSDT HOOK NtQueryPerformanceCounter实现;
加速三十倍,电脑性能极大提升(???)
并且可以应用在只狼上,直接飞起来了(雾)
直接他妈起飞!
2024/9/28:
更新了驱动模块遍历(displayKernelModules函数里面的双链表非常清晰!)
基于DRIVER_OBJECT->DRIVER_SECTION_InLoadOrderList实现。
更新了导出表解析的汇编代码,相比于之前的代码:
1.逻辑更加清晰;
2.支持全部导出函数个数功能,基于此可以计算差值;
3.重写了获取导出函数地址和名字的过程;
4.之前版本由于没有计算全部导出函数个数和仅以名字导出函数的个数之差;
导致函数名字和函数地址在差值非零的情况下对不上;
此版本解决了此问题。
(DbgView中显示前面7个函数名字和WinDbg中不一样;
但是后面3063个导出函数的名字和地址是完全对应的;
猜测应该是同一个函数,只是dbgView和winDbg符号解析的方法不同)
2024/9/27补档
发现灾难级BUG,原因在于protectProcessRestore().
修复前:memcpy((PVOID)(NtOpenProcessAddress - shellCodeSize - 1), restoreINT3Code, shellCodeSize);
修复后:memcpy((PVOID)NtOpenProcessAddress, restoreINT3Code, shellCodeSize);
问题描述:在执行了此函数之后,驱动正常卸载没问题;
但是电脑(即使是在反复重启之后)自此之后开始不定时蓝屏崩溃;
造成了系统严重不稳定,即使只开机待机什么也不做也会概率蓝屏。
问题原因:在执行了进程保护之后,由于此时NtOpenProcess的偏移已经被篡改;
而我的复原逻辑是先把跳转指令恢复成0xCC,后修改原来的NtOpenProcess偏移;
但是在复原跳转指令的时候仍然采用了NtOpenProcessAddress-shellCodeSize-1这个偏移;
这导致复原的时候实际上写入的12个0xCC字节覆盖到了我的shellCode的起始字节的上面13个偏移处!
而我的shellCode的起始字节已经距离真正的NtOpenProcessAddress偏移了13个字节!
这造成了两个结果:
1.我自己的shellCode字节没有被正确地恢复为0xCC;
2.不仅如此,我还把我自己的shellCode字节上面的13个偏移的地方
(也就是真正的NtOpenProcessAddress的上面的第25(= 13 + 12)个字节开始)写成了0xCC!
由于NtOpenProcess函数的上面只有13个0xCC可以被使用,但我却把12个用来复原的0xCC写到了NtOpenProcess函数的上面25字节处;
导致了NtOpenProcess函数的上面的那个系统函数的后12个可执行字节被错误地改成了0xCC;
而且这12个字节重启了2到3次之后通过windbg查看仍然没变,导致了频繁蓝屏,即使待机也会突然蓝屏!
目前已经改正此灾难性BUG,心有余悸!
注1:被0xCC错误覆盖的可执行字节只有在Windows执行到此过程发生蓝屏之后才会自动修复;
因为只有在执行受影响的系统函数(A)导致蓝屏时才能触发自动修复;
但如果A的错误字节通过其他路径间接影响了正常执行的系统函数(B);
系统不会意识到A的字节被破坏,这就导致了反复的蓝屏。
注2:调试期间期间报了包括但不限于:
SYSTEM_SERVICE_EXCEPTION;
CRITICAL_STRUCTURE_CORRUPTION;
SYSTEM_THREAD_EXCEPTION_NOT_HANDLED;
CRITICAL_PROCESS_DIED
等大量蓝屏代码,好在现在已经修复此BUG!
2024/9/27:
将SSDT Hook NtOpenProcess的功能整合在了函数中;
但是还没有对进程保护功能加入到用户联立中。
新蓝屏代码:CRITICAL_STRUCTURE_CORRUPTION
原因在于在driverUnload函数中没有写入protectProcessRestore()过程;
加上了protectProcessRestore()之后就没事了,应该是过了PatchGuard检查?
疑问:蓝屏的时候我并没有主动调用停止和卸载驱动,仅仅只是启动了驱动;
理论上来说,不主动调用driverUnload就不会蓝屏,但是它确实蓝屏了;
在我把protectProcessRestore()加上之后就可以正常运行了,怎么运行都不会蓝屏。
难道说OS会探测性地背后隐藏读取或者执行driverUnload来提前验证内核结构吗?
2024/9/26:
使用了SSDT Hook来实现进程保护,但是目前没有整理成函数;
//危险:卸载部分为了快速测试采用了硬编码!
//实际应用目前只能在我的电脑上,别的机器用100%会蓝屏!!但暂时先不改了!
思路:刚开始在想用我自己定义的hook函数减去SSDT表头,用差值去替换偏移;
但是上面得出差值是0x42849650,由于64位系统对NT函数寻址进行了一个小加密,需要把偏移二进制右移动4位;
即:SSDT_BASE[index] >> 4 + SSDT_BASE = funcAddressOf[index]
导致了我的差值不能直接写在偏移地址里面,差了“半个”字节,无法解决此问题!
然后我又发现NtOpenProcess函数上方有13个字节是0xCC,而我一计算:
mov rax, 0FFFFF8056B0C7BA0h -> 48 b8 60 12 32 86 06 f8 ff ff
jmp rax -> ff e0
汇编此指令后对应的机器码是12个字节,恰好能被容纳进去!!!
因此我就动手在NtOpenProcess函数上方的13个字节篡改成了我的目标机器码;
//危险:由于XP之后微软对SSDT相关的内存严格保护;
//在修改之前需要先变更CR0寄存器的第16位二进制位来破除写保护!
然后再把*(ULONG*)(SSDT_BASE[index])篡改成我的shellcode的起始地址偏移;
即:*(ULONG*)(SSDT_BASE[index]) = MyNtOpenProcess - SSDT_BASE;
再把这个值shl 4(右移的逆操作),多出来的半个字节换成什么都可以!
就实现了基于SSDT的inline hook!
测试表明,驱动程序运行时,使用CE打开进程会提示无法打开!
表明CPU确实执行到了我自己定义的NtOpenProcess了!
2024/9/24:
驱动先更新到这儿!还有用户层接口,还要忙开题,暂时挂起此项目;
挂起之后的主题是软硬件断点、驱动DLL注入和inline hook.
2024/9/21:
补充了两个三个汇编过程,可以根据模块加载的基地址获得:
1.此模块以名字导出的函数的个数;
2.第j个导出函数的名字;
3.第j个导出函数的地址。
2024/9/20:
补全了进程隐藏和进程傀儡两个功能和用户层交互的代码;
遇到了新的蓝屏代码:KERNEL_SECURITY_CHECK_FAILURE:
原因可能是傀儡进程之后没进行链表修复导致过不了关机前的机器检查;
因此加更,现在执行___UNLOAD_DRIVER_PREPARE___逻辑会自动判断并恢复恢复所有隐藏和伪装的进程。
对隐藏进程和傀儡进程的结构采用了双向链表,经测试没有蓝屏和内存泄漏问题出现。
24/9/19深夜补档:
补全了驱动程序目前为止的所有逻辑,支持驱动级内存写入。
测试时发现两个问题:
1.内存大量泄露.
RSL链表某个节点断链时需要释放掉原来这个节点的buffer成员的内存;
并且在不断链时要释放掉原来的内存并重新分配新字符串长度的内存;
之前一个版本忘记了,导致了内存池为DDDD(RSL结构的buffer成员标号)的内存出现了大量泄漏,现在已经解决。
2.蓝屏代码:INVALID_KERNEL_HANDLE.
这个问题是由于驱动程序中关闭了文件句柄后没有将其置为NULL;
导致用户层多次调用___UNLOAD_DRIVER_PREPARE___重复执行了ZwClose(g_kernelProcess)过程;
这访问了已经被释放的内存从而导致了系统蓝屏,现在已经解决。
目前驱动可以在OS:Windows x64 22H2/CPU:I7-9750H架构下驱动平稳运行,不会蓝屏;
并且支持反复测试,在启动驱动之后用户层可以反复调用驱动程序,不必调用一次卸载一次;
而且经过半小时测试也没有内存泄漏现象出现,驱动大体框架已经完工。
2024/9/19:
对链表重新进行了整理,之前的版本是新建一个链表并释放原来的链表;
新版本是直接对老链表进行节点移除,定义了虚拟链表头来辅助移除节点;
改完之后对于大型应用程序的搜索效率更加高效。
2024/9/18:
再一次重构了IOCTL逻辑,重新定义了RSL结构体来进行对比搜索;
目前驱动的大多数基本功能都已经实现,包括
内存遍历,内存查找,内存更改,进程隐藏,模块遍历,模块隐藏,寄存器读取;
内存查找模式支持首次搜索,精确值搜索,变大的数值,变小的数值,未改变的数值;
数值变动基于远端字节判断方法;
在OS:Windows x64 22H2/CPU:I7-9750H架构下驱动平稳运行,不会蓝屏,所有的内存块都没有内存泄漏;
不会蓝屏,不会内存泄漏,没有死锁/死循环风险;
几乎对所有可能蓝屏/内存泄漏/死循环的地方都进行了严格的条件检查;
接下来的工作:整理并优化驱动代码结构/构建用户层应用程序进行交互;
其他开发中的功能:抹PE头,断链,PID篡改,PE特征修改。
2024/9/16:
重构了IOCTL的屎山!逻辑更清晰,支持多次查找和继续查找;
删除了大量的宏定义和typedef,增加可读性;
六块分页内存没有一丁点泄露,所有内存和句柄都被正确释放,基于poolmon.exe检测得出;
但首次引用了全局变量,正在准备开往第二座屎山。。。。
2024/9/12:
IOCTL驱动处理已经快写成屎山了。还出现了一个内存泄漏,但是那个内存泄漏已经解决了;
泄露原因在于释放单链表操作最后一个节点没释放;
Driver_User_IO_Interaction_Entry早晚得重构,不能在屎山上一直拉屎。
2024/9/11:
新增了内核层和用户层的交互,支持用户层传递结构体到驱动;
目前支持内存遍历,字符串搜索,遍历进程的全部线程和全部模块,写入内存。
2024/9/10:
修改了模块遍历,之前由于_LDR_DATA_TABLE_ENTRY结构和_PEB_LDR_DATA弄混了导致偏移量错误导致了不能正确地导出模块地址;
新增了强行写内存,基于修改控制寄存器CR0实现;
知道了KdBreakPoint怎么和Windbg交互了。
2024/9/9:
修复了关机蓝屏的BUG,正确地释放了引用计数。
2024/9/8:
新增进程模块遍历,基于PEB->LDR->InLoadOrderModuleListAddress硬编码指针实现。
2024/9/7:
新增进程隐藏,基于断PE链实现。
2024/9/3:
驱动正常运行,但是一关机就会蓝屏,蓝屏代码为REFERENCE_BY_POINTER。