cess);
pid = *(pulong)(((pchar)peprocess)+0x9c);
if(pid == 0x8)
continue;
pfakeethread = exallocatepool(pagedpool,sizeof(fake_ethread));
memcpy(pfakeethread, pethread,sizeof(fake_ethread));
insertheadlist(pkiwaitinlisthead, &pfakeethread->waitlistentry);
}
...休息一段时间
}
首先每过一小段时间就把原来的线程调度链表清空,然后遍历当前的线程调度链,判断链中的每一个kprocess块是不是要属于要隐藏的进程线程,如果是就跳过,不是就自己构造一个ethread块把当前的信息拷贝过去,然后把自己构造的ethread块加入到原来的调度链表中。为什么要自己构造一个ethread?其原因主要有2个,其一为了使检测系统看起来更可信,如果仅仅清空原来的线程调度链表那么检测系统将查不出来任何的线程和进程信息,
很明显,这无疑不打自招的说,系统里面已经有东西了。其二,如果把自己构造的ethread块挂接在原调度链表中,检测系统会访问挂在原来调度链表上的ethread块里面的成员,如果不自己构造一个和真实ethread块重要信息一样的块,那么检测系统很有可能出现非法访问,然后就boom兰屏了。
实际上所谓的绕过系统检测仅仅是针对基于线程调度的检测进程的防御系统而言的,其实系统依旧在进行线程调度,访问的是我们新建的链表头部。而检测系统访问的是原来的头部,他后面的数据项是我们自己申请的,系统并不访问。
5.检测绕过内核调度链表隐藏进程
一般情况下我们是通过内核调试器得到那三条链表的内核地址,然后进行枚举。这就给隐藏者留下了机会,如上面所示。但是我们完全可以把上面那种隐藏进程检测出来。我们也通过在内核函数中取得硬编码的办法来分别取得他们的链表头的地址。如上面我们已经看见了 kifindreadythread+0x48+3出就是kidispatcherreadylisthead的地址,如果用上面的绕过内核调度链表检测办法同时也去要修改kifindreadythread+0x48+3的值为新链表的头部地址。所以我们的检测系统完全可以从kifindreadythread+0x48+3(0x804313de)去取得kidispatcherreadylisthead的值。同理kiwaitinlisthead, kiwaitoutlisthead也都到使用他们的相应的内核函数里面去取得地址。就算原地址被修改过,我们也能把修改过后的调度链表头给找出来。所以欺骗就不行了。
hook 内核函数(kireadythread)检测进程
1.介绍通用hook内核函数的方法
当我们要拦截目标函数的时候,只要修改原函数头5个字节的机器代码为一个jmp xxxxxxxx(xxxxxxxx是距自己的hook函数的偏移量)就行了。并且保存原来修改前的5个字节。在跳入原函数时,恢复那5个字节即可。
char jmpmycode [] = {0xe9,0x00,0x00,0x00,0x00};//e9对应jmp偏移量指令
*((ulong*)(jmpmycode+1))=(ulong)myfunc-(ulong)orgdestfunction-5;//获得偏移量
memcpy(orgcode,(char*)orgdestfunction,5);//保存原来的代码
memcpy((char*)orgdestfunction,jmpmycode,5);//覆盖前一个命令为一个跳转指令
在系统内核级中,ms的很多信息都没公开,包括函数的参数数目,每个参数的类型等。在系统内核中,访问了大量的寄存器,而很多寄存器的值,是上层调用者提供的。如果值改变系统就会变得不稳定。很可能出现不可想象的后果。另外有时候对需要hook的函数的参数不了解,所以不能随便就去改变它的堆栈,如果不小心也有可能导致蓝屏。所以hook的最佳原则是在自己的hook函数中呼叫原函数的时候,所有的寄存器值,堆栈里面的值和hook前的信息一样。这样就能保证在原函数中不会出错。一般我们自己的hook的函数都是写在c文件里面的。例如hook的目标函数kireadythread。那么一般就自己实现一个:
mykireadythread(...)
{
......
call kireadythread
......
}
但是用c编译器编译出来的代码会出现一个堆栈帧:
push ebp
mov ebp,esp
这就和我们的初衷不改变寄存器的数违背了。所以我们可以自己用汇编来实mykireadythread。
_mykireadythread @0 proc
pushad ;保存通用寄存器
call _cfunc@0 ;这里是在进入原来函数前进行的一些处理。
popad ;恢复通用寄存器
push eax
mov eax,[esp+4] ;得到系统在call 目标函数时入栈的返回地址。
mov ds:_orgret,eax ;保存在一个临时变量中
<< 上一页 [11] [12] [13] [14] 下一页