第三部分 R0 to R3
這部分有教主非常精彩和實用的分析,我就不瞎說了。
http://bbs.pediy.com/showthread.php?t=104918
r3 to r0 是常規系統調用倒過來
中斷或者sysenter的東西:
http://hi.baidu.com/andriy_aolala/blog/item/0ce3ebbf137db11a18d81fac.html
NTSTATUS
KeUserModeCallback (
INULONGApiNumber,
INPVOIDInputBuffer,
INULONGInputLength,
OUTPVOID *OutputBuffer,
INPULONGOutputLength
)
這個函數設置好棧的佈局後調用KiCallUserMode
KiCallUserMode調用_KiServiceExit
返回到ring3的_KeUserCallbackDispatcher
KeUserCallbackDispatcher從_PEB.KernelCallbackTable取得函數,執行,NtCallbackReturn返回
_PEB.KernelCallbackTable是函數表,ApiNumber是服務調用號
這些函數傳遞的參數可以參考windows_2000_source_code\win2k\private\ntos\w32\ntuser\inc\ntcb.h
不同版本不一定一樣~
kd>dds 0x77d12970
77d12970 77d27f3c USER32!__fnCOPYDATA
77d12974 77d587b3USER32!__fnCOPYGLOBALDATA
77d12978 77d28ec8 USER32!__fnDWORD
77d1297c 77d2b149 USER32!__fnNCDESTROY
77d12980 77d5876c USER32!__fnDWORDOPTINLPMSG
77d12984 77d5896d USER32!__fnINOUTDRAG
77d12988 77d3b84d USER32!__fnGETTEXTLENGTHS
等等。。。
這個地方可以hook,XT也提供了檢測這個位置的功能,不過hook這裏的樣本倒是沒見過~這個字段在應用層是隻讀的~~
Hook wndproc的話倒是可以直接hook __fnINOUTLPPOINT5。不過太麻煩了,只是參數過濾的話就在KeUserModeCallback過濾了。
我看到過直接替換windows object裏面wndproc參數的東東。
kd> k
ChildEBP RetAddr
0012f738 77d18734 4may!WndProc+0x18[C:\Users\shendi\Desktop\梅亞飛監視u盤拷貝ppt_src\4may_src\4may.cpp @167]
0012f764 77d18816USER32!InternalCallWinProc+0x28
0012f7cc 77d28ea0USER32!UserCallWinProcCheckWow+0x150
0012f820 77d2d08aUSER32!DispatchClientMessage+0xa3
0012f848 7c92e453 USER32!__fnINOUTLPPOINT5+0x27
0012f848 805026fcntdll!KiUserCallbackDispatcher+0x13
b162b920 805a2d55 nt!KiCallUserMode+0x4
b162b97c bf83b414 nt!KeUserModeCallback+0x87
b162ba2c bf813f04 win32k!SfnINOUTLPPOINT5+0xbf
b162ba74 bf8140f6win32k!xxxSendMessageToClient+0x176
b162bac0 bf80ec99 win32k!xxxSendMessageTimeout+0x1a6
b162bae4 bf83b194 win32k!xxxSendMessage+0x1b
b162bb44 bf826c4cwin32k!xxxInitSendValidateMinMaxInfo+0x1b9
b162bb88 bf83a93c win32k!xxxAdjustSize+0x22
b162bc6c bf83967e win32k!xxxCreateWindowEx+0x8fe
b162bd20 8054267c win32k!NtUserCreateWindowEx+0x1c1
b162bd20 7c92e4f4 nt!KiFastCallEntry+0xfc
0012f848 7c92e453 ntdll!KiFastSystemCallRet
0012f890 77d2e389ntdll!KiUserCallbackDispatcher+0x13
0012fd34 77d2e442USER32!NtUserCreateWindowEx+0xc
0012fde0 77d2e4dc USER32!_CreateWindowEx+0x1ed
0012fe1c 00401451 USER32!CreateWindowExA+0x33
0012fea4 004010e8 4may!InitInstance+0x51[C:\Users\shendi\Desktop\梅亞飛監視u盤拷貝ppt_src\4may_src\4may.cpp @142]
0012ff20 00401fe3 4may!WinMain+0x58[C:\Users\shendi\Desktop\梅亞飛監視u盤拷貝ppt_src\4may_src\4may.cpp @48]
0012ffc0 7c817077 4may!WinMainCRTStartup+0x1b3[crtexe.c @ 330]
0012fff0 00000000 kernel32!BaseProcessStart+0x23
第四部分 鍵盤鼠標輸入
中斷服務把鍵盤碼發給鍵盤驅動,csrss開一個線程win32k!RawInput循環read irp給鍵盤驅動~
ROS最新的0.3.14 csrss調用NtUserCallOneParam,進入內核線程RawInputThreadMain,應該說這是更接近於windows的
看一下這個線程做了什麼,鍵盤按鍵操作中的時候會pending,等待pending的操作沒貼出來
for(;;)
{
Status =OpenInputDevice(&ghMouseDevice, &pMouDevice, L"\\Device\\PointerClass0");
Status =OpenInputDevice(&ghKeyboardDevice, &pKbdDevice, L"\\Device\\KeyboardClass0");
MouStatus= ZwReadFile(ghMouseDevice,
NULL,
NULL,
NULL,
&MouIosb,
&MouseInput,
sizeof(MOUSE_INPUT_DATA),
&ByteOffset,
NULL);
KbdStatus= ZwReadFile(ghKeyboardDevice,
NULL,
NULL,
NULL,
&KbdIosb,
&KeyInput,
sizeof(KEYBOARD_INPUT_DATA),
&ByteOffset,
NULL);
UserProcessMouseInput(&MouseInput);
UserProcessKeyboardInput(&KeyInput);
}
KEYBOARD_INPUT_DATA這個結構是鍵盤驅動上傳數據標準結構
UserProcessKeyboardInput這個函數
//得到目前的焦點,這個實在desktop的結構裏
pFocusQueue= IntGetFocusMessageQueue();
if (pFocusQueue)
{
pFocusThread= pFocusQueue->Thread;
if(pFocusThread&&pFocusThread->Tcb.Win32Thread)
pKl= ((PTHREADINFO)pFocusThread->Tcb.Win32Thread)->KeyboardLayout;
}
//鍵盤佈局
if (!pKl)
pKl= W32kGetDefaultKeyLayout();
將掃描碼轉換成虛擬按鍵,最後調用
UserSendKeyboardInput(&KbdInput,FALSE);
最終ProcessKeyEvent在處理完hook以及其他特殊情況以後
MsqPostMessage(pFocusQueue,&Msg, TRUE, QS_KEY);發送給焦點窗口
所以說要攔截鍵盤消息太底層就要自己處理掃描碼了~~當然也不是不行
軟件可以模擬鍵盤輸入,就是NtUserSendInput啦