__declspec(naked)void MyKeyboardClassServiceCallback()
{
_asm
{
pop g_OrigRetAddr //调用被Call Hook替换的函数前,平衡堆载
call g_ulkbdNeedCallAddr //xp是PoSetSystemState函数
push eax
mov eax,[ebp+4h] //判断调用Callback的函数的地址是否在端口驱动中
cmp eax,g_ulKbdPs2PortStart
jae ps2StartOk //先判断是否为ps2端口驱动调用,
jmp short isUsbKbd //再判断是否为usb端口驱动调用
ps2StartOk:
cmp eax,g_ulKbdPs2PortEnd
jbe over
isUsbKbd:
cmp eax,g_ulKbdUsbPortStart
jae usbStartOk
jmp short isFilter
usbStartOk:
cmp eax,g_ulKbdUsbPortEnd
jbe over
isFilter: //检查是否在过滤驱动中,允许过滤驱动调用kbdCallBack(比如eaps2kbd)
push ebx
push ecx
push edx
mov ecx,20 //从ebp+18h(跳过4个传入的参数)往下检测20个堆载帧
mov al,0
mov ebx,14h
conCheck:
add ebx,4
mov edx,[ebp+ebx]
cmp edx, MmSystemRangeStart //低于内核地址(一般是0x80000000)
jb fOver
cmp edx,g_ulKbdPs2PortStart //有过滤驱动
jae _ps2StartOk
jmp short _isUsbKbd
_ps2StartOk:
cmp edx,g_ulKbdPs2PortEnd
setbe al //满足则置al为1
jbe fOver
_isUsbKbd:
cmp edx,g_ulKbdUsbPortStart
jae _usbStartOk
jmp short fLoop
_usbStartOk:
cmp edx,g_ulKbdUsbPortEnd
setbe al //满足则置al为1
jbe fOver
fLoop:
Loop conCheck
fOver:
pop edx
pop ecx
pop ebx
test al,1
jnz over
mov eax,[ebp+10h] //fake
sub eax,[ebp+0Ch]
cmp eax,ebx //真实Callback函数调用第一个函数前会把输入的数量赋值给ebx
jne cmpEcx //(其它也要判断下,以防微软代码小变动,winxp使用ebx,win7使用eax)
mov ebx,0 //把需要伪造的数量置为0
jmp short doLast
cmpEcx:
cmp eax,ecx
jne cmpEdx
mov ecx,0
jmp short doLast
cmpEdx:
cmp eax,edx
jne cmpEsi
mov edx,0
jmp short doLast
cmpEsi:
cmp eax,esi
jne cmpEdi
mov esi,0
jmp short doLast
cmpEdi:
cmp eax,edi
jne cmpArg1
mov edi,0
jmp short doLast
cmpArg1: //编译器有时会用传入的参数保存临时变量
cmp eax,[ebp+8h] //参数2和3为InputDataStart和InputDataEnd,
jne cmpArg4
mov [ebp+8],0
jmp short doLast
cmpArg4:
cmp eax,[ebp+14h]
jne doLast
mov [ebp+14h],0
jmp short doLast
doLast:
mov [ebp+8],0 //DeviceObject置为NULL
mov eax,[ebp+0Ch] //设置InputDataEnd=InputDataStart 键盘输入数量置为0
mov [ebp+10h],eax
mov m_bFake,1
over:
pop eax
push g_OrigRetAddr //返回到真实kbdCallBack Call后的地址
ret
}
}
3. 硬件模式:模拟挂使用WRITE_PORT_UCHAR、往0x60、0x64端口直接发送键盘数据。使用READ_PORT_UCHAR读取0x64端口状态(实际上是调用in、out输入输出汇编指令)。检测方法为hook int 0x93中断,在中断中获取按键,并要求i8048(键盘控制器)重发上次的按键,若两次不相等则说明是模拟挂在操作键盘。因为直接使用WRITE_PORT_UCHAR发送的按键是不会在i8048中保存上次按键的。有关i8048详细资料参考:http://hi.baidu.com/_erex/item/63120114b5b0aee55e53b11d。
以下是检测硬件模拟中操作i8048的代码: