[原创]重载内核之五重载GUI内核
重载内核的相关文章实在是太多了,鉴于还是有很多初学者研究这一块,本文仅作为一个引导作用,文笔不好,见谅。
我的博客:http://blog.csdn.net/sidyhe
开发环境:VS2010 + WinDDK
测试环境:VirtualDDK + VMware + Win7 sp1 x86
第一部分http://bbs.pediy.com/showthread.php?t=187863
第二部分http://bbs.pediy.com/showthread.php?t=187919
第三部分http://bbs.pediy.com/showthread.php?t=187982
第四部分http://bbs.pediy.com/showthread.php?t=188012
第五部分:重载GUI内核
不知道我的叫法对不对,实际上就是重载win32k.sys,有了前面文章的功底,我想重载一个镜像并不难了,只要稍微修改一下ReloadNtModule即可。
g_lpWin32kAddress = KeGetModuleHandle(PsLoadedModuleList, "win32k.sys"); g_lpNewWin32kAddress = ReloadNtModule(PsLoadedModuleList, g_lpWin32kAddress); KeFixReloc2(g_lpNewWin32kAddress, g_lpWin32kAddress); KeInsertPsLoadedModuleList(PsLoadedModuleList, g_lpNewWin32kAddress, g_lpWin32kAddress);
这样就完事儿了,是不是很简单?
接下来去找SHADOW SSDT的原始地址,是存储在一个叫做W32pServiceTable的变量中。大家应该知道所有的系统服务表都是存储在KeServiceDescriptorTableShadow中,最多支持四个表,默认情况下只有两个表,即SSDT与SHADOW SSDT。在系统刚初始化的时候只有一张表,因为此时win32k还没有加载,当它加载的时候会调用KeAddSystemServiceTable来添加第二张服务表,那么思路来了:

代码很简单,就是通过重定位找到调用KeAddSystemServiceTable的地方,判断附近代码,找出变量,其实在整个win32k模块只有一处调用了KeAddSystemServiceTable,很好找的。
PVOID FindW32pServiceTable(PVOID lpWin32kAddress, PVOID lpKeAddSystemServiceTable, ULONG *nApi)
{
IMAGE_DOS_HEADER *lpDosHeader = (IMAGE_DOS_HEADER*)lpWin32kAddress;
IMAGE_NT_HEADERS *lpNtHeader = (IMAGE_NT_HEADERS *)((PCHAR)lpDosHeader + lpDosHeader->e_lfanew);
IMAGE_BASE_RELOCATION *lpRelocateTable = (IMAGE_BASE_RELOCATION*)((PCHAR)lpWin32kAddress + lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
while (lpRelocateTable->SizeOfBlock)
{
if (lpRelocateTable->VirtualAddress)
{
ULONG NumberOfItems = (lpRelocateTable->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
USHORT *lpItem = (USHORT*)((PCHAR)lpRelocateTable + sizeof(IMAGE_BASE_RELOCATION));
ULONG j;
for (j = 0; j < NumberOfItems; j++)
{
if ((lpItem[j] >> 12) == IMAGE_REL_BASED_HIGHLOW)
{
PUCHAR lpFixAddress = (PUCHAR)((PCHAR)lpWin32kAddress + lpRelocateTable->VirtualAddress + (lpItem[j] & 0x0FFF));
/*
PUSH _W32pServiceTable
CALL [KeAddSystemServiceTable]
*/
if (*(lpFixAddress - sizeof(UCHAR)) == 0x68)
{
if (*(PUSHORT)(lpFixAddress + sizeof(PVOID)) == 0x15FF)
{
PVOID lpCallAddress = *(PVOID*)*(ULONG*)(lpFixAddress + sizeof(PVOID) + sizeof(USHORT));
if (lpCallAddress == lpKeAddSystemServiceTable)
{
*nApi = *(ULONG*)*(PVOID*)((PCHAR)lpFixAddress - 11);
return (PVOID)*(ULONG_PTR*)lpFixAddress;
}
}
}
}
}
}
lpRelocateTable = (IMAGE_BASE_RELOCATION *)((PCHAR)lpRelocateTable + lpRelocateTable->SizeOfBlock);
}
return NULL;
}
PVOID BuildW32pServiceTable(PVOID lpNtoskrnlAddress, PVOID lpNewWin32kAddress)
{
PVOID lpW32pServiceTable = NULL;
PVOID lpNewW32pServiceTable = NULL;
PVOID lpKeAddSystemServiceTable = KeGetProcAddress(lpNtoskrnlAddress, "KeAddSystemServiceTable");
ULONG nApi;
if (lpW32pServiceTable = FindW32pServiceTable(lpNewWin32kAddress, lpKeAddSystemServiceTable, &nApi))
{
if (lpNewW32pServiceTable = ExAllocatePool(NonPagedPool, nApi * sizeof(PVOID)))
{
RtlCopyMemory(lpNewW32pServiceTable, lpW32pServiceTable, nApi * sizeof(PVOID));
}
}
return lpNewW32pServiceTable;
}
接下来修改一下过滤函数:
PVOID ServiceCallFilter(PVOID *lppServiceTableBase, ULONG_PTR ServiceIndex)
{
if (lppServiceTableBase == KeServiceDescriptorTable->ServiceTableBase)
{
return g_KeServiceTable[ServiceIndex];
}
else
{
return g_GuiServiceTable[ServiceIndex];
}
}
至此,已经重载了两个内核模块并绕过了NATIVE SSDT/SHADOW SSDT中的函数表HOOK以及INLINE HOOK,代码还有很多不完善的地方,有待大家去找出并修复,其实我也不喜欢拿来主义者和伸手党,仅仅是希望对这一块有兴趣的朋友有所帮助。
感谢topofall指出代码中的问题。
基本上告一段落,但还是有一些东西没有告诉大家,我想还会写一些后续文章的。
待续。
