關心我的同志們可能又要說了,哈哈,這個菜鳥又要發話了,嘿嘿,我菜鳥我榮幸。
最近的編程走向白熱化,因為剛開學,所以時間比較多,所以經常泡圖書館。下決心這學期一定搞定核心級編程,大話放出去了,實現與否還得看造化了。
剛剛邁入驅動程式設計的老高的門檻,發現原來困難重重,核心程式設計不同於一般的使用者層的介面程式設計,有大量的協助資料,網上的,MSDN,論壇裡的,各種各樣,連綿不絕。到了核心態,協助資料也少了,論壇的回複也少了,錯誤也比以前更難調試了,所以一下子不知道咋辦,手足無措,一連一個星期下來,除了在核心態列印的“Hello World”這句話通過了意外,其他的程式一律藍屏。驅動程式設計的錯誤不同於使用者態的程式設計,他更加接近底層的東西,所以一旦有邏輯上的或者說是編譯器無法檢查出來的非語法錯誤,就會導致系統的嚴重錯誤,直至藍屏。一時間不知道該咋辦。但是根據我多年的經驗來看,學習一門程式設計語言最重要的是不能放棄,只有在不斷的錯不斷的該,不斷的練的情況下你才能獲得一種居高臨下的感覺,才能使你編寫程式,而不是程式編寫你。
終於,黃天不負有心人,我的第二個不算太2的程式調試成功了,是一個HOOK鍵盤驅動的分發函數,實現截獲鍵盤輸入的例子,雖然網上有不少現成的,但是入門的程式設計菜鳥重在自己動手做,這個過程是痛苦的,我寫了好久,查閱了好多資料,調試了無數遍,經曆了無數次藍屏,終於在dbgview上看到了我的鍵盤輸入,那時候自己好開心。
下面就是我的hook的代碼,雖然沒有檢測其穩定性,也就是在替換分發函數的指標的時候有IRP發過來的情況,但是我測試過是可以啟動並執行,還有就是我沒有寫驅動的卸載模組,也就是說,這個hook一旦開始,除非關閉電腦,不可能使其停下。畢竟我是菜鳥嘛,就用一些簡單的功能聊以自慰。
代碼如下:
#include "wdm.h"
#include <ntddk.h>
#define KBD_DRIVER_NAME L"//Driver//kbdclass"
ULONG gC2pKeyCount=0; //全域變數記錄IRP個數
extern POBJECT_TYPE IoDriverObjectType;//聲明這個函數
PDRIVER_DISPATCH OldDispatchRead;//原IRP_MJ_READ函數的入口地址
NTSTATUS OnReadCompletion(IN PDRIVER_OBJECT DriverObject,
IN PIRP Irp,
IN PVOID Context
) //完成函數
{
PIO_STACK_LOCATION IrpSp;
ULONG buf_len=0;
PUCHAR buf=NULL;
size_t i;
IrpSp=IoGetCurrentIrpStackLocation(Irp);
if(NT_SUCCESS(Irp->IoStatus.Status))
{
buf=Irp->AssociatedIrp.SystemBuffer;
buf_len=Irp->IoStatus.Information;
for(i=0;i<=buf_len;++i)
{
DbgPrint("%2x/r/n",buf[i]);
}
}
gC2pKeyCount--;
if(Irp->PendingReturned)
{
IoMarkIrpPending(Irp);
}
return Irp->IoStatus.Status;
}
NTSTATUS NewDispatchRead(IN PDEVICE_OBJECT pDeviceObject, IN PIRP Irp) //新的分發函數
{
PIO_STACK_LOCATION irpSp; //以下的內容都是新分發函數的新增內容
irpSp = IoGetCurrentIrpStackLocation(Irp);
irpSp->Control = SL_INVOKE_ON_SUCCESS|SL_INVOKE_ON_ERROR|SL_INVOKE_ON_CANCEL;
//保留原來的完成函數,如果有的話
irpSp->Context = irpSp->CompletionRoutine;
irpSp->CompletionRoutine = (PIO_COMPLETION_ROUTINE)OnReadCompletion;
DbgPrint("已設定回呼函數.../n");
gC2pKeyCount++;
return OldDispatchRead(pDeviceObject,Irp); //調用原來的分發函數,完成應該有的內容
}
VOID DriverUnload(PDRIVER_OBJECT DriverObject) //卸載函數,應該更完善
{
DbgPrint("successful!");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath) //入口函數
{
PDRIVER_OBJECT kbdDriverObject;
UNICODE_STRING uniNtNameString;
NTSTATUS status=NULL;
NTSTATUS ObReferenceObjectByName(PUNICODE_STRING ObjectName, //先聲明
ULONG Attributes,
PACCESS_STATE AccessState,
ACCESS_MASK DesiredAccess,
POBJECT_TYPE ObjectType,
KPROCESSOR_MODE AccessMode,
PVOID ParseContext,
PVOID *Object);
RtlInitUnicodeString(&uniNtNameString,KBD_DRIVER_NAME); //初始化為0
status=ObReferenceObjectByName( //得到並開啟裝置
&uniNtNameString,
OBJ_CASE_INSENSITIVE,
NULL,
0,
IoDriverObjectType,
KernelMode,
NULL,
&kbdDriverObject);
if(!NT_SUCCESS(status))
{
DbgPrint("cannot get the kbd object/n");
return STATUS_UNSUCCESSFUL;
}
else
{
ULONG i;
//PDRIVER_DISPATCH OldDispatchFunctions[IRP_MJ_MAXIMUM_FUNCTION+1];
OldDispatchRead = kbdDriverObject->MajorFunction[IRP_MJ_READ];//儲存原IRP_MJ_READ函數的入口地址
InterlockedExchangePointer(&kbdDriverObject->MajorFunction[IRP_MJ_READ],NewDispatchRead);//替換為自訂的新分發函數的地址
ObDereferenceObject(kbdDriverObject); //不要忘記解除調用
}
DriverObject->DriverUnload=DriverUnload;
return STATUS_SUCCESS;
}