首页
社区
课程
招聘
[原创]重载内核之四蓝屏与崩溃处理
发表于: 2014-5-19 22:06 17465

[原创]重载内核之四蓝屏与崩溃处理

2014-5-19 22:06
17465

  重载内核的相关文章实在是太多了,鉴于还是有很多初学者研究这一块,本文仅作为一个引导作用,文笔不好,见谅。
  我的博客: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
第四部分:最后的修正(蓝屏与崩溃)
  终于走到了这里,对于新的NT内核只剩下了两个问题了(其他尚未发现),第一个就是蓝屏,最麻烦的BUG,起初在我遇到的时候也是疯掉了(当时用的还是Windows 7 x86),最后发现是因为内核异常得不到处理造成的,即POOL代码决不能异常。而造成这种现象的就是SafeSEH机制。简要说明就是在内核代码中发生了异常会多一些处理,判断SEH Handler是否有效,再执行。
  现在普遍的解决思路有两个:1.废除SafeSEH机制。2.使POOL合法化。
  先来研究一下这个SafeSEH到底是怎么回事,在发生异常时经过一些处理后会调用RtlDispatchException,进而调用RtlIsValidHandler来判断Handler是否有效,如果无效,你懂得。

BOOLEAN RtlIsValidHandler(IN PEXCEPTION_ROUTINE Handler)
{
    PULONG FunctionTable;
    ULONG FunctionTableLength;
    PVOID Base;

    FunctionTable = RtlLookupFunctionTable(Handler, &Base, &FunctionTableLength);

    if (FunctionTable && FunctionTableLength) {
        PEXCEPTION_ROUTINE FunctionEntry;
        LONG High, Middle, Low;

        if ((FunctionTable == LongToPtr(-1)) && (FunctionTableLength == (ULONG)-1)) {
            // Address is in an image that shouldn't have any handlers (like a resource only dll).
            RtlInvalidHandlerDetected((PVOID)((ULONG)Handler+(ULONG)Base), LongToPtr(-1), -1);
            return FALSE;
        }
    
        // Bias the handler value down by the image base and see if the result
        // is in the table

        (ULONG)Handler -= (ULONG)Base;
        Low = 0;
        High = FunctionTableLength;
        while (High >= Low) {
            Middle = (Low + High) >> 1;
            FunctionEntry = (PEXCEPTION_ROUTINE)FunctionTable[Middle];
            if (Handler < FunctionEntry) {
                High = Middle - 1;
            } else if (Handler > FunctionEntry) {
                Low = Middle + 1;
            } else {
                // found it
                return TRUE;
            }
        }
        // Didn't find it
        RtlInvalidHandlerDetected((PVOID)((ULONG)Handler+(ULONG)Base), FunctionTable, FunctionTableLength);

        return FALSE;
    }

    // Can't verify
    return TRUE;
}
typedef struct _KLDR_DATA_TABLE_ENTRY {
    LIST_ENTRY InLoadOrderLinks;
    PVOID ExceptionTable;
    ULONG ExceptionTableSize;
    // ULONG padding on IA64
    PVOID GpValue;
    PNON_PAGED_DEBUG_INFO NonPagedDebugInfo;
    PVOID DllBase;
    PVOID EntryPoint;
    ULONG SizeOfImage;
    UNICODE_STRING FullDllName;
    UNICODE_STRING BaseDllName;
    ULONG Flags;
    USHORT LoadCount;
    USHORT __Unused5;
    PVOID SectionPointer;
    ULONG CheckSum;
    // ULONG padding on IA64
    PVOID LoadedImports;
    PVOID PatchInformation;
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
PKLDR_DATA_TABLE_ENTRY KeGetImageLdrPointer(PKLDR_DATA_TABLE_ENTRY PsLoadedModuleList, PVOID lpImageAddress)
{
  PKLDR_DATA_TABLE_ENTRY lpTableEntry = PsLoadedModuleList;
  PKLDR_DATA_TABLE_ENTRY lpTablePointer = lpTableEntry;

  do 
  {
    if (lpTablePointer->DllBase == lpImageAddress)
    {
      return lpTablePointer;
    }
    lpTablePointer = (PKLDR_DATA_TABLE_ENTRY)(lpTablePointer->InLoadOrderLinks.Flink);
  } while (lpTableEntry != lpTablePointer);
  return NULL;
}

BOOLEAN KeInsertPsLoadedModuleList(PKLDR_DATA_TABLE_ENTRY PsLoadedModuleList, PVOID NewImage, PVOID OldImage)
{
  PKLDR_DATA_TABLE_ENTRY lpNewLdr, lpSimLdr;

  if (lpSimLdr = KeGetImageLdrPointer(PsLoadedModuleList, OldImage))
  {
    if (lpNewLdr = ExAllocatePool(NonPagedPool, sizeof(KLDR_DATA_TABLE_ENTRY)))
    {
      RtlCopyMemory(lpNewLdr, lpSimLdr, sizeof(KLDR_DATA_TABLE_ENTRY));
      lpNewLdr->DllBase = NewImage;

      InsertTailList(&PsLoadedModuleList->InLoadOrderLinks, &lpNewLdr->InLoadOrderLinks);
      DbgPrint("KeInsertPsLoadedModuleList:0x%p\n", lpNewLdr);
      return TRUE;
    }
  }
  return FALSE;
}

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 4
支持
分享
最新回复 (27)
雪    币: 2847
活跃值: (3859)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
越来越有深度
2014-5-19 22:17
0
雪    币: 220
活跃值: (117)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
先mark然后从头看
2014-5-19 22:33
0
雪    币: 54
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
友情支持 顺便mark
2014-5-19 22:53
0
雪    币: 219
活跃值: (773)
能力值: (RANK:290 )
在线值:
发帖
回帖
粉丝
5
good job
2014-5-19 22:59
0
雪    币: 341
活跃值: (138)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
6
各经一路。。。
2014-5-19 23:54
0
雪    币: 11
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
楼主太有激情了 赞一个 ~!!!
2014-5-20 00:16
0
雪    币: 257
活跃值: (67)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
谢谢分享,mark了
2014-5-20 01:38
0
雪    币: 468
活跃值: (52)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
这样重载,还是不完全保证都走得新内核,我觉得数据段的数据,在新,旧,两份内核内存区内是不同的。所以如果邀你重载第三份内核,你都无法复制数据,因为不知道复制第一份内核的数据,还是复制第二份内核的数据。
所以,如果你重载以后,在进行一次ssdt hook或者inline hook,你将无法再继续重载。当然,如果你记录了第二次重载的各函数地址,可以手工修复ssdt,但对于inline hook,就无法修复。
2014-5-20 06:56
0
雪    币: 77
活跃值: (48)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
mark
2014-5-20 09:04
0
雪    币: 60
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
mark.
2014-5-20 09:35
0
雪    币: 2153
活跃值: (740)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
12
重定位的问题是没有完美解决,但最起码可以绕过绝大部分的HOOK。
数据段的数据是指向原内核的。
为什么要重载第三份内核?我很费解,如果有什么无法绕过的HOOK再具体问题具体分析。
2014-5-20 12:40
0
雪    币: 468
活跃值: (52)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
因为杀毒软件又hook你的第二份oskernel,然后你又重载第三份,又被hook,又第四份。。。
无线重复下去。哈哈哈。。。
但是,慢,你重载第三份的时候,发现数据段,你要复制第一份的数据段,还是复制第二份的数据段呢?要知道第一份和第二份的数据段是不同的。你复制哪一份到第三个内核呢?
2014-5-20 15:23
0
雪    币: 2153
活跃值: (740)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
14
额,好奇怪的逻辑,杀毒软件为什么会hook我的ntoskrnl?
难道它发现重载内核再去hook新内核么?我还没发现过这类软件。
再说它怎么发现?就凭那个KiFastCallEntry么?后面我会考虑另类hook的。
2014-5-20 15:52
0
雪    币: 468
活跃值: (52)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
这很简单,发现ssdt没指向自己的代码,就hook之,你重载后,我一检查,ssdt没指向我的代码,又hook之。
2014-5-20 16:00
0
雪    币: 2153
活跃值: (740)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
16
看来你是没理解我所做的。
“发现ssdt没指向自己的代码,就hook之”,你怎么找新的ssdt呢?又怎么hook呢?
2014-5-20 16:36
0
雪    币: 9
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
这个绝对是原创,没人发过蓝屏处理有关的东西。
2014-12-21 18:28
0
雪    币: 9
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
想请问下楼主你的这句代码:
InsertTailList(&PsLoadedModuleList->InLoadOrderLinks, &lpNewLdr->InLoadOrderLinks);
当驱动卸载后对系统没有影响吗?
2014-12-21 18:35
0
雪    币: 2153
活跃值: (740)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
19
重载后驱动不可卸载,很麻烦,没去研究,仔细点的话应该可以正常卸载的。
2014-12-21 19:25
0
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
mark
2014-12-24 22:32
0
雪    币: 44
活跃值: (186)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
顶顶顶
2014-12-26 15:29
0
雪    币: 188
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
mark下
2014-12-26 15:32
0
雪    币: 21
活跃值: (193)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
在WinXP有测试吗。。
2015-1-22 18:58
0
雪    币: 21
活跃值: (193)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
问下,重载内核之后 一些函数走新内核就很莫名其妙的蓝了。。。 比如我重载内核之后拦截NtConnectPort,NtContinue,NtCreateProcessEx等,立刻蓝屏。。。。。到底为什么
2015-1-22 19:34
0
雪    币: 2153
活跃值: (740)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
25
先确定重定位没问题
kifastcall的hook没问题
基本上就这两个地方了
另附我后来写的重定位处理代码(待测试)
ULONG KeGetAddressCharacteristics(PVOID ImageBase, ULONG Rva)
{
	IMAGE_DOS_HEADER *lpDosHeader = (IMAGE_DOS_HEADER*)ImageBase;
	IMAGE_NT_HEADERS *lpNtHeader = (IMAGE_NT_HEADERS *)((PCHAR)lpDosHeader + lpDosHeader->e_lfanew);
	IMAGE_SECTION_HEADER *Sections = IMAGE_FIRST_SECTION(lpNtHeader);
	ULONG i;

	for (i = 0; i < lpNtHeader->FileHeader.NumberOfSections; i++)
	{
		if (Rva >= Sections[i].VirtualAddress && Rva < (Sections[i].VirtualAddress + Sections[i].Misc.VirtualSize))
		{
			return Sections[i].Characteristics;
		}
	}
	return 0;
}

BOOLEAN KeFixReloc(PVOID Old, PVOID New)
{
	IMAGE_DOS_HEADER *lpDosHeader = (IMAGE_DOS_HEADER*)New;
	IMAGE_NT_HEADERS *lpNtHeader = (IMAGE_NT_HEADERS *)((PCHAR)lpDosHeader + lpDosHeader->e_lfanew);
	IMAGE_BASE_RELOCATION *lpRelocateTable = (IMAGE_BASE_RELOCATION*)((PCHAR)New + lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

	while (lpRelocateTable->SizeOfBlock)
	{
		ULONG NumberOfItems = (lpRelocateTable->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
		USHORT *lpItem = (USHORT*)((PCHAR)lpRelocateTable + sizeof(IMAGE_BASE_RELOCATION));
		ULONG i;

		for (i = 0; i < NumberOfItems; i++)
		{
			switch (lpItem[i] >> 12)
			{
			case IMAGE_REL_BASED_HIGHLOW:
				{
					ULONG *lpFix;
					LONG  Rva;
					PCHAR Fixed;  // 定位到新模块上
					PCHAR UnFixed;// 定位到原模块上
					ULONG Characteristics;
					
					lpFix = (ULONG*)((PCHAR)New + lpRelocateTable->VirtualAddress + (lpItem[i] & 0x0FFF));
					Rva = *lpFix - lpNtHeader->OptionalHeader.ImageBase;
					if (Rva > 0)
					{
						Fixed = (PCHAR)New + Rva;
						UnFixed = (PCHAR)Old + Rva;
						if (KeIsIAT(New, Fixed))
						{
							*lpFix = (ULONG)Fixed;
						}
						else if (Characteristics = KeGetAddressCharacteristics(New, Rva))
						{
							if (Characteristics & (IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA))
							{
								*lpFix = (ULONG)UnFixed;
							}
							else
							{
								*lpFix = (ULONG)Fixed;
							}
						}
						else
						{
							*lpFix = (ULONG)UnFixed;
						}
					}
					else
					{
						return FALSE;
					}
				}
				break;
			case IMAGE_REL_BASED_ABSOLUTE://do nothing
				break;
			default:
				break;
			}
		}
		lpRelocateTable = (IMAGE_BASE_RELOCATION *)((PCHAR)lpRelocateTable + lpRelocateTable->SizeOfBlock);
	}
	return TRUE;
}

总之自己多调试,一定会发现问题,我在精神上支持你。
2015-1-22 20:27
0
游客
登录 | 注册 方可回帖
返回
//