欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]重载内核之六接管流程进阶

[原创]重载内核之六接管流程进阶

  重载内核的相关文章实在是太多了,鉴于还是有很多初学者研究这一块,本文仅作为一个引导作用,文笔不好,见谅。
  我的博客: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
  第五部分http://bbs.pediy.com/showthread.php?t=188050
第六部分:IDT HOOK
  对我来说IDT一直是一个很难理解的东西,尤其是段选择子什么的,这里我不敢教大家如何HOOK IDT表,我只会INLINE HOOK,囧。再说每一个CPU都有各自独立的IDT表,做HOOK的话每一个CPU都要处理,也很麻烦。
  为什么要HOOK IDT?除了正常的服务请求会经过KiFastCallEntry,那么不正常的就只能走中断门了,比如DEBUG,BREAKPOINT等等,我想这是大家有兴趣的地方。
  和之前一样,对于大部分函数表来说,在NT内核中都会有一个对应的地方来存储原始地址,初始化函数是在KiSystemStartup中,但是WRK里并没有源代码,被可恶的编译成了lib文件,所以来看IDA吧:


  显然这里的77E164也可以理解为是一个函数表,里面存储了中断门的线性地址,起个名字吧,我自己叫做KiTrapTable,不知道对不对。有一个特点就是这个地址表并不是元素连续的,每隔一个才是地址,也就是中断函数地址=函数表[索引*2],至于另外一个元素是什么我就不敢断言了,老办法,利用重定位来搜索:


PVOID FindKiTrapTable(PVOID lpNtoskrnlAddress)

{

	IMAGE_DOS_HEADER *lpDosHeader = (IMAGE_DOS_HEADER*)lpNtoskrnlAddress;

	IMAGE_NT_HEADERS *lpNtHeader = (IMAGE_NT_HEADERS *)((PCHAR)lpDosHeader + lpDosHeader->e_lfanew);

	IMAGE_BASE_RELOCATION *lpRelocateTable = (IMAGE_BASE_RELOCATION*)((PCHAR)lpNtoskrnlAddress + 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)lpNtoskrnlAddress + lpRelocateTable->VirtualAddress + (lpItem[j] & 0x0FFF));

					/*

					MOV  ESI, OFFSET KiTrapTable

					MOV  ECX, 0x0800

					SHR  ECX, 2

					REP  MOVSD

					*/

					if (*(lpFixAddress - sizeof(UCHAR)) == 0xBE)

					{

						UCHAR CodeBytes[] = {0xB9, 0x00, 0x08, 0x00, 0x00, 0xC1, 0xE9, 0x02, 0xF3, 0xA5};

						if (RtlEqualMemory(lpFixAddress + sizeof(PVOID), CodeBytes, sizeof(CodeBytes)))

						{

							return (PVOID)*(ULONG*)lpFixAddress;

						}

					}

				}

			}

		}

		lpRelocateTable = (IMAGE_BASE_RELOCATION *)((PCHAR)lpRelocateTable + lpRelocateTable->SizeOfBlock);

	}

	return NULL;

}

PVOID BuildKiTrapTable(PVOID lpNtoskrnlAddress)

{

	PVOID lpKiTrapTable = NULL;

	PVOID lpNewKiTrapTable = NULL;

	if (lpKiTrapTable = FindKiTrapTable(lpNtoskrnlAddress))

	{

		if (lpNewKiTrapTable = ExAllocatePool(NonPagedPool, sizeof(PVOID) * 0xFF * 2))

		{

			RtlCopyMemory(lpNewKiTrapTable, lpKiTrapTable, sizeof(PVOID) * 0xFF * 2);

			DbgPrint("BuildKiTrapTable:%08X\n", lpKiTrapTable);

		}

	}

	return lpNewKiTrapTable;

}


  找到原始地址,INLINE HOOK就非常简单了,直接在函数头写JMP到新内核中或者额外处理什么,这里我就不再贴代码了,节省篇幅。
  其实HOOK IDT并没有什么很大的意义,毕竟正常的内核调用都是调用sysenter的,也是HOOK竞争最激烈的地方,把握住了这里,就可以绕过绝大部分的钩子。
  当然对于反反调试,接管IDT中的调试相关中断还是很有用的,具体怎么做那就不是我的事儿了,大家各自发挥,对症下药吧。
  也许还有后续内容,也许直接是一个总结,希望大家能够在技术上得到真正的提高,不论大家重载内核的目的纯洁与否,学到东西才是最长久的。也不要认为x86在远离我们就开始忽视,其实x64也是建立在x86的基础上,变化不是很大,对于底层要进行革命性的变化还要好久好久。

上传的附件 00.jpg
01.jpg
6.重载内核之接管流程进阶.doc

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功