Windows熱鍵註冊原理
BOOL RegisterHotKey(
HWND hWnd,
int id,
UINT fsModifiers,
UINT vk
);
函式功能:該函式定義一個系統範圍的熱鍵。
函式原型:BOOL RegisterHotKey(HWND hWnd,int id,UINT fsModifiers,UINT vk);
引數:
hWnd:接收熱鍵產生WM_HOTKEY訊息的視窗控制代碼。若該引數NULL,傳遞給呼叫執行緒的WM_HOTKEY訊息必須在訊息迴圈中中進行處理。
id:定義熱鍵的識別符號。呼叫執行緒中的其他熱鍵不能使用同樣的識別符號。應用功能程式必須定義一個0X0000-0xBFFF範圍的值。一個共享的動態連結庫(DLL)必須
定義一個0xC000-0xFFFF範圍的值伯GlobalAddAtom函式返回該範圍)。為了避免與其他動態連結庫定義的熱鍵衝突,一個DLL必須使用GlobalAddAtom函式獲得熱鍵的標
識符。
fsModifoers:定義為了產生WM_HOTKEY訊息而必須與由nVirtKey引數定義的鍵一起按下的鍵。該引數可以是如下值的組合:
MOD_ALT:按下的可以是任一Alt鍵。MOD_CONTROL:按下的可以是任一Ctrl鍵。
MOD_SHIFT:按下的可以是任一Shift鍵。
MOD_WIN:按下的可以是任一Windows按鍵。這些鍵可以用Microsoft Windows日誌記錄下來。
MOD_NOREPEAT:Windows 7或者後續版本: 更改熱鍵行為,以便鍵盤自動重複不會產生多個熱鍵通知。
vk:定義熱鍵的虛擬鍵碼。
返回值:若函式呼叫成功,返回一個非O值。若函式呼叫失敗,則返回值為0。若要獲得更多的錯誤資訊,可以呼叫GetLastError函式。
備註:當某鍵被接下時,系統在所有的熱鍵中尋找匹配者。一旦找到一個匹配的熱鍵,系統將把WM_HOTKEY訊息傳遞給登記了該熱鍵的執行緒的訊息佇列。該訊息被傳
送到佇列頭部,因此它將在下一輪訊息迴圈中被移去。該函式不能將熱鍵同其他執行緒建立的視窗關聯起來。
若為一熱鍵定義的擊鍵己被其他熱鍵所定義,則RegisterHotKey函式呼叫失敗。
若hWnd引數標識的視窗已用與id引數定義的相同的識別符號登記了一個熱鍵,則引數fsModifiers和vk的新值將替代這些引數先前定義的值。
Windows CE:Windows CE 2.0以上版本對於引數fsModifiers支援一個附加的標誌位。叫做MOD_KEYUP。
若設定MOD_KEYUP位,則當發生鍵被按下或被彈起的事件時,視窗將傳送WM_HOTKEY訊息。
RegisterHotKey可以被用來線上程之間登記熱鍵。
速查:Windows NT:3.1及以上版本;Windows:95及以上版本;Windows CE:不支援;標頭檔案:winuser.h;庫檔案:Hotkey.lib。
F12鍵是偵錯程式所使用的保留,所以不應將其註冊為熱鍵
程式碼:
#define MOD_ALT 0x0001 = 1 #define MOD_CONTROL 0x0002 = 10 #define MOD_SHIFT 0x0004 = 100 #define MOD_WIN 0x0008 = 1000
在IDA中反彙編RegisterHotKey
程式碼:
.text:77D1EBB3 mov eax, 11EAh //系統服務號 .text:77D1EBB8 mov edx, 7FFE0300h .text:77D1EBBD call dword ptr [edx] .text:77D1EBBF retn 10h .text:77D1EBBF [email protected] endp系統把服務號儲存在eax暫存器,直接call [edx]
OD檢視得到7FFE0300
程式碼:
dd 7FFE0300 7FFE0300 7C92E510 ntdll.KiFastSystemCall 7FFE0304 7C92E514 ntdll.KiFastSystemCallRetWindbg檢視得到
程式碼:
lkd> dd ffdf0300 l2 ffdf0300 7c92e510 7c92e514 lkd> u 7c92e510 7c92e510 8bd4 mov edx,esp 7c92e512 0f34 sysenterwindows中0x7FFE0000和0x0FFDF0000被對映到同一個實體地址,供4KB,但在使用者模式下該地址是不可寫的,核心模式下的可寫,4K空間作業系統佔用一部分,
餘下的大約有3K
USER:0x7FFE0000
KERNEL:0x0FFDF0000
在Windbg可用dt nt!_KUSER_SHARED_DATA命令檢視該共享區域
程式碼:
lkd> dt nt!_KUSER_SHARED_DATA +0x000 TickCountLow : Uint4B +0x004 TickCountMultiplier : Uint4B +0x008 InterruptTime : _KSYSTEM_TIME +0x014 SystemTime : _KSYSTEM_TIME +0x020 TimeZoneBias : _KSYSTEM_TIME +0x02c ImageNumberLow : Uint2B +0x02e ImageNumberHigh : Uint2B +0x030 NtSystemRoot : [260] Uint2B +0x238 MaxStackTraceDepth : Uint4B +0x23c CryptoExponent : Uint4B +0x240 TimeZoneId : Uint4B +0x244 Reserved2 : [8] Uint4B +0x264 NtProductType : _NT_PRODUCT_TYPE +0x268 ProductTypeIsValid : UChar +0x26c NtMajorVersion : Uint4B +0x270 NtMinorVersion : Uint4B +0x274 ProcessorFeatures : [64] UChar +0x2b4 Reserved1 : Uint4B +0x2b8 Reserved3 : Uint4B +0x2bc TimeSlip : Uint4B +0x2c0 AlternativeArchitecture : _ALTERNATIVE_ARCHITECTURE_TYPE +0x2c8 SystemExpirationDate : _LARGE_INTEGER +0x2d0 SuiteMask : Uint4B +0x2d4 KdDebuggerEnabled : UChar +0x2d5 NXSupportPolicy : UChar +0x2d8 ActiveConsoleId : Uint4B +0x2dc DismountCount : Uint4B +0x2e0 ComPlusPackage : Uint4B +0x2e4 LastSystemRITEventTickCount : Uint4B +0x2e8 NumberOfPhysicalPages : Uint4B +0x2ec SafeBootMode : UChar +0x2f0 TraceLogging : Uint4B +0x2f8 TestRetInstruction : Uint8B +0x300 SystemCall : Uint4B +0x304 SystemCallReturn : Uint4B +0x308 SystemCallPad : [3] Uint8B +0x320 TickCount : _KSYSTEM_TIME +0x320 TickCountQuad : Uint8B +0x330 Cookie : Uint4B11EA = 1000111101010 = 13~14位選擇服務描述表,選擇KeServiceDescriptorTableShadow,系統共有4個服務描述表,第一個在ntoskrnl.exe中
並匯出KeServiceDescriptorTable指標
可見該函式沒做任何處理直接進入核心(win32k.sys)中,在Windbg反彙編:
程式碼:
lkd> uf win32k!NtUserRegisterHotKey win32k!NtUserRegisterHotKey+0x34: bf899720 33c0 xor eax,eax //eax = NULL bf899722 eb29 jmp win32k!NtUserRegisterHotKey+0x36 (bf89974d) win32k!NtUserRegisterHotKey: bf899729 8bff mov edi,edi bf89972b 55 push ebp bf89972c 8bec mov ebp,esp bf89972e 56 push esi bf89972f e8b673f6ff call win32k!EnterCrit (bf800aea) bf899734 f74510f07fffff test dword ptr [ebp+10h],0FFFF7FF0h //fsModifiers是否有效,是否大於1000b 11111111111111110111111111110000 bf89973b 752d jne win32k!NtUserRegisterHotKey+0x14 (bf89976a)//fsModifiers無效則跳轉 win32k!NtUserRegisterHotKey+0x20: bf89973d 8b4d08 mov ecx,dword ptr [ebp+8] //hWnd bf899740 85c9 test ecx,ecx bf899742 74dc je win32k!NtUserRegisterHotKey+0x34 (bf899720)//hWnd == NULL win32k!NtUserRegisterHotKey+0x27: bf899744 e86a7ef6ff call win32k!ValidateHwnd (bf8015b3)//則驗證控制代碼 bf899749 85c0 test eax,eax bf89974b 7427 je win32k!NtUserRegisterHotKey+0x30 (bf899774) //返回NULL win32k!NtUserRegisterHotKey+0x36: bf89974d ff7514 push dword ptr [ebp+14h] //vk bf899750 ff7510 push dword ptr [ebp+10h] //fsModifiers bf899753 ff750c push dword ptr [ebp+0Ch] //id bf899756 50 push eax //pWnd bf899757 e8aefeffff call win32k!_RegisterHotKey (bf89960a) bf89975c 8bf0 mov esi,eax win32k!NtUserRegisterHotKey+0x47: bf89975e e8b373f6ff call win32k!LeaveCrit (bf800b16) bf899763 8bc6 mov eax,esi bf899765 5e pop esi bf899766 5d pop ebp bf899767 c21000 ret 10h win32k!NtUserRegisterHotKey+0x14: bf89976a 68ec030000 push 3ECh //錯誤碼:1004,引數無效 bf89976f e83da0f6ff call win32k!UserSetLastError (bf8037b1) win32k!NtUserRegisterHotKey+0x30: bf899774 33f6 xor esi,esi bf899776 ebe6 jmp win32k!NtUserRegisterHotKey+0x47 (bf89975e) /***************************************/ PWND FASTCALL ValidateHwnd( HWND hwnd);//NtUserRegisterHotKey虛擬碼:
程式碼:
BOOLEN APIENTRY NtUserRegisterHotKey(HWND hWnd, int id, UINT fsModifiers, UINT vk) { BOOLEN bRet; PWND pWnd = NULL; EnterCrit(); if(!(fsModifiers & 0x0FFFF7FF0h)) { if(hWnd) { pWnd = ValidateHwnd(hWnd); } bRet = _RegisterHotKey(pWnd,id,fsModifiers,vk); } else { UserSetLastError(1004);//1004無效標誌 bRet = FALSE; } LeaveCrit(); return bRet; }//系統熱鍵結構:
程式碼:
typedef struct _HOT_KEY_ITEM { PETHREAD Thread; HWND spwnd; UINT fsModifiers; UINT vk; int id; struct _HOT_KEY_ITEM phkNext; } HOT_KEY_ITEM, *PHOT_KEY_ITEM;_RegisterHotKey虛擬碼如下:
程式碼:
BOOL _RegisterHotKey( PWND pwnd, int id, UINT fsModifiers, UINT vk) { PHOT_KEY_ITEM phk; BOOL fKeysExist = FALSE; PTHREADINFO ptiCurrent; PWINDOWSTATION pwinsta = _GetProcessWindowStation(NULL); DWORD ErrorCode; ptiCurrent = gptiCurrent; //如果呼叫者不是WindowStation初始化的執行緒和不適當的許可權 if(grpwinstaList && !CheckWinstaWriteAttributesAccess()) { return FALSE; } //不能為其他執行緒的視窗註冊熱鍵 if ((pwnd != PWND_FOCUS) && (pwnd != PWND_INPUTOWNER)) { if (GETPTI(pwnd) != ptiCurrent) { UserSetLastError(1408); //1408錯誤碼:無效視窗;它屬於另一執行緒。 return FALSE; } } phk = FindHotKey(ptiCurrent, pwnd, id, fsModifiers, vk, FALSE, &fKeysExist); //如果其他執行緒已經註冊過該熱鍵,返回FALSE if (fKeysExist) { UserSetLastError(1409); //1409錯誤碼:熱鍵已被註冊 return FALSE; } if (phk == NULL) { //熱鍵並未被註冊 phk = (PHOT_KEY_ITEM)HeavyAllocPool(sizeof(HOT_KEY_ITEM), TAG_HOTKEY); //分配失敗,返回FALSE if (phk == NULL) { return FALSE; } phk->pti = ptiCurrent; if ((pwnd != PWND_FOCUS) && (pwnd != PWND_INPUTOWNER)) { phk->spwnd = NULL; HMAssignmentLock(&phk->spwnd, pwnd); } else { phk->spwnd = pwnd; } phk->fsModifiers = fsModifiers; phk->vk = vk; phk->id = id; //插入到系統熱鍵連結串列中 //gphkFirst - 這是不匯出變數儲存了系統結構熱鍵(phkNext指向下一個熱鍵結構域)地址 phk->phkNext = gphkFirst; gphkFirst = phk; } else { //如果本執行緒已註冊過該熱鍵,則重新覆蓋 phk->fsModifiers = fsModifiers; phk->vk = vk; } return TRUE; }//用Windbg檢視下gphkFirst
程式碼:
lkd> dd gphkFirst L1 bf9af814 e2ce10d8
e2ce10d8就是最近一次軟體向系統註冊的全域性熱鍵,繼續
程式碼:
lkd> dd e2ce10d8 l6 e2ce10d8 e2265008 bbe35a28 00000003 00000054 e2ce10e8 0000c024 e2291a68e2265008 是ETHREAD,檢視發現是QQ的一個執行緒
bbe35a28 是視窗控制代碼
00000003 是功能鍵11,說明有Ctrl+Alt鍵
00000054 是VK_?,0x54對應ASCI碼的大寫T,Ctrl+ATL+T(QQ上:傳送騰訊微博的)
0000c024 是熱鍵的ID
e2291a68 是下一個熱鍵結構
程式碼:
PHOT_KEY_ITEM FindHotKey( PTHREADINFO ptiCurrent, PWND pwnd, int id, UINT fsModifiers, UINT vk, BOOL fUnregister, PBOOL pfKeysExist) { PHOT_KEY_ITEM phk, phkRet, phkPrev; //初始化返回值 *pfKeysExist = FALSE; phkRet = NULL; phk = gphkFirst; while (phk) { if ((phk->pti == ptiCurrent) && (phk->spwnd == pwnd) && (phk->id == id)) { if (fUnregister) { //摘掉熱鍵 if (phk == gphkFirst) { gphkFirst = phk->phkNext; } else { phkPrev->phkNext = phk->phkNext; } if ((pwnd != PWND_FOCUS) && (pwnd != PWND_INPUTOWNER)) { Unlock(&phk->spwnd); } UserFreePool((PVOID)phk); return((PHOT_KEY_ITEM)1); } phkRet = phk; } //如果熱鍵已經註冊過,設定已存在標誌 if ((phk->fsModifiers == fsModifiers) && (phk->vk == vk)) { if (phk->spwnd == PWND_FOCUS) { if (phk->pti == ptiCurrent) { *pfKeysExist = TRUE; } } else { *pfKeysExist = TRUE; } } phkPrev = phk; phk = phk->phkNext; } return phkRet; }//遍歷系統熱鍵
程式碼:
VOID DumpHotKeys() { ULONG dwAddr; KAPC_STATE ApcState; PETHREAD pThread; PEPROCESS pProc; PHOTKEY phk; //必須在GUI執行緒中遍歷 KeStackAttachProcess( pExpEprocess , &ApcState ); dwAddr = *(PULONG)gphkFirst; KeUnstackDetachProcess(&ApcState); phk = (PHOTKEY)dwAddr; //解析系統所有熱鍵 while( phk != NULL ) { pThread = *(PULONG)phk->pti; //0x220位置指向當前執行緒的EPROCESS pProc = *(PULONG)( (ULONG)pThread + 0x220 ); //EPROCESS + 0x174指向程序名字 KdPrint(("Process Name : %s\n" , (ULONG)pProc + 0x174 )); KdPrint(("id : %d\n" , phk->id )); KdPrint(("Combination : %s + %X\n" , GetButton( phk->fsModifiers ) , phk->vk )); KdPrint(("------------------------------------------\n")); phk = phk->phkNext; } }
相關推薦
Windows熱鍵註冊原理
要像系統註冊一個全域性熱鍵,需要用到RegisterHotKey,函式用法如下(MSDN):BOOL RegisterHotKey( HWND hWnd, int id, UINT fsModifi
Windows熱鍵註冊(反彙編方法 檢視win32api 原理)
要像系統註冊一個全域性熱鍵,需要用到RegisterHotKey,函式用法如下(MSDN): BOOL RegisterHotKey( HWND hWnd, int id, UINT fsM
windows 程式設計 註冊熱鍵
網上找了很多關於註冊熱鍵的,都是基於MFC 響應的。 本文是 直接響應 對於註冊多個熱鍵,使用hotkeyid ,我這裡是使用 對於 輸入的按鍵,進行拼接,將保證每次鍵入的id 都不同,方便移除熱鍵/****************************/ /***直接
windows 微軟註冊
alt cnblogs 分享 windows es2017 ima ges http src windows 微軟註冊
初級遊戲外掛編程詳解 windows運行原理+遊戲輔助編程 遊戲外掛編程
穩定 程序員 操作系統 上下 open 服務 dll stdio.h 五個 詳解遊戲輔助編程 【目錄】 1-什麽是Windows API 2-Windows進程 3-Windows 的內存的運行原理 4-windows 中句柄的概念 5-Windows的變量類型
windows系統註冊TeeChart8.ocx
下面win7為例。 win7系統64位版本: 1、把TeeChart8.ocx拷貝到系統的C:\Windows\SysWOW64\目錄。 2、以管理員身份執行cmd.exe,它的位置在C:\Windows\SysWOW64\目錄。 3、執行以下命令: cd .
Windows如何註冊Com元件
1.先了解什麼是Com元件 Com元件百科地址:https://baike.baidu.com
Delphi全域性熱鍵註冊
private { Private declarations } Aatom: ATOM; procedure hotkey(var msg: TMessage); message WM_HOTKEY; procedure TForm1.Fo
windows服務註冊 -- svn伺服器開機自啟
啟用SVN服務,按下windows+R鍵,輸入cmd進入命令介面,輸入svnserve -d -r e:\ejsvn;e:\ejsvn為你伺服器目錄; 注意:這是臨時開啟的服務,命令執行後不能關閉視窗
獲取Windows系統註冊的檔案型別和圖示
煩死,寫了快一個小時。不知道怎麼碰了一下,就沒了。隨便記記吧。 就是獲取下面這個新建裡面的內容: 思路: (1)獲取系統已註冊的檔案型別 登錄檔路徑:MFC版獲取檔案型別 地址:http://blog.csdn.net/qq2399431200/article/deta
myeclipse 2013 SR2 for(MAC/WINDOWS)破解 註冊過程
前天去官網下載的時候都還只是sr1,結果昨天去看居然有sr2了,之前一直在windows下用 2013,網上的註冊機都還很好用。但最近換了mac,下載的sr1我卻無論如何都沒辦法破解,下載了N個版本的註冊機都不行。 今天終於把它搞定了。與大家分享一下: 1 首先來這裡下載註
QT 如何註冊系統熱鍵,類似 Windows上的RegisterHotKey函式一樣
下載庫: 在linux下編譯安裝,ubuntu9.10上會報找不到X11/libx.h,執行命令apt-get install libx11-dev安裝完後再編譯就可以了 2:在qt中使用qxt庫 在pro檔案中加上 CONFIG += qxt
玩轉Windows服務系列——Debug、Release版本的註冊和解除安裝,及其原理
Windows服務Debug版本 註冊 Services.exe -regserver 解除安裝 Services.exe -unregserver Windows服務Release版本 註冊 Services.exe -service 解除安裝 Services
windows dos 修改註冊表
edev 能夠 最好 cal pro write prot storage ont U盤被寫保護了,然後需要修改註冊表,解決辦法這個不一定是最好的,僅僅是為了能讓dos能夠做處理,記錄一下: rem delete firstREG DELETE HKEY_LOCAL_MAC
Elasticsearch 註冊為Windows服務
size 註意 ont enter window search nts ice ast 首先 cd 到es文件夾中的bin: 然後註冊為windows服務,註意 elasticsearch-service 即為上圖中標註elasticsearch-service.b
詳解Windows註冊表分析取證
classes 創建 dev html ida soft free 人在 隱藏 大多數都知道windows系統中有個叫註冊表的東西,但卻很少有人會去深入的了解它的作用以及如何對它進行操作。然而對於計算機取證人員來說註冊表無疑是塊巨大的寶藏。通過註冊表取證人員能分析出系統發生
Node.js原生及Express方法實現註冊登錄原理
美化 set head ack function charset stat input col 由於本文只是實現其原理,所以沒有使用數據庫,只是在js裏面模擬數據庫,當然實際中還是需要用數據庫的。 1.node.js原生方法 ①html頁面,非常簡單,沒有一絲美化~我們叫它
把Tomcat註冊為windows服務
control bsp png adb mage windows ont 自動 cmd windows安裝java及配置環境 http://www.cnblogs.com/17shiqi/p/7397939.html Tomcat註冊為windows服務 本人是win7
Windows 編程入門,如何註冊賬號
ima 界面 登錄 windows com tle 賬號註冊 登陸 分享 第一步:點擊立即註冊 第二步:點擊註冊,用郵箱作為賬號註冊登錄,由於我已經註冊了,所以就出現這個頁面 第三步:登陸界面 Windows 編程入門,如何註冊賬號
Windows Server下把BAT批處理註冊成服務在後臺運行且註銷後能正常運行
sha 方法 pytho 面具 blog overflow 程序 str .cn 批處理有如下特點: 1、登錄到當前窗口運行時,如果關閉控制臺會連同啟動的程序一起關閉。 2、如果是以start /b的形式啟動,那麽同樣也是在控制臺關閉後者註銷當前窗口也會一起關閉。 3