#include <ntifs.h> #include <windef.h> /* Zw层次的注册表操作很简单。 但是做与不做还是有点区别的。 made by correy made at 2014.07.24 homepage:http://correy.webs.com */ NTSTATUS ZwEnumerateKeyEx(IN UNICODE_STRING * Name) /* 显示一个注册表的键下的:子键,名字,类型,数据。 注意:没有递归显示。 */ { NTSTATUS Status = STATUS_UNSUCCESSFUL; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE KeyHandle; PKEY_FULL_INFORMATION pfi; ULONG ResultLength; ULONG i = 0; InitializeObjectAttributes(&ObjectAttributes, Name, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); if( !NT_SUCCESS( Status ) ) { return Status; } /* 注意ZwQueryKey的第一个参数。 The KeyHandle passed to ZwQueryKey must have been opened with KEY_QUERY_VALUE access. This is accomplished by passing KEY_QUERY_VALUE, KEY_READ, or KEY_ALL_ACCESS as the DesiredAccess parameter to ZwCreateKey or ZwOpenKey. */ // 第一次调用是为了获取需要的长度 Status = ZwQueryKey(KeyHandle, KeyFullInformation, NULL, 0, &ResultLength); if( !NT_SUCCESS( Status ) ) { if (Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) //STATUS_BUFFER_OVERFLOW这个情况应该不会发生在这种情况下。 { //在下面申请内存。 } else { ZwClose(KeyHandle); return Status; } } //ResultLength += MAX_PATH ; //ResultLength *= 2;//多申请一半。 pfi = (PKEY_FULL_INFORMATION)ExAllocatePool(NonPagedPool, ResultLength); if (pfi == NULL) { //If ExAllocatePool returns NULL, the caller should return the NTSTATUS value STATUS_INSUFFICIENT_RESOURCES or should delay processing to another point in time. Status = STATUS_INSUFFICIENT_RESOURCES; ZwClose(KeyHandle); return Status; } // 第二次调用是为了获取数据 Status = ZwQueryKey(KeyHandle, KeyFullInformation, pfi, ResultLength, &ResultLength);//少了赋值。这等低级的错误。 if( !NT_SUCCESS( Status ) ) { ExFreePool(pfi); ZwClose(KeyHandle); return Status; } //枚举子键。 for (i = 0; i < pfi->SubKeys; i++) { PKEY_BASIC_INFORMATION pbi; UNICODE_STRING us; // 获取第i个子项的长度 Status = ZwEnumerateKey(KeyHandle, i, KeyBasicInformation, NULL, 0, &ResultLength); if( !NT_SUCCESS( Status ) ) { if (Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) //STATUS_BUFFER_OVERFLOW这个情况应该不会发生在这种情况下。 { //在下面申请内存。 } else { break; } } pbi = (PKEY_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, ResultLength); if (pbi == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } // 获取第i个子项的数据 Status = ZwEnumerateKey(KeyHandle, i, KeyBasicInformation, pbi, ResultLength, &ResultLength); if( !NT_SUCCESS( Status ) ) { ExFreePool(pbi); break; } us.Buffer = pbi->Name; us.Length = (USHORT)pbi->NameLength; us.MaximumLength = us.Length; DbgPrint("subkey:%wZ\n", &us); /* 在这里组合字符串,可以考虑递归枚举。 */ ExFreePool(pbi);// 释放内存 } //枚举名字,类型,数据。 for (i = 0; i < pfi->Values; i++) //可以考虑用ZwQueryValueKey获取数量。MSDN关于这个成员的解释是:The number of value entries for this key. { PKEY_VALUE_BASIC_INFORMATION pkvbi; UNICODE_STRING us; PKEY_VALUE_PARTIAL_INFORMATION pkvpi; UNICODE_STRING data; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 获取名字及类型。 Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueBasicInformation, NULL, 0, &ResultLength); if( !NT_SUCCESS( Status ) ) { if (Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) //STATUS_BUFFER_OVERFLOW这个情况应该不会发生在这种情况下。 { //在下面申请内存。 } else { break; } } pkvbi = (PKEY_VALUE_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, ResultLength); if (pkvbi == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueBasicInformation, pkvbi, ResultLength, &ResultLength); if( !NT_SUCCESS( Status ) ) { ExFreePool(pkvbi); break; } us.Buffer = pkvbi->Name; us.Length = (USHORT)pkvbi->NameLength; us.MaximumLength = us.Length; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 获取数据 Status = ZwEnumerateValueKey(KeyHandle, i, KeyValuePartialInformation, NULL, 0, &ResultLength); if( !NT_SUCCESS( Status ) ) { if (Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) //STATUS_BUFFER_OVERFLOW这个情况应该不会发生在这种情况下。 { //在下面申请内存。 } else { ExFreePool(pkvbi); break; } } pkvpi = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(NonPagedPool, ResultLength); if (pkvpi == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; ExFreePool(pkvbi); break; } Status = ZwEnumerateValueKey(KeyHandle, i, KeyValuePartialInformation, pkvpi, ResultLength, &ResultLength); if( !NT_SUCCESS( Status ) ) { ExFreePool(pkvpi); ExFreePool(pkvbi); break; } data.Buffer = (PWCH)pkvpi->Data;//有的数据可能无法显示。 data.Length = (USHORT)pkvpi->DataLength; data.MaximumLength = data.Length; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// DbgPrint("name:%wZ,type:%d,data:%wZ\n", &us, pkvbi->Type, &data); ExFreePool(pkvbi);// 释放内存 ExFreePool(pkvpi); } ExFreePool(pfi); ZwClose(KeyHandle); return Status; } DRIVER_UNLOAD Unload; VOID Unload(__in PDRIVER_OBJECT DriverObject) { } DRIVER_INITIALIZE DriverEntry; NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath) { NTSTATUS status = STATUS_UNSUCCESSFUL; UNICODE_STRING test = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control");//\\Session Manager KdBreakPoint(); DriverObject->DriverUnload = Unload; status = ZwEnumerateKeyEx(&test); if( !NT_SUCCESS( status ) ) { DbgPrint("ZwEnumerateKeyEx fail with 0x%x\n", status); } return status;//STATUS_SUCCESS } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include <ntifs.h> #include <windef.h> #define TAG 'tset' //test NTSTATUS ZwCopyKey(IN UNICODE_STRING * Name, IN UNICODE_STRING * Name2) /* 复制一个注册表的键下的:子键,名字,类型,数据。 注意: 1.没有递归复制。 2.没有复制(安全)属性。 3.没有对参数的有效性进行检查。字符串的末尾不要带L'\\'. 4.确认使用前这两个路径是存在的。 5.更多的缺陷,请你补充纠正。更多的功能等待你的发挥。 */ { NTSTATUS Status = STATUS_UNSUCCESSFUL; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE KeyHandle; HANDLE KeyHandle3; PKEY_FULL_INFORMATION pfi; ULONG ResultLength; ULONG i = 0; InitializeObjectAttributes(&ObjectAttributes, Name, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes); if( !NT_SUCCESS( Status ) ) { return Status; } /* 注意ZwQueryKey的第一个参数。 The KeyHandle passed to ZwQueryKey must have been opened with KEY_QUERY_VALUE access. This is accomplished by passing KEY_QUERY_VALUE, KEY_READ, or KEY_ALL_ACCESS as the DesiredAccess parameter to ZwCreateKey or ZwOpenKey. */ // 第一次调用是为了获取需要的长度 Status = ZwQueryKey(KeyHandle, KeyFullInformation, NULL, 0, &ResultLength); if( !NT_SUCCESS( Status ) ) { if (Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) //STATUS_BUFFER_OVERFLOW这个情况应该不会发生在这种情况下。 { //在下面申请内存。 } else { ZwClose(KeyHandle); return Status; } } //ResultLength += MAX_PATH ; //ResultLength *= 2;//多申请一半。 pfi = (PKEY_FULL_INFORMATION)ExAllocatePool(NonPagedPool, ResultLength); if (pfi == NULL) { //If ExAllocatePool returns NULL, the caller should return the NTSTATUS value STATUS_INSUFFICIENT_RESOURCES or should delay processing to another point in time. Status = STATUS_INSUFFICIENT_RESOURCES; ZwClose(KeyHandle); return Status; } // 第二次调用是为了获取数据 Status = ZwQueryKey(KeyHandle, KeyFullInformation, pfi, ResultLength, &ResultLength);//少了赋值。这等低级的错误。 if( !NT_SUCCESS( Status ) ) { ExFreePool(pfi); ZwClose(KeyHandle); return Status; } //枚举子键。 for (i = 0; i < pfi->SubKeys; i++) { PKEY_BASIC_INFORMATION pbi; UNICODE_STRING us; UNICODE_STRING new_key ; OBJECT_ATTRIBUTES ob; HANDLE KeyHandle2 = 0; PUNICODE_STRING Class = NULL; ULONG Disposition; // 获取第i个子项的长度 Status = ZwEnumerateKey(KeyHandle, i, KeyBasicInformation, NULL, 0, &ResultLength); if( !NT_SUCCESS( Status ) ) { if (Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) //STATUS_BUFFER_OVERFLOW这个情况应该不会发生在这种情况下。 { //在下面申请内存。 } else { break; } } pbi = (PKEY_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, ResultLength); if (pbi == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } // 获取第i个子项的数据 Status = ZwEnumerateKey(KeyHandle, i, KeyBasicInformation, pbi, ResultLength, &ResultLength); if( !NT_SUCCESS( Status ) ) { ExFreePool(pbi); break; } us.Buffer = pbi->Name; us.Length = (USHORT)pbi->NameLength; us.MaximumLength = us.Length; DbgPrint("subkey:%wZ\n", &us); //开始新建。 new_key.Buffer = (wchar_t *)ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG); if (new_key.Buffer == NULL) { ExFreePool(pbi); Status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlZeroMemory(new_key.Buffer, MAX_PATH); RtlInitEmptyUnicodeString(&new_key, new_key.Buffer,MAX_PATH); RtlCopyUnicodeString(&new_key,Name2); Status = RtlAppendUnicodeToString(&new_key, L"\\"); if (!NT_SUCCESS (Status)) { ExFreePool(new_key.Buffer); ExFreePool(pbi); Status = STATUS_INSUFFICIENT_RESOURCES; break; } Status = RtlAppendUnicodeStringToString(&new_key, &us); if (!NT_SUCCESS (Status)) { ExFreePool(new_key.Buffer); ExFreePool(pbi); Status = STATUS_INSUFFICIENT_RESOURCES; break; } InitializeObjectAttributes(&ob, &new_key, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0); Status = ZwCreateKey(&KeyHandle2, KEY_WRITE, &ob, 0, Class, REG_OPTION_NON_VOLATILE, &Disposition);//KEY_ALL_ACCESS KEY_READ if (!NT_SUCCESS (Status)) { //如果子键已经存在,返回正确。 ExFreePool(new_key.Buffer); ExFreePool(pbi); Status = STATUS_INSUFFICIENT_RESOURCES; break; } else { if (KeyHandle2)//断言FileHandle不等于0也不是无效的句柄。 { Status = ZwClose(KeyHandle2); if (!NT_SUCCESS (Status)) { KdPrint(("ZwClose fail with 0x%x.\n", Status)); } } } /* 在这里组合字符串,可以考虑递归。 */ ExFreePool(pbi);// 释放内存 ExFreePool(new_key.Buffer); } //处理上面失败的情况。主要是for 循环。 if( !NT_SUCCESS( Status ) ) { ExFreePool(pfi); ZwClose(KeyHandle); return Status; } InitializeObjectAttributes(&ObjectAttributes, Name2, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenKey(&KeyHandle3, KEY_ALL_ACCESS, &ObjectAttributes); if( !NT_SUCCESS( Status ) ) { ExFreePool(pfi); ZwClose(KeyHandle); return Status; } //枚举名字,类型,数据。 for (i = 0; i < pfi->Values; i++) //可以考虑用ZwQueryValueKey获取数量。MSDN关于这个成员的解释是:The number of value entries for this key. { PKEY_VALUE_BASIC_INFORMATION pkvbi; UNICODE_STRING us; PKEY_VALUE_PARTIAL_INFORMATION pkvpi; UNICODE_STRING data; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 获取名字及类型。 Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueBasicInformation, NULL, 0, &ResultLength); if( !NT_SUCCESS( Status ) ) { if (Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) //STATUS_BUFFER_OVERFLOW这个情况应该不会发生在这种情况下。 { //在下面申请内存。 } else { break; } } pkvbi = (PKEY_VALUE_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, ResultLength); if (pkvbi == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueBasicInformation, pkvbi, ResultLength, &ResultLength); if( !NT_SUCCESS( Status ) ) { ExFreePool(pkvbi); break; } us.Buffer = pkvbi->Name; us.Length = (USHORT)pkvbi->NameLength; us.MaximumLength = us.Length; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 获取数据 Status = ZwEnumerateValueKey(KeyHandle, i, KeyValuePartialInformation, NULL, 0, &ResultLength); if( !NT_SUCCESS( Status ) ) { if (Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) //STATUS_BUFFER_OVERFLOW这个情况应该不会发生在这种情况下。 { //在下面申请内存。 } else { ExFreePool(pkvbi); break; } } pkvpi = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(NonPagedPool, ResultLength); if (pkvpi == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; ExFreePool(pkvbi); break; } Status = ZwEnumerateValueKey(KeyHandle, i, KeyValuePartialInformation, pkvpi, ResultLength, &ResultLength); if( !NT_SUCCESS( Status ) ) { ExFreePool(pkvpi); ExFreePool(pkvbi); break; } data.Buffer = (PWCH)pkvpi->Data;//有的数据可能无法显示。 data.Length = (USHORT)pkvpi->DataLength; data.MaximumLength = data.Length; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Status = ZwSetValueKey(KeyHandle3, &us, 0, pkvbi->Type, data.Buffer, data.Length); if( !NT_SUCCESS( Status ) ) //如果句柄的权限是KEY_READ这里成功,但是实际是没有成功的。 { ExFreePool(pkvpi); ExFreePool(pkvbi); break; } DbgPrint("name:%wZ,type:%d,data:%wZ\n", &us, pkvbi->Type, &data); ExFreePool(pkvbi);// 释放内存 ExFreePool(pkvpi); } ExFreePool(pfi); ZwClose(KeyHandle); ZwClose(KeyHandle3); return Status; } DRIVER_UNLOAD Unload; VOID Unload(__in PDRIVER_OBJECT DriverObject) { } DRIVER_INITIALIZE DriverEntry; NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath) { NTSTATUS status = STATUS_UNSUCCESSFUL; UNICODE_STRING test = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager"); UNICODE_STRING test2 = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager2"); KdBreakPoint(); DriverObject->DriverUnload = Unload; status = ZwCopyKey(&test, &test2); if( !NT_SUCCESS( status ) ) { DbgPrint("ZwEnumerateKeyEx fail with 0x%x\n", status); } return status;//STATUS_SUCCESS }
2014年7月24日星期四
内核中的注册表操作
2014年7月22日星期二
最简单的显示网页的办法
#include "stdafx.h" /* 显示网页的最简单的办法. 再复杂一点的是调用接口。 这个还有更多的属性去开发,如:查看源代码。 其实只有一个SYSLINK可用那个控件。 更多功能和优缺点有待深入。 本文修改自MSDN。 更加详细的是:ShowHTMLDialog Sample Source Page, 地址是:http://www.microsoft.com/en-us/download/details.aspx?id=944 名字是:htmldlg.exe,可解压释放。 这个好像显示的是本地的(PE文件的一个资源)自己的网页。还可以获取选择/操作的结果。 更多的类似的函数还有: ShowHTMLDialogEx ShowModelessHTMLDialog made by correy made at 2014.07.22 homepage:http://correy.webs.com */ #include <windows.h> #include <urlmon.h> #include <mshtmhst.h> #pragma comment (lib,"Urlmon.lib") void wmain(void) { HINSTANCE hinstMSHTML = LoadLibrary(TEXT("MSHTML.DLL")); if (hinstMSHTML == NULL) { return;// Error loading module -- fail as securely as possible } SHOWHTMLDIALOGFN* pfnShowHTMLDialog; pfnShowHTMLDialog = (SHOWHTMLDIALOGFN*)GetProcAddress(hinstMSHTML, "ShowHTMLDialog"); if (pfnShowHTMLDialog) { IMoniker *pURLMoniker; BSTR bstrURL = SysAllocString(L"http://correy.webs.com"); CreateURLMoniker(NULL, bstrURL, &pURLMoniker); if (pURLMoniker) { (*pfnShowHTMLDialog)(NULL, pURLMoniker, NULL, NULL, NULL); pURLMoniker->Release(); } SysFreeString(bstrURL); } FreeLibrary(hinstMSHTML); //以下也是摘自MSDN。 //IHostDialogHelper* pHDH; //IMoniker* pUrlMoniker; //BSTR bstrOptions = SysAllocString(L"dialogHeight:30;dialogWidth:40"); //BSTR bstrPath = SysAllocString(L"c:\\dummy.htm");//c:\\dummy.htm http://correy.webs.com //CreateURLMoniker(NULL, bstrPath, &pUrlMoniker); //CoCreateInstance(CLSID_HostDialogHelper, NULL, CLSCTX_INPROC, IID_IHostDialogHelper, (void**)&pHDH); //pHDH->ShowHTMLDialog(NULL, pUrlMoniker, NULL, bstrOptions, NULL, NULL);//pHDH == 0 //SysFreeString(bstrPath); //SysFreeString(bstrOptions); //pUrlMoniker->Release(); //pHDH->Release(); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" /* 改进版的如下: 在自己的窗口中显示一个网页(其实不是的,还得用接口)。 made by correy made at 2014.07.23 homepage:http://correy.webs.com */ #include <windows.h> #include <urlmon.h> #include <mshtmhst.h> #pragma comment (lib,"Urlmon.lib") #pragma comment(linker, "/ENTRY:Entry") #pragma comment(linker, "/subsystem:windows") void show_my_website(HWND hWnd) { HINSTANCE hinstMSHTML = LoadLibrary(TEXT("MSHTML.DLL")); if (hinstMSHTML == NULL) { return;// Error loading module -- fail as securely as possible } SHOWHTMLDIALOGFN* pfnShowHTMLDialog; pfnShowHTMLDialog = (SHOWHTMLDIALOGFN*)GetProcAddress(hinstMSHTML, "ShowHTMLDialog"); if (pfnShowHTMLDialog) { IMoniker *pURLMoniker; BSTR bstrURL = SysAllocString(L"http://correy.webs.com"); CreateURLMoniker(NULL, bstrURL, &pURLMoniker); if (pURLMoniker) { (*pfnShowHTMLDialog)(hWnd, pURLMoniker, NULL, NULL, NULL); pURLMoniker->Release(); } SysFreeString(bstrURL); } FreeLibrary(hinstMSHTML); } LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CREATE://可以考虑刷新的消息。 show_my_website(hWnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return(DefWindowProc(hWnd, uMsg, wParam, lParam)); } return(0); } void Entry() { WNDCLASSEX sWndClassEx = {48,3,WindowProc,0,0,GetModuleHandle(0),0,LoadCursor(0,IDC_ARROW),(HBRUSH)6,0,L"correy",0}; ATOM a = RegisterClassEx(&sWndClassEx); ShowWindow(CreateWindowEx(0,L"correy",L"correy",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,0,0, GetModuleHandle(0),0),1); MSG sMsg; while (GetMessage(&sMsg, NULL, 0, 0)) { DispatchMessage(&sMsg); } ExitProcess(0); }
调试sysenter
很早就有个想法: 看看sysenter指令的下一步操作是啥,也就是下一条指令的代码。 sysenter指令主要的操作是设置IP。 IP设置完后,这个指令的功能也就完成差不多了。 剩下的事是CPU的事了,也就是按照指定的地址去执行了。 这个指令的功能很明确了。 接下来进入正题: 1: kd> rdmsr 176 msr[176] = 00000000`805426e0 注释:SYSENTER_EIP_MSR == 176 1: kd> u 805426e0 nt!KiFastCallEntry: 805426e0 b923000000 mov ecx,23h 805426e5 6a30 push 30h 805426e7 0fa1 pop fs 805426e9 8ed9 mov ds,cx 805426eb 8ec1 mov es,cx 805426ed 648b0d40000000 mov ecx,dword ptr fs:[40h] 805426f4 8b6104 mov esp,dword ptr [ecx+4] 805426f7 6a23 push 23h 至此问题应该解决了。 注意:有的时候,按进入下一步的时候不是这个地址,而是别的,我的解释是线程的切换。 而调用者一般如下: ntdll!KiFastSystemCall: 001b:7c92e510 8bd4 mov edx,esp 001b:7c92e512 0f34 sysenter ntdll!KiFastSystemCallRet: 001b:7c92e514 c3 ret ------------------------------------------------------------------------------------------------------------------------------ nt!KiSystemCallExit: 805428ec cf iretd nt!KiSystemCallExit2: 805428ed f644240901 test byte ptr [esp+9],1 805428f2 75f8 jne nt!KiSystemCallExit (805428ec) 805428f4 5a pop edx 805428f5 83c404 add esp,4 805428f8 80642401fd and byte ptr [esp+1],0FDh 805428fd 9d popfd 805428fe 59 pop ecx 805428ff fb sti 80542900 0f35 sysexit 80542902 cf iretd 80542903 90 nop 1: kd> r eax=00000000 ebx=7c9a0600 ecx=0225f624 edx=7c92e514 esi=0016b6d8 edi=7c99e3e0 eip=80542900 esp=f824addc ebp=0225f644 iopl=0 nv up ei ng nz na po cy cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000283 nt!KiSystemCallExit2+0x13: 80542900 0f35 sysexit 注意:EDX的值。 说明:nt!KiSystemCallExit很少被调用。 ntdll!KiFastSystemCallRet: 001b:7c92e514 c3 ret 操作步骤: 1.在nt!KiSystemCallExit2下断点。 2.走到sysexit时,在不发生切换线程的情况下会走到ntdll!KiFastSystemCallRet的。 3.ntdll!KiFastSystemCallRet返回到函数的调用者处。 ------------------------------------------------------------------------------------------------------------------------------ made by correy made at 2014.07.22
2014年7月21日星期一
内核函数的前缀
What Does the Zw Prefix Mean?
http://msdn.microsoft.com/en-us/library/windows/hardware/ff565646(v=vs.85).aspx
The Windows native system services routines have names that begin with the prefixes Nt
and Zw.
The Nt prefix is an abbreviation of Windows NT, but the Zw prefix has no meaning.
Zw was selected partly to avoid potential naming conflicts with other APIs, and partly to
avoid using any potentially useful two-letter prefixes that might be needed in the
future.
Many of the Windows driver support routines have names that begin with two- or three-
letter prefixes.
These prefixes indicate which kernel-mode system components implement the routines.
The following table contains some examples.
Prefix Kernel component Example routine
Cm Configuration manager CmRegisterCallbackEx
Ex Executive ExAllocatePool
Hal Hardware abstraction layer HalGetAdapter
Io I/O manager IoAllocateIrp
Ke Kernel core KeSetEvent
Mm Memory manager MmUnlockPages
Ob Object manager ObReferenceObject
Po Power manager PoSetPowerState
Tm Transaction manager TmCommitTransaction
Nt and Zw Native system services NtCreateFile and ZwCreateFile
以上是原文。
总以为,相信这是比较全的。其实还有更多的前缀,现在给予补充:
cc 缓存管理。
DBG 调试管理。注意还有两个以v开头的。
FsRtl File System Runtime Library Routines
Inbv 内核底层打印用的。
Interlocked 原子操作。
Kd 调试。
Ki 更加内核。
Ldr PE文件资源相关的。
Lpc 进程间通讯。
Lsa 安全子系统相关。
Nls 语言相关。
Pfx
ProbeFor 地址检测。
Ps Process and Thread Manager Routines
Rtl Runtime Library Routines
Se Security Reference Monitor Routines
Ver
Vf 可能是验证的。
WRITE_REGISTER 操作寄存器和端口相关。
Wmi WMI Library Routines
_str或者_wcs等 内核中C运行时函数。
str或者wcs等 内核中C运行时函数。
Clfs CLFS Library Routines
Flt FltXxx (Minifilter Driver) Routines
Sec Kernel Security Support Routines
MRx Network Mini-Redirector Routines
Rx Network Mini-Redirector Support Routines
Kf 在HAL.dll里面。
特殊的函数/变量:
GetSecurityUserInfo
MapSecurityError
HeadlessDispatch
initSafeBootMode
XipDispatch
二级前缀,或者说是隐含的前缀:
f 估计是fast的意思。
x 如Rtlx。
更多的还有:
p 估计是私有的。
i 估计是内部的。
更多的请看WDK。
磁盘驱动,网络驱动等不再此收集之列。
made by correy
made at 2014.07.20
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
持续更新中。
http://msdn.microsoft.com/en-us/library/windows/hardware/ff565646(v=vs.85).aspx
The Windows native system services routines have names that begin with the prefixes Nt
and Zw.
The Nt prefix is an abbreviation of Windows NT, but the Zw prefix has no meaning.
Zw was selected partly to avoid potential naming conflicts with other APIs, and partly to
avoid using any potentially useful two-letter prefixes that might be needed in the
future.
Many of the Windows driver support routines have names that begin with two- or three-
letter prefixes.
These prefixes indicate which kernel-mode system components implement the routines.
The following table contains some examples.
Prefix Kernel component Example routine
Cm Configuration manager CmRegisterCallbackEx
Ex Executive ExAllocatePool
Hal Hardware abstraction layer HalGetAdapter
Io I/O manager IoAllocateIrp
Ke Kernel core KeSetEvent
Mm Memory manager MmUnlockPages
Ob Object manager ObReferenceObject
Po Power manager PoSetPowerState
Tm Transaction manager TmCommitTransaction
Nt and Zw Native system services NtCreateFile and ZwCreateFile
以上是原文。
总以为,相信这是比较全的。其实还有更多的前缀,现在给予补充:
cc 缓存管理。
DBG 调试管理。注意还有两个以v开头的。
FsRtl File System Runtime Library Routines
Inbv 内核底层打印用的。
Interlocked 原子操作。
Kd 调试。
Ki 更加内核。
Ldr PE文件资源相关的。
Lpc 进程间通讯。
Lsa 安全子系统相关。
Nls 语言相关。
Pfx
ProbeFor 地址检测。
Ps Process and Thread Manager Routines
Rtl Runtime Library Routines
Se Security Reference Monitor Routines
Ver
Vf 可能是验证的。
WRITE_REGISTER 操作寄存器和端口相关。
Wmi WMI Library Routines
_str或者_wcs等 内核中C运行时函数。
str或者wcs等 内核中C运行时函数。
Clfs CLFS Library Routines
Flt FltXxx (Minifilter Driver) Routines
Sec Kernel Security Support Routines
MRx Network Mini-Redirector Routines
Rx Network Mini-Redirector Support Routines
Kf 在HAL.dll里面。
特殊的函数/变量:
GetSecurityUserInfo
MapSecurityError
HeadlessDispatch
initSafeBootMode
XipDispatch
二级前缀,或者说是隐含的前缀:
f 估计是fast的意思。
x 如Rtlx。
更多的还有:
p 估计是私有的。
i 估计是内部的。
更多的请看WDK。
磁盘驱动,网络驱动等不再此收集之列。
made by correy
made at 2014.07.20
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
持续更新中。
2014年7月16日星期三
minifilter之删除和改名操作
#include <fltKernel.h> #include <windef.h> #include <ntddk.h> PFLT_FILTER gFilterHandle; #define TAG 'tset' //test /* 文件名:minifilter之删除和改名操作。 一般的用户的删除的操作的设置是移动到回收站。 也可以设置为不移动到回收站而直接删除。 选中文件再按SHITF+DELETE是直接删除而不是移动到回收站。 所以普通的删除操作要走两个地方:一是删除,而是改名。一个想法是能区分/识别这两个操作为一个操作不? 参考: http://msdn.microsoft.com/en-us/library/windows/hardware/ff549366(v=vs.85).aspx http://msdn.microsoft.com/en-us/library/windows/hardware/ff544789(v=vs.85).aspx http://msdn.microsoft.com/en-us/library/windows/hardware/ff550799(v=vs.85).aspx made by correy made at 2014.07.16 homepage:http://correy.webs.com */ FLT_PREOP_CALLBACK_STATUS SetInformationPreOperation(__inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __out PVOID *CompletionContext) { PFLT_FILE_NAME_INFORMATION pfni; NTSTATUS status; UNREFERENCED_PARAMETER( CompletionContext ); if(!NT_SUCCESS(Data->IoStatus.Status)) { return FLT_PREOP_SUCCESS_WITH_CALLBACK;//The filter driver must pass this IRP down to the next-lower driver on the stack. } /* FltGetFileNameInformation cannot get file name information if the TopLevelIrp field of the current thread is not NULL, because the resulting file system recursion could cause deadlocks or stack overflows. (For more information about this issue, see IoGetTopLevelIrp.) FltGetFileNameInformation cannot get file name information in the paging I/O path. FltGetFileNameInformation cannot get file name information in the post-close path. FltGetFileNameInformation cannot get the short name of a file in the pre-create path. */ if (FlagOn(Data->Iopb->IrpFlags, IRP_PAGING_IO) || FlagOn(Data->Iopb->IrpFlags, IRP_SYNCHRONOUS_PAGING_IO) || IoGetTopLevelIrp()) //IRP_NOCACHE { return FLT_PREOP_SUCCESS_WITH_CALLBACK; } status = FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &pfni); if (!NT_SUCCESS( status )) { return FLT_PREOP_SUCCESS_WITH_CALLBACK; } status = FltParseFileNameInformation(pfni); if (!NT_SUCCESS( status )) { FltReleaseFileNameInformation(pfni); return FLT_PREOP_SUCCESS_WITH_CALLBACK; } //FltReleaseFileNameInformation(pfni); switch(Data->Iopb->Parameters.SetFileInformation.FileInformationClass) { case FileDispositionInformation://删除。 { PFILE_DISPOSITION_INFORMATION pfdi = (PFILE_DISPOSITION_INFORMATION)Data->Iopb->Parameters.SetFileInformation.InfoBuffer; /* Indicates whether the operating system file should delete the file when the file is closed. Set this member to TRUE to delete the file when it is closed. Otherwise, set to FALSE. Setting this member to FALSE has no effect if the handle was opened with FILE_FLAG_DELETE_ON_CLOSE. 严格的说还可以判断pfdi->DeleteFile的值。上面的是条件。 */ if (pfdi->DeleteFile == TRUE) { KdPrint(("删除文件\n")); } /* #define FO_DELETE_ON_CLOSE 0x00010000 FILE_FLAG_DELETE_ON_CLOSE 0x04000000 //http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx 到底该用哪个呢? */ if (FlagOn(Data->Iopb->TargetFileObject->Flags, FO_DELETE_ON_CLOSE))//FO_DELETE_ON_CLOSE OR FILE_FLAG_DELETE_ON_CLOSE? { KdPrint(("打开时就已经指定删除此文件了\n")); } /* For rename or link operations. If InfoBuffer->FileName contains a fully qualified file name, or if InfoBuffer->RootDirectory is non-NULL, this member is a file object pointer for the parent directory of the file that is the target of the operation. Otherwise it is NULL. 还可以根据情况判断ParentOfTarget是否可用,然后再根据ParentOfTarget获取被删除文件的所在的目录。 */ /* A file marked for deletion is not actually deleted until all open handles for the file object have been closed and the link count for the file is zero. 注意:文件不会立即删除。是延迟的。 */ KdPrint(("删除文件/目录:%wZ\n", &pfni->Name)); } KdPrint(("\n")); break; case FileRenameInformation://改名。 { PFILE_RENAME_INFORMATION pfri = (PFILE_RENAME_INFORMATION )Data->Iopb->Parameters.SetFileInformation.InfoBuffer; UNICODE_STRING new_name; /* 注意有一些重命名的规则和注意事项,包括目录的,见msdn. */ /* RootDirectory If the file is not being moved to a different directory, or if the FileName member contains the full pathname, this member is NULL. Otherwise, it is a handle for the root directory under which the file will reside after it is renamed. pfri->RootDirectory不是判断改名和移动的标志,仅仅用于获取路径。因为FileName大多是全路径。 */ if (pfri->RootDirectory == NULL) { //本目录改名,FileName是全路径。 //KdPrint(("改名!\n")); } else { /* 就是移动,普通的删除(移动到回收站)。 根据RootDirectory和FileName获取全路径。 */ //KdPrint(("移动!\n")); } /* 关于原来的文件名字的获取的思路: 1.Data->Iopb->TargetFileObject 或者 FltObjects->FileObject,其实这二者是相等的一样的。 其实这个值是和pfni->Name一致的。 2.Data->Iopb->TargetFileObject->FsContext和Data->Iopb->TargetFileObject->FsContext2。 不过思路2有很多未公开的结构,ccb,fcb等,可参考: http://dokan.googlecode.com/svn/trunk/sys/dokan.h http://dokan.googlecode.com/svn/trunk/sys/fileinfo.c */ //KdPrint(("改名/移动前的文件/目录:%wZ\n", &Data->Iopb->TargetFileObject->FileName)); KdPrint(("改名/移动前的文件/目录:%wZ\n", &pfni->Name)); /* FileName是改名后的路径,和pfni->Name的值在此时是不一样的。 */ new_name.Buffer = pfri->FileName; new_name.Length = (USHORT)pfri->FileNameLength; new_name.MaximumLength = new_name.Length; KdPrint(("改名/移动后的文件/目录:%wZ\n", &new_name)); } KdPrint(("\n")); break; default://其实还有更多,不信你看头文件,注意对应的结构的处理。 KdPrint(("设置信息的类型:%d\n\n", Data->Iopb->Parameters.SetFileInformation.FileInformationClass)); break; } FltReleaseFileNameInformation(pfni); return FLT_PREOP_SUCCESS_WITH_CALLBACK; } FLT_POSTOP_CALLBACK_STATUS SetInformationPostOperation (__inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __in_opt PVOID CompletionContext, __in FLT_POST_OPERATION_FLAGS Flags) /* 这个无用,暂时不用。 */ { PFLT_FILE_NAME_INFORMATION pfni; NTSTATUS status; UNREFERENCED_PARAMETER( CompletionContext ); if(!NT_SUCCESS(Data->IoStatus.Status)) { return FLT_POSTOP_FINISHED_PROCESSING;//The filter driver must pass this IRP down to the next-lower driver on the stack. } /* FltGetFileNameInformation cannot get file name information if the TopLevelIrp field of the current thread is not NULL, because the resulting file system recursion could cause deadlocks or stack overflows. (For more information about this issue, see IoGetTopLevelIrp.) FltGetFileNameInformation cannot get file name information in the paging I/O path. FltGetFileNameInformation cannot get file name information in the post-close path. FltGetFileNameInformation cannot get the short name of a file in the pre-create path. */ if (FlagOn(Data->Iopb->IrpFlags, IRP_PAGING_IO) || FlagOn(Data->Iopb->IrpFlags, IRP_SYNCHRONOUS_PAGING_IO) || IoGetTopLevelIrp()) //IRP_NOCACHE { return FLT_POSTOP_FINISHED_PROCESSING; } status = FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &pfni); if (!NT_SUCCESS( status )) { return FLT_POSTOP_FINISHED_PROCESSING; } status = FltParseFileNameInformation(pfni); if (!NT_SUCCESS( status )) { FltReleaseFileNameInformation(pfni); return FLT_POSTOP_FINISHED_PROCESSING; } //FltReleaseFileNameInformation(pfni); switch(Data->Iopb->Parameters.SetFileInformation.FileInformationClass) { case FileDispositionInformation://删除。 { PFILE_DISPOSITION_INFORMATION pfdi = (PFILE_DISPOSITION_INFORMATION)Data->Iopb->Parameters.SetFileInformation.InfoBuffer; /* Indicates whether the operating system file should delete the file when the file is closed. Set this member to TRUE to delete the file when it is closed. Otherwise, set to FALSE. Setting this member to FALSE has no effect if the handle was opened with FILE_FLAG_DELETE_ON_CLOSE. 严格的说还可以判断pfdi->DeleteFile的值。上面的是条件。 */ if (pfdi->DeleteFile == TRUE) { //KdPrint(("删除文件\n")); } /* #define FO_DELETE_ON_CLOSE 0x00010000 FILE_FLAG_DELETE_ON_CLOSE 0x04000000 //http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx 到底该用哪个呢? */ if (FlagOn(Data->Iopb->TargetFileObject->Flags, FO_DELETE_ON_CLOSE))//FO_DELETE_ON_CLOSE OR FILE_FLAG_DELETE_ON_CLOSE? { //KdPrint(("打开时就已经指定删除此文件了\n")); } /* For rename or link operations. If InfoBuffer->FileName contains a fully qualified file name, or if InfoBuffer->RootDirectory is non-NULL, this member is a file object pointer for the parent directory of the file that is the target of the operation. Otherwise it is NULL. 还可以根据情况判断ParentOfTarget是否可用,然后再根据ParentOfTarget获取被删除文件的所在的目录。 */ /* A file marked for deletion is not actually deleted until all open handles for the file object have been closed and the link count for the file is zero. 注意:文件不会立即删除。是延迟的。 */ //KdPrint(("删除文件/目录:%wZ\n", &pfni->Name)); } //KdPrint(("\n")); break; case FileRenameInformation://改名。 { PFILE_RENAME_INFORMATION pfri = (PFILE_RENAME_INFORMATION )Data->Iopb->Parameters.SetFileInformation.InfoBuffer; /* 注意有一些重命名的规则和注意事项,包括目录的,见msdn. */ /* RootDirectory If the file is not being moved to a different directory, or if the FileName member contains the full pathname, this member is NULL. Otherwise, it is a handle for the root directory under which the file will reside after it is renamed. pfri->RootDirectory不是判断改名和移动的标志,仅仅用于获取路径。因为FileName大多是全路径。 */ if (pfri->RootDirectory == NULL) { //本目录改名,FileName是全路径。 //KdPrint(("改名!\n")); } else { /* 就是移动,普通的删除(移动到回收站)。 根据RootDirectory和FileName获取全路径。 */ //KdPrint(("移动!\n")); } /* 关于原来的文件名字的获取的思路: 1.Data->Iopb->TargetFileObject 或者 FltObjects->FileObject,其实这二者是相等的一样的。其实这个值是和pfni->Name一致的。 这个有时是改名后的路径有时是改名前的路径。此办法不可信,不可用。还得组合路径是必须的。 2.Data->Iopb->TargetFileObject->FsContext和Data->Iopb->TargetFileObject->FsContext2。 不过思路2有很多未公开的结构,ccb,fcb等,可参考: http://dokan.googlecode.com/svn/trunk/sys/dokan.h http://dokan.googlecode.com/svn/trunk/sys/fileinfo.c 获取改名前的名字在和路径在前操作中进行。 */ //KdPrint(("改名/移动前的文件/目录:%wZ\n", &Data->Iopb->TargetFileObject->FileName)); /* FileName是改名后的路径,和pfni->Name是一样的。\Device\HarddiskVolume1\和\??\之别。 */ //KdPrint(("改名/移动后的文件/目录:%wZ\n", &pfni->Name)); } //KdPrint(("\n")); break; default://其实还有更多,不信你看头文件,注意对应的结构的处理。 //KdPrint(("设置信息的类型:%d\n\n", Data->Iopb->Parameters.SetFileInformation.FileInformationClass)); break; } FltReleaseFileNameInformation(pfni); return FLT_POSTOP_FINISHED_PROCESSING; } CONST FLT_OPERATION_REGISTRATION Callbacks[] = { { IRP_MJ_SET_INFORMATION, 0, SetInformationPreOperation, SetInformationPostOperation}, { IRP_MJ_OPERATION_END } }; #pragma PAGEDCODE NTSTATUS InstanceQueryTeardown (__in PCFLT_RELATED_OBJECTS FltObjects,__in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags) { return STATUS_SUCCESS; } #pragma PAGEDCODE//#pragma alloc_text(PAGE, PtUnload) NTSTATUS MiniFilterUnload (__in FLT_FILTER_UNLOAD_FLAGS Flags) { FltUnregisterFilter( gFilterHandle ); return STATUS_SUCCESS; } CONST FLT_REGISTRATION FilterRegistration = { sizeof( FLT_REGISTRATION ), // Size FLT_REGISTRATION_VERSION, // Version 0, // Flags NULL, // Context Callbacks, // Operation callbacks MiniFilterUnload, // MiniFilterUnload NULL, // InstanceSetup InstanceQueryTeardown, // InstanceQueryTeardown NULL, // InstanceTeardownStart NULL, // InstanceTeardownComplete NULL, // GenerateFileName NULL, // GenerateDestinationFileName NULL // NormalizeNameComponent }; DRIVER_INITIALIZE DriverEntry; #pragma alloc_text(INIT, DriverEntry)//#pragma INITCODE NTSTATUS DriverEntry (_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) { NTSTATUS status; UNREFERENCED_PARAMETER( RegistryPath ); KdBreakPoint(); status = FltRegisterFilter( DriverObject, &FilterRegistration, &gFilterHandle ); if (!NT_SUCCESS( status )) //FLT_ASSERT( NT_SUCCESS( status ) ); { return status; } status = FltStartFiltering( gFilterHandle ); if (!NT_SUCCESS( status )) { FltUnregisterFilter( gFilterHandle ); } return status; }
2014年7月11日星期五
内核中的通配符和字符匹配
#include <ntifs.h> #include <windef.h> /* FsRtlIsNameInExpression的用法规则: 1.If IgnoreCase is TRUE, Expression must be uppercase. 如果忽略大小写(第三个参数),第一个参数必须是大写的。 2.If this value is not supplied, the default system uppercase character table is used. 如果第四个参数为0,那(第一个参数)必须是大写的。 3.If only one of the string parameters has a length of zero, FsRtlIsNameInExpression returns FALSE. This means that "*" does not match a null string. 如果有一个参数是0,返回失败。 4.If both parameters are null strings, FsRtlIsNameInExpression returns TRUE. 如果都是0,返回匹配。 Wildcard character Meaning * (asterisk) Matches zero or more characters. ? (question mark) Matches a single character. DOS_DOT Matches either a period or zero characters beyond the name string. DOS_QM Matches any single character or, upon encountering a period or end of name string, advances the expression to the end of the set of contiguous DOS_QMs. DOS_STAR Matches zero or more characters until encountering and matching the final . in the name. DOS_QM和DOS_STAR是啥东西呢? #define DOS_STAR (L'<') #define DOS_QM (L'>') #define DOS_DOT (L'"') //dot也就是L".",为何定义这呢?不过看源码,它也处理了L"." 摘自:\wrk\WindowsResearchKernel-WRK\WRK-v1.2\public\sdk\inc\ntioapi.h 但是另一个文档的说明如下: ~* is DOS_STAR, ~? is DOS_QM, and ~. is DOS_DOT 摘自:\wrk\WindowsResearchKernel-WRK\WRK-v1.2\base\ntos\fsrtl\name.c 前后不符。 综上所述:DOS_QM和DOS_STAR,DOS_DOT是处理DOS路径的(个人理解)。 参考资料:MSDN和WRK。 多字符的FsRtlIsDbcsInExpression与此类似。 不说了,能用则已,简单的几个,不够用的时候在仔细看。 made by correy made at 2014.07.11 homepage:http://correy.webs.com */ BOOLEAN RtlIsNameInExpression(IN UNICODE_STRING * Expression, IN UNICODE_STRING * Name) { NTSTATUS status = STATUS_UNSUCCESSFUL; UNICODE_STRING DestinationString; BOOLEAN B; if (Expression == 0 || Name == 0) { return FALSE ; } status = RtlUpcaseUnicodeString(&DestinationString, Expression, TRUE); if (!NT_SUCCESS( status )) { return FALSE ; } B = FsRtlIsNameInExpression(&DestinationString, Name, TRUE, 0); RtlFreeUnicodeString(&DestinationString); return B; } DRIVER_INITIALIZE DriverEntry; NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath) { NTSTATUS status = STATUS_UNSUCCESSFUL; UNICODE_STRING Expression1 = RTL_CONSTANT_STRING(L"co*ey"); UNICODE_STRING Expression2 = RTL_CONSTANT_STRING(L"cor?ey"); UNICODE_STRING Name = RTL_CONSTANT_STRING(L"correy"); UNICODE_STRING Name2 = RTL_CONSTANT_STRING(L"coeyrr"); KdBreakPoint(); if (RtlIsNameInExpression(&Expression1, &Name)) { KdPrint(("匹配\n")); } else { KdPrint(("不匹配\n")); } if (RtlIsNameInExpression(&Expression2, &Name)) { KdPrint(("匹配\n")); } else { KdPrint(("不匹配\n")); } //以上都因该匹配。 ///////////////////////////////////////////////////// //以下都应该不匹配。 if (RtlIsNameInExpression(&Expression1, &Name2)) { KdPrint(("匹配\n")); } else { KdPrint(("不匹配\n")); } if (RtlIsNameInExpression(&Expression2, &Name2)) { KdPrint(("匹配\n")); } else { KdPrint(("不匹配\n")); } return status;//STATUS_SUCCESS }
----------------------------------------------------------------------------------------------
/*
通配符的测试。
The following are wildcard characters: *, ?, ANSI_DOS_STAR, ANSI_DOS_DOT, and ANSI_DOS_QM.
FsRtlDoesNameContainWildCards 是个函数,调用FsRtlIsUnicodeCharacterWild实现的。
FsRtlIsUnicodeCharacterWild 是个宏
FsRtlIsAnsiCharacterWild 是个宏
made by correy
made at 2015.03.04
#define DOS_STAR (L'<')
#define DOS_QM (L'>')
#define DOS_DOT (L'"') //dot也就是L".",为何定义这呢?不过看源码,它也处理了L"."
摘自:\wrk\WindowsResearchKernel-WRK\WRK-v1.2\public\sdk\inc\ntioapi.h
但是另一个文档的说明如下:
~* is DOS_STAR, ~? is DOS_QM, and ~. is DOS_DOT
摘自:\wrk\WindowsResearchKernel-WRK\WRK-v1.2\base\ntos\fsrtl\name.c
经测试:这个是不正确的,不可信的。
其实:
#define ANSI_DOS_STAR ('<') 但是这代表啥意思的呢?还没有测试。
#define ANSI_DOS_QM ('>')
#define ANSI_DOS_DOT ('"')
#define DOS_STAR (L'<')
#define DOS_QM (L'>')
#define DOS_DOT (L'"')
这些都定义在ntifs.h中的。
*/
#include <ntifs.h>
//#include <ntddk.h> //这两个次序不能乱,有上面的,这个可以注释掉。
#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
BOOLEAN B = FALSE;
UNICODE_STRING test1 = RTL_CONSTANT_STRING(L"*");
UNICODE_STRING test2 = RTL_CONSTANT_STRING(L"a*");
UNICODE_STRING test3 = RTL_CONSTANT_STRING(L"*a");
UNICODE_STRING test4 = RTL_CONSTANT_STRING(L"*a*");
UNICODE_STRING test5 = RTL_CONSTANT_STRING(L"?");
UNICODE_STRING test6 = RTL_CONSTANT_STRING(L"a?");
UNICODE_STRING test7 = RTL_CONSTANT_STRING(L"?a");
UNICODE_STRING test8 = RTL_CONSTANT_STRING(L"?a?");
UNICODE_STRING test9 = RTL_CONSTANT_STRING(L"test");
UNICODE_STRING test10 = RTL_CONSTANT_STRING(L"<");
UNICODE_STRING test11 = RTL_CONSTANT_STRING(L">");
UNICODE_STRING test12 = RTL_CONSTANT_STRING(L"\"");
UNICODE_STRING test13 = RTL_CONSTANT_STRING(L".");
//混合的就不测试了,因为单个的测试了,混合的必定可以的。
KdBreakPoint();
B = FsRtlDoesNameContainWildCards(&test1);
if (B) {
KdPrint(("%wZ contains wildcard characters!\n", &test1));
} else {
KdPrint(("%wZ not contains wildcard characters!\n", &test1));
}
B = FsRtlDoesNameContainWildCards(&test2);
if (B) {
KdPrint(("%wZ contains wildcard characters!\n", &test2));
} else {
KdPrint(("%wZ not contains wildcard characters!\n", &test2));
}
B = FsRtlDoesNameContainWildCards(&test3);
if (B) {
KdPrint(("%wZ contains wildcard characters!\n", &test3));
} else {
KdPrint(("%wZ not contains wildcard characters!\n", &test3));
}
B = FsRtlDoesNameContainWildCards(&test4);
if (B) {
KdPrint(("%wZ contains wildcard characters!\n", &test4));
} else {
KdPrint(("%wZ not contains wildcard characters!\n", &test4));
}
B = FsRtlDoesNameContainWildCards(&test5);
if (B) {
KdPrint(("%wZ contains wildcard characters!\n", &test5));
} else {
KdPrint(("%wZ not contains wildcard characters!\n", &test5));
}
B = FsRtlDoesNameContainWildCards(&test6);
if (B) {
KdPrint(("%wZ contains wildcard characters!\n", &test6));
} else {
KdPrint(("%wZ not contains wildcard characters!\n", &test6));
}
B = FsRtlDoesNameContainWildCards(&test7);
if (B) {
KdPrint(("%wZ contains wildcard characters!\n", &test7));
} else {
KdPrint(("%wZ not contains wildcard characters!\n", &test7));
}
B = FsRtlDoesNameContainWildCards(&test8);
if (B) {
KdPrint(("%wZ contains wildcard characters!\n", &test8));
} else {
KdPrint(("%wZ not contains wildcard characters!\n", &test8));
}
B = FsRtlDoesNameContainWildCards(&test9);
if (B) {
KdPrint(("%wZ contains wildcard characters!\n", &test9));
} else {
KdPrint(("%wZ not contains wildcard characters!\n", &test9));
}
B = FsRtlDoesNameContainWildCards(&test10);
if (B) {
KdPrint(("%wZ contains wildcard characters!\n", &test10));
} else {
KdPrint(("%wZ not contains wildcard characters!\n", &test10));
}
B = FsRtlDoesNameContainWildCards(&test11);
if (B) {
KdPrint(("%wZ contains wildcard characters!\n", &test11));
} else {
KdPrint(("%wZ not contains wildcard characters!\n", &test11));
}
B = FsRtlDoesNameContainWildCards(&test12);
if (B) {
KdPrint(("%wZ contains wildcard characters!\n", &test12));
} else {
KdPrint(("%wZ not contains wildcard characters!\n", &test12));
}
B = FsRtlDoesNameContainWildCards(&test13);
if (B) {
KdPrint(("%wZ contains wildcard characters!\n", &test13));
} else {
KdPrint(("%wZ not contains wildcard characters!\n", &test13));
}
return status;//STATUS_SUCCESS
}
/*
测试结果如下:
1: kd> g
* contains wildcard characters!
a* contains wildcard characters!
*a contains wildcard characters!
*a* contains wildcard characters!
? contains wildcard characters!
a? contains wildcard characters!
?a contains wildcard characters!
?a? contains wildcard characters!
test not contains wildcard characters!
< contains wildcard characters!
> contains wildcard characters!
" contains wildcard characters!
. not contains wildcard characters!
*/
2014年7月10日星期四
minifilter打开/创建的前操作识别目录
#include <fltKernel.h> PFLT_FILTER gFilterHandle; /* 打开/创建的前操作的时候判断是不是目录。 打开/创建的前操作不可以用FltIsDirectory,因为第一个参数为空/不可以使用。 made by correy made at 2014.07.10 homepage:http://correy.webs.com */ //这些在WDK 7600.16385.1中没有定义,在WDK8.0中定义了. //一下代码是解决办法之一. #ifndef _In_ #define _Inout_ #define _In_ #define _In_opt_ #endif //另一思路可参考:http://msdn.microsoft.com/zh-cn/library/windows/hardware/ff554695(v=vs.85).aspx FLT_PREOP_CALLBACK_STATUS CreatePreOPeration(__inout PFLT_CALLBACK_DATA Cbd, __in PCFLT_RELATED_OBJECTS FltObjects, __out PVOID *CompletionContext) { PFLT_FILE_NAME_INFORMATION pfni; NTSTATUS status; FILE_STANDARD_INFORMATION fsi = {0}; ULONG LengthReturned; BOOLEAN IsDirectory = FALSE ; //status = FltIsDirectory(FltObjects->FileObject, FltObjects->Instance, &IsDirectory);//FileObject不可用,所以这个函数不可用。 //if (NT_SUCCESS(status) && IsDirectory) //{ // //如果是目录. //} //else //{ // return FLT_PREOP_SUCCESS_NO_CALLBACK; //} /* 方法一: 确信用户打开文件填写的是FILE_NON_DIRECTORY_FILE,打开目录是FILE_DIRECTORY_FILE。 应用程序没有这个选项,所以过滤应用层是正确的。驱动层的有的程序会填写错误。 */ if (!FlagOn( Cbd->Iopb->Parameters.Create.Options, FILE_DIRECTORY_FILE )) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } /* 创建的标志: FILE_SUPERSEDE FILE_CREATE FILE_OPEN_IF FILE_OVERWRITE_IF 打开标志: FILE_OPEN FILE_OPEN_IF FILE_OVERWRITE FILE_OVERWRITE_IF 注释:FILE_OPEN和FILE_OVERWRITE不会创建。 */ /* 方法二:FltQueryInformationFile OR ZwQueryInformationFile。 最好判断下目的。新建的估计失败,估计是PFILE_OBJECT不存在。 */ //status = FltQueryInformationFile(FltObjects->Instance, FltObjects->FileObject, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation, &LengthReturned); //if (!NT_SUCCESS( status )) //{ // return FLT_PREOP_SUCCESS_NO_CALLBACK; //} //if (fsi.Directory != TRUE ) //{ // return FLT_PREOP_SUCCESS_NO_CALLBACK; //} /* FltGetFileNameInformation cannot get file name information if the TopLevelIrp field of the current thread is not NULL, because the resulting file system recursion could cause deadlocks or stack overflows. (For more information about this issue, see IoGetTopLevelIrp.) FltGetFileNameInformation cannot get file name information in the paging I/O path. FltGetFileNameInformation cannot get file name information in the post-close path. FltGetFileNameInformation cannot get the short name of a file in the pre-create path. */ if (FlagOn(Cbd->Iopb->IrpFlags, IRP_PAGING_IO) || FlagOn(Cbd->Iopb->IrpFlags, IRP_SYNCHRONOUS_PAGING_IO) || IoGetTopLevelIrp()) //IRP_NOCACHE { return FLT_PREOP_SUCCESS_NO_CALLBACK; } status = FltGetFileNameInformation( Cbd, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &pfni); if (!NT_SUCCESS( status )) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } status = FltParseFileNameInformation(pfni); if (!NT_SUCCESS( status )) { FltReleaseFileNameInformation(pfni); return FLT_PREOP_SUCCESS_NO_CALLBACK; } KdPrint(("目录:%wZ\n", &pfni->Name)); FltReleaseFileNameInformation(pfni); return FLT_PREOP_SUCCESS_NO_CALLBACK; } CONST FLT_OPERATION_REGISTRATION Callbacks[] = { { IRP_MJ_CREATE, 0, CreatePreOPeration, 0}, { IRP_MJ_OPERATION_END } }; #pragma PAGEDCODE NTSTATUS PtInstanceQueryTeardown (__in PCFLT_RELATED_OBJECTS FltObjects,__in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags) { return STATUS_SUCCESS; } #pragma PAGEDCODE//#pragma alloc_text(PAGE, PtUnload) NTSTATUS PtUnload (__in FLT_FILTER_UNLOAD_FLAGS Flags) { FltUnregisterFilter( gFilterHandle ); return STATUS_SUCCESS; } CONST FLT_REGISTRATION FilterRegistration = { sizeof( FLT_REGISTRATION ), // Size FLT_REGISTRATION_VERSION, // Version 0, // Flags NULL, // Context Callbacks, // Operation callbacks PtUnload, // MiniFilterUnload NULL, // InstanceSetup PtInstanceQueryTeardown, // InstanceQueryTeardown NULL, // InstanceTeardownStart NULL, // InstanceTeardownComplete NULL, // GenerateFileName NULL, // GenerateDestinationFileName NULL // NormalizeNameComponent }; DRIVER_INITIALIZE DriverEntry; #pragma alloc_text(INIT, DriverEntry)//#pragma INITCODE NTSTATUS DriverEntry (_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) { NTSTATUS status; UNREFERENCED_PARAMETER( RegistryPath ); KdBreakPoint(); status = FltRegisterFilter( DriverObject, &FilterRegistration, &gFilterHandle ); if (!NT_SUCCESS( status )) //FLT_ASSERT( NT_SUCCESS( status ) ); { return status; } status = FltStartFiltering( gFilterHandle ); if (!NT_SUCCESS( status )) { FltUnregisterFilter( gFilterHandle ); } return status; }
FltDoCompletionProcessingWhenSafe
#include <fltKernel.h> PFLT_FILTER gFilterHandle; /* 文件名:FltDoCompletionProcessingWhenSafe.c 起因在写的后操作直接调用FltGetFileNameInformation蓝屏。 后来得知是后操作的IRQL <= DISPATCH_LEVEL。 解决办法有2: 1.FltDoCompletionProcessingWhenSafe 2.FltQueueDeferredIoWorkItem(自己试验失败,总是蓝屏) 3.个人不建议使用普通的线程队列,因为有些内核对象不能使用。还是用官方建议的吧! made by correy made at 2014.07.10 homepage:http://correy.webs.com */ //这些在WDK 7600.16385.1中没有定义,在WDK8.0中定义了. //一下代码是解决办法之一. #ifndef _In_ #define _Inout_ #define _In_ #define _In_opt_ #endif //另一思路可参考:http://msdn.microsoft.com/zh-cn/library/windows/hardware/ff554695(v=vs.85).aspx FLT_POSTOP_CALLBACK_STATUS WritePostOPerationWhenSafe (__inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __in_opt PVOID CompletionContext, __in FLT_POST_OPERATION_FLAGS Flags) { PFLT_FILE_NAME_INFORMATION pfni; NTSTATUS status; status = FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &pfni); if (!NT_SUCCESS( status )) { return FLT_POSTOP_FINISHED_PROCESSING; } status = FltParseFileNameInformation(pfni); if (!NT_SUCCESS( status )) { FltReleaseFileNameInformation(pfni); return FLT_POSTOP_FINISHED_PROCESSING; } KdPrint(("写文件:%wZ\n", &pfni->Name)); FltReleaseFileNameInformation(pfni); return FLT_POSTOP_FINISHED_PROCESSING; /* If a minifilter calls FltDoCompletionProcessingWhenSafe and the SafePostCallback is invoked in a worker thread because it is not safe to invoke it in the current thread context, the filter manager will resume completion processing as long as the minifilter does not return FLT_POSTOP_MORE_PROCESSING_REQUIRED from the SafePostCallback. If the minifilter does return FLT_POSTOP_MORE_PROCESSING_REQUIRED from the SafePostCallback, the minifilter must call FltCompletePendedPostOperation to resume completion processing. 理解为,如果这个函数返回了FLT_POSTOP_MORE_PROCESSING_REQUIRED,后操作要调用FltCompletePendedPostOperation。 */ } FLT_POSTOP_CALLBACK_STATUS WritePostOPeration(__inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __in PVOID CompletionContext, __in FLT_POST_OPERATION_FLAGS Flags) /* A minifilter driver's post-operation callback routine performs completion processing for one or more types of I/O operations. Post-operation callback routines are similar to the completion routines used by legacy file system filter drivers. Post-operation callback routines are called in an arbitrary thread context, at IRQL <= DISPATCH_LEVEL. Because this callback routine can be called at IRQL DISPATCH_LEVEL, it is subject to the following constraints: It cannot safely call any kernel-mode routine that must run at a lower IRQL. Any data structures used in this routine must be allocated from nonpaged pool. It cannot be made pageable. It cannot acquire resources, mutexes, or fast mutexes. However, it can acquire spin locks. It cannot get, set, or delete contexts, but it can release contexts. Any I/O completion processing that needs to be performed at IRQL < DISPATCH_LEVEL cannot be performed directly in the postoperation callback routine. Instead, it must be posted to a work queue by calling a routine such as FltDoCompletionProcessingWhenSafe or FltQueueDeferredIoWorkItem. Be aware that FltDoCompletionProcessingWhenSafe should never be called if the Flags parameter of the post-operation callback has the FLTFL_POST_OPERATION_DRAINING bit set. The following are exceptions to this rule: If a minifilter driver's pre-operation callback routine returns FLT_PREOP_SYNCHRONIZE for an IRP-based I/O operation, the corresponding post-operation callback routine is guaranteed to be called at IRQL <= APC_LEVEL, in the same thread context as the pre-operation callback. Post-create callback routines are guaranteed to be called at IRQL PASSIVE_LEVEL, in the context of the thread that originated the IRP_MJ_CREATE operation. */ { FLT_POSTOP_CALLBACK_STATUS retValue = FLT_POSTOP_FINISHED_PROCESSING; /* FltDoCompletionProcessingWhenSafe can only be called for IRP-based operations. To determine whether the operation is an IRP-based operation, use the FLT_IS_IRP_OPERATION macro. */ if (!FLT_IS_IRP_OPERATION(Data)) //FlagOn( (Data)->Flags, FLTFL_CALLBACK_DATA_IRP_OPERATION ) { return FLT_POSTOP_FINISHED_PROCESSING; } /* Note that FltDoCompletionProcessingWhenSafe should never be called if the Flags parameter of the postoperation callback has the FLTFL_POST_OPERATION_DRAINING bit set. */ if (FlagOn(Flags,FLTFL_POST_OPERATION_DRAINING)) { return FLT_POSTOP_FINISHED_PROCESSING; } /* FltDoCompletionProcessingWhenSafe cannot be used to post completion of a paging I/O operation to a worker thread. */ if (FlagOn(Data->Iopb->IrpFlags, IRP_PAGING_IO) || FlagOn(Data->Iopb->IrpFlags, IRP_SYNCHRONOUS_PAGING_IO)) //IRP_NOCACHE { return FLT_POSTOP_FINISHED_PROCESSING; } /* FltDoCompletionProcessingWhenSafe can only be called from a minifilter driver's postoperation callback routine (PFLT_POST_OPERATION_CALLBACK). */ if (!FltDoCompletionProcessingWhenSafe( Data, FltObjects, CompletionContext, Flags, WritePostOPerationWhenSafe, &retValue )) { Data->IoStatus.Status = STATUS_UNSUCCESSFUL; Data->IoStatus.Information = 0; return retValue; } //FltCompletePendedPostOperation();//如果返回了FLT_POSTOP_MORE_PROCESSING_REQUIRED就调用这个。 return retValue; } CONST FLT_OPERATION_REGISTRATION Callbacks[] = { { IRP_MJ_WRITE, 0, 0, WritePostOPeration}, { IRP_MJ_OPERATION_END } }; #pragma PAGEDCODE NTSTATUS PtInstanceQueryTeardown (__in PCFLT_RELATED_OBJECTS FltObjects,__in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags) { return STATUS_SUCCESS; } #pragma PAGEDCODE//#pragma alloc_text(PAGE, PtUnload) NTSTATUS PtUnload (__in FLT_FILTER_UNLOAD_FLAGS Flags) { FltUnregisterFilter( gFilterHandle ); return STATUS_SUCCESS; } CONST FLT_REGISTRATION FilterRegistration = { sizeof( FLT_REGISTRATION ), // Size FLT_REGISTRATION_VERSION, // Version 0, // Flags NULL, // Context Callbacks, // Operation callbacks PtUnload, // MiniFilterUnload NULL, // InstanceSetup PtInstanceQueryTeardown, // InstanceQueryTeardown NULL, // InstanceTeardownStart NULL, // InstanceTeardownComplete NULL, // GenerateFileName NULL, // GenerateDestinationFileName NULL // NormalizeNameComponent }; DRIVER_INITIALIZE DriverEntry; #pragma alloc_text(INIT, DriverEntry)//#pragma INITCODE NTSTATUS DriverEntry (_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) { NTSTATUS status; UNREFERENCED_PARAMETER( RegistryPath ); KdBreakPoint(); status = FltRegisterFilter( DriverObject, &FilterRegistration, &gFilterHandle ); if (!NT_SUCCESS( status )) //FLT_ASSERT( NT_SUCCESS( status ) ); { return status; } status = FltStartFiltering( gFilterHandle ); if (!NT_SUCCESS( status )) { FltUnregisterFilter( gFilterHandle ); } return status; }
minifilter-DirectoryControl-QueryDirectory
#include <fltKernel.h>
#include <windef.h>
PFLT_FILTER gFilterHandle;
#define TAG 'tset' //test
/*
文件名就叫:minifilter-QueryDirectory.c吧!
框架是DirectoryControl,主要写的是QueryDirectory,NotifyDirectory与此类似。
参考:
http://msdn.microsoft.com/en-us/library/windows/hardware/ff548658(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/hardware/ff544695(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/hardware/ff540314(v=vs.85).aspx
made by correy
made at 2014.07.09
homepage:http://correy.webs.com
*/
FLT_POSTOP_CALLBACK_STATUS DirectoryControlPostOperation (__inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __in_opt PVOID CompletionContext, __in FLT_POST_OPERATION_FLAGS Flags)
{
PVOID p = NULL;
PFLT_FILE_NAME_INFORMATION pfni;
NTSTATUS status;
UNREFERENCED_PARAMETER( CompletionContext );
//IRP_MJ_DIRECTORY_CONTROL is an IRP-based operation.
if (!FLT_IS_IRP_OPERATION(Data))
{
return FLT_POSTOP_FINISHED_PROCESSING;
}
/*
The file system driver should check the minor function code to determine which directory control operation is requested.
One of the following:
IRP_MN_NOTIFY_CHANGE_DIRECTORY 对应NotifyDirectory结构。
IRP_MN_QUERY_DIRECTORY 对应QueryDirectory结构即(Union component used for IRP_MN_QUERY_DIRECTORY operations.)
*/
if (Data->Iopb->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
{
return FLT_POSTOP_FINISHED_PROCESSING;//The filter driver must pass this IRP down to the next-lower driver on the stack.
}
if( FlagOn( Flags, FLTFL_POST_OPERATION_DRAINING ))
{
return FLT_POSTOP_FINISHED_PROCESSING;
}
if(Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length <= 0)
{
return FLT_POSTOP_FINISHED_PROCESSING;
}
if(!NT_SUCCESS(Data->IoStatus.Status))
{
return FLT_POSTOP_FINISHED_PROCESSING;
}
if (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress != NULL) {
p = MmGetSystemAddressForMdlSafe(Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress, NormalPagePriority);
} else {
p = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;
}
if(p == NULL) {
return FLT_POSTOP_FINISHED_PROCESSING;
}
//这个不是目录。
//KdPrint(("查询的目录:%wZ\n", Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileName));
/*
FltGetFileNameInformation cannot get file name information if the TopLevelIrp field of the current thread is not NULL,
because the resulting file system recursion could cause deadlocks or stack overflows. (For more information about this issue, see IoGetTopLevelIrp.)
FltGetFileNameInformation cannot get file name information in the paging I/O path.
FltGetFileNameInformation cannot get file name information in the post-close path.
FltGetFileNameInformation cannot get the short name of a file in the pre-create path.
*/
if (FlagOn(Data->Iopb->IrpFlags, IRP_PAGING_IO) || FlagOn(Data->Iopb->IrpFlags, IRP_SYNCHRONOUS_PAGING_IO) || IoGetTopLevelIrp()) //IRP_NOCACHE
{
return FLT_POSTOP_FINISHED_PROCESSING;
}
status = FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &pfni);
if (!NT_SUCCESS( status ))
{
return FLT_POSTOP_FINISHED_PROCESSING;
}
status = FltParseFileNameInformation(pfni);
if (!NT_SUCCESS( status ))
{
FltReleaseFileNameInformation(pfni);
return FLT_POSTOP_FINISHED_PROCESSING;
}
KdPrint(("查询的目录:%wZ\n", &pfni->Name));
//FltReleaseFileNameInformation(pfni);
switch(Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass)
{
case FileBothDirectoryInformation://XP走这里了,server 2008也走这里了。
{
PFILE_BOTH_DIR_INFORMATION pfbdi = (PFILE_BOTH_DIR_INFORMATION)p;
UNICODE_STRING FileName = {0};
if (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileIndex == SL_INDEX_SPECIFIED)//SL_RESTART_SCAN SL_RETURN_SINGLE_ENTRY
{
/*
注意有的是一下子枚举完毕,有的是一个一个的枚举。
下同。
*/
}
KdPrint(("查询目录的类型:FileBothDirectoryInformation\n"));
do
{
FileName.Buffer = pfbdi->FileName;
FileName.Length = (USHORT)pfbdi->FileNameLength;
FileName.MaximumLength = FileName.Length;
if (pfbdi->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
KdPrint(("目录:%wZ\n", &FileName));
} else {
KdPrint(("文件:%wZ\n", &FileName));
}
pfbdi = (PFILE_BOTH_DIR_INFORMATION)((PCHAR)(pfbdi) + pfbdi->NextEntryOffset);
} while( pfbdi->NextEntryOffset != 0 );
}
KdPrint(("\n"));
break;
case FileDirectoryInformation://win 7走这里了。走这里的时机不太清楚,机会很少。
{
PFILE_DIRECTORY_INFORMATION pfdi = (PFILE_DIRECTORY_INFORMATION )p;
UNICODE_STRING FileName = {0};
KdPrint(("查询目录的类型:FileDirectoryInformation\n\n"));
do
{
FileName.Buffer = pfdi->FileName;
FileName.Length = (USHORT)pfdi->FileNameLength;
FileName.MaximumLength = FileName.Length;
if (pfdi->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
KdPrint(("目录:%wZ\n", &FileName));
} else {
KdPrint(("文件:%wZ\n", &FileName));
}
pfdi = (PFILE_DIRECTORY_INFORMATION )((PCHAR)(pfdi) + pfdi->NextEntryOffset);
} while( pfdi->NextEntryOffset != 0 );
}
KdPrint(("\n"));
break;
case FileFullDirectoryInformation://server 2008的dir /a 走这里了。
{
PFILE_FULL_DIR_INFORMATION pffdi = (PFILE_FULL_DIR_INFORMATION )p;
UNICODE_STRING FileName = {0};
KdPrint(("查询目录的类型:FileFullDirectoryInformation\n"));
do
{
FileName.Buffer = pffdi->FileName;
FileName.Length = (USHORT)pffdi->FileNameLength;
FileName.MaximumLength = FileName.Length;
if (pffdi->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
KdPrint(("目录:%wZ\n", &FileName));
} else {
KdPrint(("文件:%wZ\n", &FileName));
}
pffdi = (PFILE_FULL_DIR_INFORMATION )((PCHAR)(pffdi) + pffdi->NextEntryOffset);
} while( pffdi->NextEntryOffset != 0 );
}
KdPrint(("\n"));
break;
case FileIdBothDirectoryInformation://server 2008也走这里了。
{
PFILE_ID_BOTH_DIR_INFORMATION pfibdi = (PFILE_ID_BOTH_DIR_INFORMATION )p;
UNICODE_STRING FileName = {0};
KdPrint(("查询目录的类型:FileIdBothDirectoryInformation\n"));
do
{
FileName.Buffer = pfibdi->FileName;
FileName.Length = (USHORT)pfibdi->FileNameLength;
FileName.MaximumLength = FileName.Length;
if (pfibdi->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
KdPrint(("目录:%wZ\n", &FileName));
} else {
KdPrint(("文件:%wZ\n", &FileName));
}
pfibdi = (PFILE_ID_BOTH_DIR_INFORMATION )((PCHAR)(pfibdi) + pfibdi->NextEntryOffset);
} while( pfibdi->NextEntryOffset != 0 );
}
KdPrint(("\n"));
break;
case FileIdFullDirectoryInformation://这个及上面的都有FileAttributes属性。
KdPrint(("查询目录的类型:FileIdFullDirectoryInformation\n\n"));
break;
case FileNamesInformation://XP有时也走这里,如启动一个程序。win 7 也走这里了。
{
PFILE_NAMES_INFORMATION pfni2 = (PFILE_NAMES_INFORMATION )p;
UNICODE_STRING FileName = {0};
UNICODE_STRING FilePathName = {0};
FILE_STANDARD_INFORMATION fsi = {0};
IO_STATUS_BLOCK IoStatusBlock ={0};
HANDLE FileHandle = 0;//(HANDLE)-1;
OBJECT_ATTRIBUTES ob = {0};
UNICODE_STRING dot = RTL_CONSTANT_STRING(L".");
UNICODE_STRING double_dot = RTL_CONSTANT_STRING(L"..");
KdPrint(("查询目录的类型:FileNamesInformation\n"));
FilePathName.MaximumLength = MAX_PATH;//(USHORT)BufferSizeNeeded + 2;
FilePathName.Buffer = ExAllocatePoolWithTag( NonPagedPool, FilePathName.MaximumLength, TAG );
if (FilePathName.Buffer == NULL) {
break;
}
RtlZeroMemory(FilePathName.Buffer, FilePathName.MaximumLength);
do
{
FileName.Buffer = pfni2->FileName;
FileName.Length = (USHORT)pfni2->FileNameLength;
FileName.MaximumLength = FileName.Length;
RtlCopyUnicodeString(&FilePathName, &pfni->Name);
if (FilePathName.Buffer[FilePathName.Length/2 -1] != L'\\')
{
status = RtlAppendUnicodeToString( &FilePathName, L"\\");
if (!NT_SUCCESS( status )) {
break;
}
}
if (RtlCompareUnicodeString(&FileName, &dot, TRUE) == 0 || RtlCompareUnicodeString(&FileName, &double_dot, TRUE) == 0)
{
FilePathName.Length -= 2;
}
else
{
status = RtlAppendUnicodeStringToString( &FilePathName, &FileName);
if (!NT_SUCCESS( status )) {
break;
}
}
InitializeObjectAttributes(&ob, &FilePathName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);
status = ZwOpenFile(&FileHandle, GENERIC_READ | SYNCHRONIZE, &ob, &IoStatusBlock, FILE_SHARE_READ, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS (status))
{
status = ZwOpenFile(&FileHandle, GENERIC_READ | SYNCHRONIZE, &ob, &IoStatusBlock, FILE_SHARE_READ, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS (status))
{
KdPrint(("\nZwOpenFile fail %wZ with 0x%x.\n", &FilePathName, status));//pagefile.sys和HIVE文件会打不开。
if ( status == STATUS_OBJECT_NAME_NOT_FOUND) {
KdPrint(("file does not exist\n"));
}
if (IoStatusBlock.Information == FILE_DOES_NOT_EXIST ) {
KdPrint(("file does not exist\n"));
}
break;
}
}
//status = FltQueryInformationFile(FltObjects->Instance, FltObjects->FileObject, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation, &LengthReturned);
status = ZwQueryInformationFile(FileHandle, &IoStatusBlock, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);
if (!NT_SUCCESS( status ))
{
if (FileHandle)
{
status = ZwClose(FileHandle);
if (!NT_SUCCESS (status))
{
KdPrint(("ZwClose fail with 0x%x.\n", status));
}
}
break;
}
if (fsi.Directory == TRUE )
{
KdPrint(("目录的名字:%wZ\n", &FilePathName));//注意这个有几个没有显示:点和双点及汉字的等。
}
else
{
KdPrint(("文件的名字:%wZ\n", &FilePathName));//FilePathName FileName
}
if (FileHandle)
{
status = ZwClose(FileHandle);
if (!NT_SUCCESS (status))
{
KdPrint(("ZwClose fail with 0x%x.\n", status));
}
}
pfni2 = (PFILE_NAMES_INFORMATION )((PCHAR)(pfni2) + pfni2->NextEntryOffset);
} while( pfni2->NextEntryOffset != 0 );
ExFreePoolWithTag(FilePathName.Buffer, TAG);
}
KdPrint(("\n"));
break;
//这两个对应的结构没有NextEntryOffset成员,并且上面的结构的第一个成员都是NextEntryOffset。
//case FileObjectIdInformation:
// break;
//case FileReparsePointInformation:
// break;
default://其实还有更多,不信你看头文件,注意对应的结构的处理。
KdPrint(("查询目录的类型:FileInformationClass:%d\n", Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass));
break;
}
FltReleaseFileNameInformation(pfni);
return FLT_POSTOP_FINISHED_PROCESSING;
}
CONST FLT_OPERATION_REGISTRATION Callbacks[] = {
{ IRP_MJ_DIRECTORY_CONTROL, 0, 0, DirectoryControlPostOperation},
{ IRP_MJ_OPERATION_END }
};
#pragma PAGEDCODE
NTSTATUS PtInstanceQueryTeardown (__in PCFLT_RELATED_OBJECTS FltObjects,__in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
{
return STATUS_SUCCESS;
}
#pragma PAGEDCODE//#pragma alloc_text(PAGE, PtUnload)
NTSTATUS PtUnload (__in FLT_FILTER_UNLOAD_FLAGS Flags)
{
FltUnregisterFilter( gFilterHandle );
return STATUS_SUCCESS;
}
CONST FLT_REGISTRATION FilterRegistration = {
sizeof( FLT_REGISTRATION ), // Size
FLT_REGISTRATION_VERSION, // Version
0, // Flags
NULL, // Context
Callbacks, // Operation callbacks
PtUnload, // MiniFilterUnload
NULL, // InstanceSetup
PtInstanceQueryTeardown, // InstanceQueryTeardown
NULL, // InstanceTeardownStart
NULL, // InstanceTeardownComplete
NULL, // GenerateFileName
NULL, // GenerateDestinationFileName
NULL // NormalizeNameComponent
};
DRIVER_INITIALIZE DriverEntry;
#pragma alloc_text(INIT, DriverEntry)//#pragma INITCODE
NTSTATUS DriverEntry (_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
NTSTATUS status;
UNREFERENCED_PARAMETER( RegistryPath );
KdBreakPoint();
status = FltRegisterFilter( DriverObject, &FilterRegistration, &gFilterHandle );
if (!NT_SUCCESS( status )) //FLT_ASSERT( NT_SUCCESS( status ) );
{
return status;
}
status = FltStartFiltering( gFilterHandle );
if (!NT_SUCCESS( status )) {
FltUnregisterFilter( gFilterHandle );
}
return status;
}
订阅:
博文 (Atom)