[原创]重载内核之二接管流程
发表于:
2014-5-17 07:53
10865
重载内核的相关文章实在是太多了,鉴于还是有很多初学者研究这一块,本文仅作为一个引导作用,文笔不好,见谅。
我的博客:http://blog.csdn.net/sidyhe
开发环境:VS2010 + WinDDK
测试环境:VirtualDDK + VMware + Win7 sp1 x86
第一部分链接:http://bbs.pediy.com/showthread.php?t=187863
第二部分:接管流程
在第一部分完成之后,已经重载了一份新的NT内核,接下来就是接管执行流程。
自Windows XP以后从RING3进RING0统一调用sysenter汇编指令,但仍保留了INT 2E中断,在sysenter调用之后会执行内核空间中的KiFastCallEntry函数,这个函数负责所有的应用层请求,即使是INT 2E也会走这个函数,而KiFastCallEntry在经过简单的处理后会通过KeServiceDescriptorTable或者KeServiceDescriptorTableShadow来获取内核函数指针并调用,重载内核的目的就是为了在执行内核函数的时候转移到新的模块上,从而不被其他HOOK所影响。那么需要做的就是在调用内核函数的时候转移指令,但并不是所有内核函数都由ntoskrnl实现,内核中GUI函数却是由win32k.sys实现,由于目前只重载了ntoskrnl,所以只能做到转移SSDT中的函数。额外说明一下,即使NT内核有不同的版本,但所有NT内核的导出模块名称都是ntoskrnl.exe(详见输出表),所以我所说的ntoskrnl泛指NT内核,而不是具体的文件名。
在KiFastCallEntry中调用内核函数的地方大家很容易找到资料,最先是谁提出的我记不清了,反正现在是被某出名软件所使用,下面HOOK的地方与其他软件可能会冲突,所以在测试的时候需要保证没有安装任何安全软件。
用户态程序调用内核函数的流程简述为:用户态->ntdll.ZwApi->sysenter->内核态->KiFastCallEntry->ServiceTable->ServiceRoutine。ServiceTable分为两种,上面已经提到了,接下来要做的就是在调用SSDT中函数的时候转移到新模块上,在WRK中可以找到这样的代码:
mov esi, edx ; (esi)->User arguments
mov ebx, [edi]+SdNumber ; get argument table address
xor ecx, ecx
mov cl, byte ptr [ebx+eax] ; (ecx) = argument size
mov edi, [edi]+SdBase ; get service table address
mov ebx, [edi+eax*4] ; (ebx)-> service routine
sub esp, ecx ; allocate space for arguments
shr ecx, 2 ; (ecx) = number of argument DWORDs
mov edi, esp ; (edi)->location to receive 1st arg
//省略部分代码
call ebx ; call system service
PVOID __declspec(naked) _GetKiFastCallEntryAddress()
{
__asm
{
MOV ECX, 0x00000176;
RDMSR;
RETN;
}
}
PVOID FindHookKiFastCallEntryAddress(PVOID lpKiFastCallEntry)
{
/*
sub esp, ecx
shr ecx, 2
mov edi, esp
*/
UCHAR HookBytes[] = {0x2B, 0xE1, 0xC1, 0xE9, 0x02, 0x8B, 0xFC};
return RtlFindMemory(lpKiFastCallEntry, 0x300, HookBytes, sizeof(HookBytes));
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
上传的附件: