内核编程学习记录,拒绝做脚本小子!!!
涉及到的未公开数据结构的查询网站
WRK部分开源的KernelCode
火哥6期
宏定义
kPrint
1
| #define kPrint(X,...) DbgPrintEx(77,0,X,__VA_ARGS__)
|
字符串操作
主要是对UnicodeString数据类型的操作,包括格式化输出、ASCII字符串和UNICODE字符串的比较等。
了解UNICODE_SRING类型的内存布局
1 2 3 4 5
| typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING;
|
0x01 格式化输出
1 2 3 4 5 6 7 8 9
| kPrint("[kv]:开始测试格式化输出\r\n"); UNICODE_STRING uString; RtlInitUnicodeString(&uString, L"I am unicodeString");
kPrint("[kv]:%wZ\r\n", &uString); kPrint("[kv]:%ws\r\n", uString.Buffer); kPrint("[kv]:%ls\r\n", uString.Buffer);
|
0x02 宽字符串和UNICODE字符串比较
直接用RtlInitUnicodeString
初始化一个UNICODE字符串,然后用RtlEqualUnicodeString
比较
1 2 3 4 5 6 7 8 9 10 11 12 13
| const wchar_t cmpAstring[] = L"I am unicodeString"; UNICODE_STRING cmpUstring; RtlInitUnicodeString(&cmpUstring, cmpAstring); if (RtlEqualUnicodeString(&uString, &cmpUstring, 0) == TRUE) { kPrint("[kv]:方式一成功\r\n"); } if (!wcscmp(uString.Buffer, cmpAstring)) { kPrint("[kv]:方式二成功\r\n"); } ExFreePoolWithTag(unicodeBuffer, 'tag1');
|
0x03 非宽字符和UNICODE字符串比较
用RtlMultiByteToUnicodeSize
获取生成UNICODE字符串的长度,然后用RtlMultiByteToUnicodeN
转换成宽字符串和UNICODESTRING的buffer比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| const char cmpAstring[] = "I am unicodeString"; ULONG bytesInUnicodeString = 0; RtlMultiByteToUnicodeSize(&bytesInUnicodeString, cmpAstring, strlen(cmpAstring));
PWSTR unicodeBuffer = (PWSTR)ExAllocatePoolWithTag(NonPagedPool, bytesInUnicodeString, 'tag1'); if (!unicodeBuffer) { kPrint("Memory allocation failed.\n"); return; } UNICODE_STRING cmpUstring; cmpUstring.Buffer = unicodeBuffer; cmpUstring.Length = 0; cmpUstring.MaximumLength = (USHORT)bytesInUnicodeString; RtlMultiByteToUnicodeN(cmpUstring.Buffer, bytesInUnicodeString, &cmpUstring.Length, cmpAstring, strlen(cmpAstring)); DbgBreakPoint(); if (RtlEqualUnicodeString(&uString, &cmpUstring, 0) == TRUE) { kPrint("[kv]:方式一成功\r\n"); } if (!wcsncmp(uString.Buffer,cmpUstring.Buffer,uString.Length/sizeof(WCHAR))) { kPrint("[kv]:方式二成功\r\n"); } ExFreePoolWithTag(unicodeBuffer, 'tag1');
|
0x04 封装
KvCmpUnicodeStringA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| BOOLEAN KvCmpUnicodeStringA(PCHAR AString,UNICODE_STRING UString) { ULONG bytesInUnicodeString = 0; RtlMultiByteToUnicodeSize(&bytesInUnicodeString, AString, strlen(AString)); PWSTR unicodeBuffer = (PWSTR)ExAllocatePoolWithTag(NonPagedPool, bytesInUnicodeString, 'tag1'); if (!unicodeBuffer) { kPrint("%s:ExAllocatePoolWithTag Failed\r\n", __FUNCTION__); return FALSE; } RtlMultiByteToUnicodeN(unicodeBuffer, bytesInUnicodeString, NULL, AString, strlen(AString)); if (!wcsncmp(UString.Buffer, unicodeBuffer, UString.Length / sizeof(WCHAR))) { ExFreePoolWithTag(unicodeBuffer, 'tag1'); return TRUE; } ExFreePoolWithTag(unicodeBuffer, 'tag1'); return FALSE; }
|
KvCmpUnicodeStringW
1 2 3 4 5 6 7 8 9 10
| BOOLEAN KvCmpUnicodeStringW(PWCHAR AString, UNICODE_STRING UString) { UNICODE_STRING cmpUstring; RtlInitUnicodeString(&cmpUstring, AString); if (RtlEqualUnicodeString(&UString, &cmpUstring, 0) == TRUE) { return TRUE; } return FALSE; }
|
驱动断链
0x01 数据结构
DRIVER_OBJECT
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| struct _DRIVER_OBJECT { SHORT Type; SHORT Size; struct _DEVICE_OBJECT* DeviceObject; ULONG Flags; VOID* DriverStart; ULONG DriverSize; VOID* DriverSection; struct _DRIVER_EXTENSION* DriverExtension; struct _UNICODE_STRING DriverName; struct _UNICODE_STRING* HardwareDatabase; struct _FAST_IO_DISPATCH* FastIoDispatch; LONG (*DriverInit)(struct _DRIVER_OBJECT* arg1, struct _UNICODE_STRING* arg2); VOID (*DriverStartIo)(struct _DEVICE_OBJECT* arg1, struct _IRP* arg2); VOID (*DriverUnload)(struct _DRIVER_OBJECT* arg1); LONG (*MajorFunction[28])(struct _DEVICE_OBJECT* arg1, struct _IRP* arg2); };
|
_KLDR_DATA_TABLE_ENTRY
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| typedef struct _NON_PAGED_DEBUG_INFO { USHORT Signature; USHORT Flags; ULONG Size; USHORT Machine; USHORT Characteristics; ULONG TimeDateStamp; ULONG CheckSum; ULONG SizeOfImage; ULONGLONG ImageBase; } NON_PAGED_DEBUG_INFO, * PNON_PAGED_DEBUG_INFO;
typedef struct _KLDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderLinks; PVOID ExceptionTable; ULONG ExceptionTableSize; 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; PVOID LoadedImports; PVOID PatchInformation; } KLDR_DATA_TABLE_ENTRY, * PKLDR_DATA_TABLE_ENTRY;
|
0x02 驱动枚举
通过DriverSection找到双向链表,遍历双向链表针对BaseDllName属性进行比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| kPrint("驱动枚举操作\r\n");
PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection; PKLDR_DATA_TABLE_ENTRY preLdr = ldr->InLoadOrderLinks.Flink; PKLDR_DATA_TABLE_ENTRY nxtLdr = ldr->InLoadOrderLinks.Blink; ULONG sum = 1; kPrint("[kv]:%d-%wZ\r\n", sum, &ldr->BaseDllName); while (preLdr != nxtLdr) { sum++; UNICODE_STRING baseName = preLdr->BaseDllName; kPrint("[kv]:%d-%wZ\r\n", sum,&baseName); preLdr = preLdr->InLoadOrderLinks.Flink; }
|
0x03 驱动断链
浅层断链
找到指定驱动后用RemoveEntryList
函数断链,还是会被PCHunter找到并列入隐藏驱动名单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection; PKLDR_DATA_TABLE_ENTRY preLdr = ldr->InLoadOrderLinks.Flink; PKLDR_DATA_TABLE_ENTRY nxtLdr = ldr->InLoadOrderLinks.Blink; UNICODE_STRING target; RtlInitUnicodeString(&target, L"HTTP.sys"); while (preLdr != nxtLdr) { UNICODE_STRING baseName = preLdr->BaseDllName; if (RtlEqualUnicodeString(&target, &baseName, TRUE)) { RemoveEntryList(&preLdr->InLoadOrderLinks); kPrint("[kv]:find %wZ\r\n", &baseName); break; } preLdr = preLdr->InLoadOrderLinks.Flink; }
|
深层断链
对驱动程序对象的部分属性进行抹除即可让PCHunter检测不到
- 引入非导出的函数
ObReferenceObjectByName
1 2 3 4 5 6 7 8 9 10 11 12 13
| NTKERNELAPI NTSTATUS ObReferenceObjectByName( __in PUNICODE_STRING ObjectName, __in ULONG Attributes, __in_opt PACCESS_STATE AccessState, __in_opt ACCESS_MASK DesiredAccess, __in POBJECT_TYPE ObjectType, __in KPROCESSOR_MODE AccessMode, __inout_opt PVOID ParseContext, __out PVOID* Object ); extern POBJECT_TYPE * IoDriverObjectType;
|
- 实现深层断链
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection; PKLDR_DATA_TABLE_ENTRY preLdr = ldr->InLoadOrderLinks.Flink; PKLDR_DATA_TABLE_ENTRY nxtLdr = ldr->InLoadOrderLinks.Blink; UNICODE_STRING target; RtlInitUnicodeString(&target, L"HTTP.sys"); UNICODE_STRING objectName; RtlInitUnicodeString(&objectName, L"\\Driver\\http"); while (preLdr != nxtLdr) { UNICODE_STRING baseName = preLdr->BaseDllName; if (RtlEqualUnicodeString(&target, &baseName, TRUE)) { PDRIVER_OBJECT driverObject = NULL; NTSTATUS st = ObReferenceObjectByName(&objectName, FILE_ALL_ACCESS, 0, 0, *IoDriverObjectType, KernelMode, NULL, &driverObject); if (!NT_SUCCESS(st)) { kPrint("[kv]:ObReferenceObjectByName faild st:0x%x\r\n", st); return; RemoveEntryList(&preLdr->InLoadOrderLinks); driverObject->DriverSection = 0; DriverObject->DriverInit = 0; kPrint("[kv]:断链%wZ成功\r\n", &baseName); break; } preLdr = preLdr->InLoadOrderLinks.Flink; }
|
效果图
被列入可疑驱动对象名单
自我断链
在驱动主要功能实现完毕即将返回前,创建一个延迟线程(KeDelayExecutionThread),等驱动返回之后抹除驱动特征(DriverInit、DriverSection),直接抹除会因为DriverEntry结束之后继续调用驱动特征属性导致蓝屏。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| typedef struct _DriverHideContext { PWCH objectName; PDRIVER_OBJECT DriverObject; }DriverHideContext,*PDriverHideContext; NTSTATUS DriverHide(PDriverHideContext context) { LARGE_INTEGER interval = { 0 }; interval.QuadPart = -10000 * 5000; KeDelayExecutionThread(KernelMode, FALSE,&interval); PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)context->DriverObject->DriverSection; UNICODE_STRING target; RtlInitUnicodeString(&target,context->objectName); PDRIVER_OBJECT driverObject; NTSTATUS st = ObReferenceObjectByName(&target, FILE_ALL_ACCESS, 0, 0, *IoDriverObjectType, KernelMode, NULL, &driverObject); if (!NT_SUCCESS(st)) { ExFreePool(context); kPrint("[kv]:%s-ObReferenceObjectByName failed 0x%x\r\n", __FUNCTION__, st); return st; } RemoveEntryList(&ldr->InLoadOrderLinks); driverObject->DriverInit = 0; driverObject->DriverSection = 0; ExFreePool(context); ObDereferenceObject(driverObject); return STATUS_SUCCESS; } VOID mainTest() { HANDLE threadHandle; PDriverHideContext context = (PDriverHideContext)ExAllocatePool(NonPagedPool, sizeof(PDriverHideContext)); context->objectName = L"\\Driver\\driverStudy"; context->DriverObject = DriverObject; NTSTATUS st = PsCreateSystemThread(&threadHandle, THREAD_ALL_ACCESS, NULL, NULL,NULL, DriverHide, context); if (NT_SUCCESS(st)) { NtClose(threadHandle); } }
|
效果图
0x04 封装
KvEnumAllKernelModules
遍历双向链表枚举内核模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| VOID KvEnumAllKernelModules(PDRIVER_OBJECT DriverObject) { PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection; PKLDR_DATA_TABLE_ENTRY preLdr = ldr->InLoadOrderLinks.Flink; PKLDR_DATA_TABLE_ENTRY nxtLdr = ldr->InLoadOrderLinks.Blink;
ULONG sum = 1; kPrint("[kv]:%d-%wZ\r\n", sum, &ldr->BaseDllName); while (preLdr != nxtLdr) { sum++; UNICODE_STRING baseName = preLdr->BaseDllName; kPrint("[kv]:%d-%wZ\r\n", sum, &baseName); preLdr = preLdr->InLoadOrderLinks.Flink; } }
|
KvChainBreak
对指定名称的驱动进行断链
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| NTSTATUS KvChainBreak(PDRIVER_OBJECT DriverObject,PWCH targetDriverName) { PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection; PKLDR_DATA_TABLE_ENTRY preLdr = ldr->InLoadOrderLinks.Flink; PKLDR_DATA_TABLE_ENTRY nxtLdr = ldr->InLoadOrderLinks.Blink; UNICODE_STRING target; RtlInitUnicodeString(&target, targetDriverName); PWCH prefix = L"\\Driver\\"; ULONG totalLen = 8 + wcslen(targetDriverName) - 4; PWCH totalStr = (PWCH)ExAllocatePool(NonPagedPool, sizeof(WCHAR)*(totalLen+1)); wcscpy(totalStr,prefix); wcsncat(totalStr + 8, targetDriverName, wcslen(targetDriverName) - 4); totalStr[totalLen] = NULL; UNICODE_STRING objectName; RtlInitUnicodeString(&objectName, totalStr); while (preLdr != nxtLdr) { UNICODE_STRING baseName = preLdr->BaseDllName; if (RtlEqualUnicodeString(&target, &baseName, TRUE)) { PDRIVER_OBJECT driverObject = NULL; NTSTATUS st = ObReferenceObjectByName(&objectName, FILE_ALL_ACCESS, 0, 0, *IoDriverObjectType, KernelMode, NULL, &driverObject); if (!NT_SUCCESS(st)) { kPrint("[kv]:ObReferenceObjectByName faild st:0x%x\r\n", st); ExFreePool(totalStr); return st; }
RemoveEntryList(&preLdr->InLoadOrderLinks); driverObject->DriverSection = 0; DriverObject->DriverInit = 0; ExFreePool(totalStr); return STATUS_SUCCESS; } preLdr = preLdr->InLoadOrderLinks.Flink; } ExFreePool(totalStr); return STATUS_NOT_FOUND; }
|
KvChainBreakSelfThread
线程函数,用于驱动自我断链
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| VOID KvChainBreakSelfThread(PDriverHideContext context) { LARGE_INTEGER interval = { 0 }; interval.QuadPart = 10000000 * context->delayTime; KeDelayExecutionThread(KernelMode, FALSE, &interval); PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)context->DriverObject->DriverSection; UNICODE_STRING target; RtlInitUnicodeString(&target, context->objectName); PDRIVER_OBJECT driverObject; NTSTATUS st = ObReferenceObjectByName(&target, FILE_ALL_ACCESS, 0, 0, *IoDriverObjectType, KernelMode, NULL, &driverObject); if (!NT_SUCCESS(st)) { ExFreePool(context); kPrint("[kv]:%s-ObReferenceObjectByName failed 0x%x\r\n", __FUNCTION__, st); return; } RemoveEntryList(&ldr->InLoadOrderLinks); driverObject->DriverInit = 0; driverObject->DriverSection = 0; ExFreePool(context); ObDereferenceObject(driverObject); }
|
KvChainBreakSelf
驱动自我断链函数,调用KvChainBreakSelfThread
线程函数抹除驱动特征
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| VOID KvChainBreakSelf(PDRIVER_OBJECT DriverObject,PWCH objectName, ULONG delayTime)
{ HANDLE threadHandle; PDriverHideContext conText = (PDriverHideContext)ExAllocatePool(NonPagedPool, sizeof(DriverHideContext)); conText->delayTime = -10000 * 1000 * delayTime; conText->DriverObject = DriverObject; conText->objectName = objectName; NTSTATUS nt = PsCreateSystemThread(&threadHandle, FILE_ALL_ACCESS, NULL, NULL, NULL, KvChainBreakSelfThread, conText); if (NT_SUCCESS(nt)) { NtClose(threadHandle); } ExFreePool(conText); }
|