WinDbg为什么可以轻松分析结构体?本质原因就是它有符号文件并且能够解析它,也就是PDB文件 上一篇中为什么需要把项目目录加到symbol下的原因
应用层编程使用 <windows.h> 提供的各种API函数 MSDN文档
内核编程使用<ntddk.h>提供的各种API函数 (已安装了WDK) WDK文档
未导出函数
WDK说明文档中只包含了内核模块导出的函数,对于未导出的函数,则不能直接使用
如果要使用未导出的函数,自己定义一个函数指针,并且为函数指针提供正确的函数地址就可以使用了。2种办法可以获取导出的函数地址
1.特征码搜索 (硬编码)
2.解析内核PDB文件
驱动基本类型
unsigned long length 不建议这样写
使用WDK自己的类型
ULONG(unsigned long) PULONG(unsigned long*)
UINT(unsigned int) PUINT(unsigned int*)
UCHAR(unsigned char) PUCHAR(unsigned char*)
UVOID(void) PUVOID(void*)
typedef signed char INT8, *PINT8;
typedef signed short INT16, *PINT16;
typedef signed int INT32, *PINT32;
typedef signed __int64 INT64, *PINT64;
typedef unsigned char UINT8, *PUINT8;
typedef unsigned short UINT16, *PUINT16;
typedef unsigned int UINT32, *PUINT32;
typedef unsigned __int64 UINT64, *PUINT64;
返回值
大部分内核函数的返回值都是NTSTATUS类型
//函数举例
NTSTATUS PsCreateSystemThread()
NTSTATUS ZwOpenProcess()
NTSTATUS ZwOpenEvent()
//返回值结果
STATUS_SUCCESS 0x00000000 成功
STATUS_INVALID_PARAMETER 0xC000000D 参数无效
STATUS_BUFFER_OVERFLOW 0x80000005 缓冲区长度不够
其它返回说明 : 参考 ntstatus.h
异常处理
__try {
//可能出错的代码
} __except(filter_value) {
//出错的时候要执行的代码
}
filter_value:
EXCEPTION_EXECUTE_HANDLER(1),代码进入except块
EXCEPTION_CONTINUE_SEARCH(0),不处理异常,由上一层调用函数处理
EXCEPTION_CONTINUE_EXECUTION(-1),回去继续执行错误处的代码
内核内存函数
C语言 内核
malloc ExAllocatePool //非分页内存是常驻内存的,分页内存会被放到文件上
memset RtFillMemory
memcpy RtlMoveMemory
free ExFreePool
内核字符串种类
CHAR(char)/WCHAR(wchar_t)/ANSI_STRING/UNICODE_STRING
ANSI_STRING :
typedef struct _STRING
{
USHORT Length;
USHORT MaximumLength;
PCHAR Buffer;
} STRING;
UNICODE_STRING :
typedef struct _UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
PCHAR Buffer;
} UNICODE_STRING;
内核字符串操作
创建、复制、比较、转换
ANSI_STRING 字符串 UNICODE_STRING 字符串
RtllnitAnsiString RtllnitUnicodeString
RtlCopyString RtlCopyUnicodeString
RtlCompareString RtlCompareUnicodeString
RtlAnsiStringToUnicodeString RtlUnicodeStringToAnsiString
驱动代码详解
#include <ntddk.h>
NTSTATUS UnloadDriver(PDRIVER_OBJECT DriverObject)
{
DbgPrint("Chapter Driver By WingSummer,Unloaded Successfully!");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
DbgPrint("Chapter Driver By WingSummer,Loaded Successfully!");
DriverObject->DriverUnload = UnloadDriver;
return STATUS_SUCCESS;
}
DriverEntry
DriverEntry是驱动程序的入口,如果驱动加载成功后,就像Dll加载成功调用DllMain函数一样,调用该函数。
PDRIVER_OBJECT
PDRIVER_OBJECT是驱动对象的指针
typedef struct _DRIVER_OBJECT {
CSHORT Type;
CSHORT Size;
PDEVICE_OBJECT DeviceObject;
ULONG Flags;
PVOID DriverStart;
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension;
UNICODE_STRING DriverName;
PUNICODE_STRING HardwareDatabase;
PFAST_IO_DISPATCH FastIoDispatch;
PDRIVER_INITIALIZE DriverInit;
PDRIVER_STARTIO DriverStartIo;
PDRIVER_UNLOAD DriverUnload;
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT;
我们看看这个结构 :
kd> dt _DRIVER_OBJECT 89B7FA20
ntdll!_DRIVER_OBJECT
+0x000 Type : 0n4
+0x002 Size : 0n168
+0x004 DeviceObject : (null)
+0x008 Flags : 0x12
+0x00c DriverStart : 0xbab50000 Void
+0x010 DriverSize : 0x6000
+0x014 DriverSection : 0x89936678 Void
+0x018 DriverExtension : 0x89b7fac8 _DRIVER_EXTENSION
+0x01c DriverName : _UNICODE_STRING "\Driver\HelloDriver"
+0x024 HardwareDatabase : 0x80671ae0 _UNICODE_STRING "\REGISTRY\MACHINE\HARDWARE\DESCRIPTION\SYSTEM"
+0x028 FastIoDispatch : (null)
+0x02c DriverInit : 0xbab54000 long HelloDriver!GsDriverEntry+0
+0x030 DriverStartIo : (null)
+0x034 DriverUnload : 0xbab51040 void HelloDriver!UnloadDriver+0
+0x038 MajorFunction : [28] 0x804f454a long nt!IopInvalidDeviceRequest+0
DriverStart :驱动对象加载后的起始地址
DriverSize : 驱动对象加载后的内存大小
DriverName : 驱动对象的名字
DriverUnload : 驱动对象的卸载地址
DriverSection : 存储目前所有已加载的驱动程序信息相关的LDR_DATA_TABLE_ENTRY结构体的双向循环链表。通过这个东西来实现把它们全部串起来,通过这个我们也可以进行遍历
kd> dt _LDR_DATA_TABLE_ENTRY 0x89936678
ntdll!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x80554fc0 - 0x89b80d58 ]
+0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0xffffffff - 0xffffffff ]
+0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x630069 - 0x0 ]
+0x018 DllBase : 0xbab50000 Void
+0x01c EntryPoint : 0xbab54000 Void
+0x020 SizeOfImage : 0x6000
+0x024 FullDllName : _UNICODE_STRING "\??\C:\Documents and Settings\wingsummer\桌面\HelloDriver.sys"
+0x02c BaseDllName : _UNICODE_STRING "HelloDriver.sys"
+0x034 Flags : 0x9104000
+0x038 LoadCount : 1
+0x03a TlsIndex : 0x49
+0x03c HashLinks : _LIST_ENTRY [ 0xffffffff - 0x1055c ]
+0x03c SectionPointer : 0xffffffff Void
+0x040 CheckSum : 0x1055c
+0x044 TimeDateStamp : 0xfffffffe
+0x044 LoadedImports : 0xfffffffe Void
+0x048 EntryPointActivationContext : (null)
+0x04c PatchInformation : 0x00650048 Void
我们可以看下一个成员
kd> dt _LDR_DATA_TABLE_ENTRY 0x89b80d58
ntdll!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x89936678 - 0x89b45e98 ]
+0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0xb8183850 - 0x1 ]
+0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0xe - 0x0 ]
+0x018 DllBase : 0xb817e000 Void
+0x01c EntryPoint : 0xb81a6105 Void
+0x020 SizeOfImage : 0x2b000
+0x024 FullDllName : _UNICODE_STRING "\SystemRoot\system32\drivers\kmixer.sys"
+0x02c BaseDllName : _UNICODE_STRING "kmixer.sys"
+0x034 Flags : 0x9104000
+0x038 LoadCount : 1
+0x03a TlsIndex : 0x74
+0x03c HashLinks : _LIST_ENTRY [ 0xffffffff - 0x2f580 ]
+0x03c SectionPointer : 0xffffffff Void
+0x040 CheckSum : 0x2f580
+0x044 TimeDateStamp : 0xe1786190
+0x044 LoadedImports : 0xe1786190 Void
+0x048 EntryPointActivationContext : (null)
+0x04c PatchInformation : 0x006d006b Void
IRQL
IRQL全称Interrupt Request Level,即中断执行的优先级。它是Windows自己定义的一套优先级方案,与CPU无关,数值越大权限越高。中断包括了硬中断和软中断,硬中断是由硬件产生,而软中断则是完全虚拟出来的。
CPU任何时刻必须处于某一个等级
在同一处理器上,等级高的程序可以打断等级低的程序
HOOK的时候使用的程序等级是 2
缺页异常的 分页处理程序 等级是 2
所以HOOK必须使用非分页内存 分页内存可能遇到缺页异常的情况