最近学一下hook ,初试hook KeyboardClassServiceCallback ,但是遇到点问题.调试一下午,不知道怎么弄?
下面贴上部分源代码:
__declspec(naked)
VOID
Froxy_KeyboardClassServiceCallback(
PDEVICE_OBJECT pDeviceObject,
PKEYBOARD_INPUT_DATA InputDataStart,
PKEYBOARD_INPUT_DATA InputDataEnd,
PULONG InputDataConsumed
)
{
_asm
{
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90 //填充Jmp
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90 //因为是长转移,所以必须是0x0080
}
}
void
fake_KeyboardClassServiceCallback(IN PDEVICE_OBJECT pDeviceObject,
IN PKEYBOARD_INPUT_DATA InputDataStart,
IN PKEYBOARD_INPUT_DATA InputDataEnd,
IN OUT PULONG InputDataConsumed
)
{
PShareMemory Scan = (PShareMemory)g_ShareMem;
/*
if(g_pReadReady == NULL || g_pReadFinish == NULL)
goto _x_;
*/
if(InputDataStart->Flags == KEY_MAKE || InputDataStart->Flags == KEY_E0)
{
RtlCopyMemory(Scan->Code,&InputDataStart->MakeCode,1);
dprintf("ScanCode is %d\n",Scan->Code[0]);
}
_asm
{
jmp Froxy_KeyboardClassServiceCallback
}
}
void
InlineHookkbClassServiceCallback()
{
KIRQL Irql;
BYTE JmpCodes[7] ={0xEA,0,0,0,0,0x08,0x00},InlineCodes[5] = {0xe9,0x00,0x00,0x00,0x00};
dprintf("==>进入 InlineHookkbClassServiceCallback 例程\n");
RtlCopyMemory(g_OrigCodes,(BYTE *)OldKbClassServiceCallbackAddr,5);
*((ULONG *)(InlineCodes+1)) = (ULONG)fake_KeyboardClassServiceCallback - (ULONG)OldKbClassServiceCallbackAddr - 5;
//关闭保护模式
_asm
{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
//提升Iqrl到Dpc
Irql = KeRaiseIrqlToDpcLevel();
RtlCopyMemory((BYTE *)OldKbClassServiceCallbackAddr,InlineCodes,5);
*((ULONG *)(JmpCodes + 1)) = (ULONG)((BYTE *)OldKbClassServiceCallbackAddr+5);
RtlCopyMemory((BYTE *)Froxy_KeyboardClassServiceCallback, g_OrigCodes, 5);
RtlCopyMemory((BYTE *)Froxy_KeyboardClassServiceCallback+5 , JmpCodes, 7);
//将Irql置成原来的Level
KeLowerIrql(Irql);
//开启保护模式
_asm
{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
dprintf("<==退出 InlineHookkbClassServiceCallback 例程\n");
}
调试发现,获取的扫描码是正确的,但是jmp到Froxy_KeyboardClassServiceCallback里,再jmp到原函数(KeyboardClassServiceCallback)的时候出错了.
出错位置为:KeyboardClassDequeueRead + 0x14
部分kbdclass.c源码
VOID
KeyboardClassServiceCallback(
IN PDEVICE_OBJECT DeviceObject,
IN PKEYBOARD_INPUT_DATA InputDataStart,
IN PKEYBOARD_INPUT_DATA InputDataEnd,
IN OUT PULONG InputDataConsumed
)
{
PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION irpSp;
LIST_ENTRY listHead;
PIRP irp;
ULONG bytesInQueue;
ULONG bytesToMove;
ULONG moveSize;
ULONG dumpData[2];
BOOLEAN logOverflow;
KbdPrint((2,"KBDCLASS-KeyboardClassServiceCallback: enter\n"));
deviceExtension = DeviceObject->DeviceExtension;
bytesInQueue = (ULONG)((PCHAR) InputDataEnd - (PCHAR) InputDataStart);
moveSize = 0;
*InputDataConsumed = 0;
logOverflow = FALSE;
//
// Notify system that human input has occured
//
PoSetSystemState (ES_USER_PRESENT);
//
// N.B. We can use KeAcquireSpinLockAtDpcLevel, instead of
// KeAcquireSpinLock, because this routine is already running
// at DISPATCH_IRQL.
//
KeAcquireSpinLockAtDpcLevel (&deviceExtension->SpinLock);
InitializeListHead (&listHead);
irp = KeyboardClassDequeueRead (deviceExtension);
if (irp) {
//
// An outstanding read request exists.
//
// Copy as much of the input data possible from the port input
// data queue to the SystemBuffer to satisfy the read.
//
irpSp = IoGetCurrentIrpStackLocation (irp);
bytesToMove = irpSp->Parameters.Read.Length;
moveSize = (bytesInQueue < bytesToMove) ?
bytesInQueue:bytesToMove;
*InputDataConsumed += (moveSize / sizeof(KEYBOARD_INPUT_DATA));
KeyboardClassDequeueRead函数部分源码:
PIRP
KeyboardClassDequeueRead(
IN PDEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
Dequeues the next available read irp regardless of FileObject
Assumptions:
DeviceExtension->SpinLock is already held (so no further sync is required).
--*/
{
PIRP nextIrp = NULL;
KIRQL oldIrql;
while (!nextIrp && !IsListEmpty (&DeviceExtension->ReadQueue)){
PDRIVER_CANCEL oldCancelRoutine;
PLIST_ENTRY listEntry = RemoveHeadList (&DeviceExtension->ReadQueue);
//
// Get the next IRP off the queue and clear the cancel routine
//
nextIrp = CONTAINING_RECORD (listEntry, IRP, Tail.Overlay.ListEntry);
oldCancelRoutine = IoSetCancelRoutine (nextIrp, NULL);
我初步认为出错在while (!nextIrp && !IsListEmpty (&DeviceExtension->ReadQueue))这句,但是不知道怎么改.
望大牛们,解惑一下,谢谢.
[课程]Linux pwn 探索篇!