1. 程式人生 > >Windows熱鍵註冊(反彙編方法 檢視win32api 原理)

Windows熱鍵註冊(反彙編方法 檢視win32api 原理)

要像系統註冊一個全域性熱鍵,需要用到RegisterHotKey,函式用法如下(MSDN):
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.KiFastSystemCallRet

Windbg檢視得到
lkd> dd ffdf0300 l2
ffdf0300  7c92e510 7c92e514

lkd> u 7c92e510
7c92e510 8bd4            mov     edx,esp
7c92e512 0f34            sysenter

windows中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           : Uint4B


11EA = 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 e2291a68

e2265008 是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熱鍵註冊(彙編方法 檢視win32api 原理)

要像系統註冊一個全域性熱鍵,需要用到RegisterHotKey,函式用法如下(MSDN): BOOL RegisterHotKey(                   HWND hWnd,             int id,             UINT fsM

Windows熱鍵註冊原理

要像系統註冊一個全域性熱鍵,需要用到RegisterHotKey,函式用法如下(MSDN):BOOL RegisterHotKey(                  HWND hWnd,            int id,            UINT fsModifi

ARM的BIN檔案彙編方法

最近在除錯uboot的程式碼時,用的新版本的uboot,lowlevel_init函式裡是空的,而且在連結檔案中也沒有發現對lowlevel_init.o的連結。在bl lowlevel_init 之前和之中加了兩個電燈,發現在bl之後的部分並沒有被執行,所以想看看具體程式

轉——一個超級wince牛人使用彙編工具修改程式的方法

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

windows下端口占用解決方法-檢視和殺死佔用埠程序

在Windows下啟動程式時有時會遇到埠被佔用的情況,由於一個埠同時只能執行一個程序,所以要想啟動新的程式就要先把佔用該埠的程序給kill掉,具體的命令分為以下三步, 以殺死佔用了80埠的程序為例: 1、根據埠號“80”查詢程序號 netstat -ano|findstr "80" TCP

windows、ubuntu系統程式執行檢視視訊記憶體方法

ubuntu系統 開啟終端  在終端直接輸入命令列    nvidia-smi 即可檢視 windows系統 執行 命令列  nvidia-smi.exe  -l  方法如下: nvidia-smi.exe 路徑 C:\Windows\System32\DriverStor

dex2jar彙編android的dex/APK檔案為jar包命令和方法

1、下載dex2jar 2、windows系統開啟cmd進入dex2jar.bat目錄  輸入命令: dex2jar.bat  ./classes.dex  或者 d2j-dex2jar classes.dex(classes.dex 為需要反編譯的檔案,) 3、即可生成

彙編檢視gcc行為

int i = 3; printf(”%d/n”, i++ * ++i + i– * –i); 在吉林大學的視訊c教程中, 上式值為18.她的解法是字首優先於字尾,所以就是3 * 4 + 3 * 2。在gcc中得到的結果是25。 這種行為是標準未定義的。 可以通過反彙編來檢視gcc的行為。如下,我們看看呼叫

windows 程式設計 註冊熱鍵

網上找了很多關於註冊熱鍵的,都是基於MFC 響應的。 本文是 直接響應 對於註冊多個熱鍵,使用hotkeyid ,我這裡是使用 對於 輸入的按鍵,進行拼接,將保證每次鍵入的id 都不同,方便移除熱鍵/****************************/ /***直接

shellcode 彙編,模擬執行以及除錯方法

onlinedisassembler https://onlinedisassembler.com 線上反彙編工具,類似於lda。功能比較單一。 Any.run 等平臺線上分析 將shellcode儲存為檔案 通過如下指令碼,轉換shellcode為char陣列 import binascii fil

windows 微軟註冊

alt cnblogs 分享 windows es2017 ima ges http src windows 微軟註冊

未知打磨IC芯片型號鑒定IC芯片型號查詢單片機絲印查詢方法

芯片型號鑒定 ic芯片查詢 芯片型號查詢 ic型號查詢 未知打磨IC芯片型號鑒定IC芯片型號查詢單片機絲印反查詢方法! 我們在PCB抄板解密時經常會遇到IC芯片被打磨了沒有字,或者真實的型號被擦除並絲印上假的型號。這樣無法做出完整的電路板B

metasploit下Windows的多種提權方法

sys png 獲得 詳細信息 參考 leg hack 用法 spl metasploit下Windows的多種提權方法 前言 當你在愛害者的機器上執行一些操作時,發現有一些操作被拒絕執行,為了獲得受害機器的完全權限,你需要繞過限制,獲取本來沒有的一些權限,這些權限可以

VMware 上windows 系統密碼忘記修改方法

windows虛擬機密碼* 1.下載PE,ISO本版本的(帶密碼破解軟件) * 2.上傳PE ISO 至虛擬機服務器 * 3.關閉windows虛擬機 * 4.點擊編輯虛擬機設置 * 5.點擊硬件,點擊CD/DVD驅動器,勾選數據存儲ISO文件,點擊瀏覽選擇上傳的PE ISO文件 * 6.點擊選項,勾選強制執

Windows10中啟用原來的Windows照片查看器方法

eas txt文件 PE col pan 保存文件 str RR 垃圾 前言: ============================================== Windows10 版系統自帶很多垃圾應用,圖片查看器弄得很不好用,還是習慣Windows

3星|《數據的真相》:常見的數據誤導與誤導方法

內容 心理學 原因 體重 href eas 關聯 至少 蘋果手機 數據的真相:如何在數字時代做出明智決策 全書由許多小章節組成,每一小章節是一篇相對獨立的短文,講一種數據造成的誤解/誤導,和讀者的反誤解/反誤導方法。比如說看數據的話美國的副市長的平均工資高於市長的平均

Win10系統清理Windows Store緩存的方法

下回 朋友 是我 助手 51cto 管理員 www 運行 mar Win10系統的應用商店相比之前有了許多的更新,微軟也成立了專門的團隊準備對應用商店進行完善,但是我們在使用應用商店的過程中會產生許多緩存文件,占用電腦空間資源,也會影響電腦的運行速度。下面<A hre

在Linux下訪問Windows共享目錄的配置方法

admin 完全 linu all 計算 ifs amba 方法 linux 1、在Windows上設置一個共享目錄mailbak(設置用戶權限,用戶名和密碼這些)對該共享目錄有完全控制權限(讀、寫)2、在Linux下安裝samba-client客戶端# yum insta

SQLSERVER誤刪Windows登錄用戶驗證方式使用Windows身份驗證的解決方法

ros 命令 microsoft gif ride 給他 服務器 reat lan 今天看到這篇文章:沒有了SA密碼,無法Windows集成身份登錄,DBA怎麽辦? 想起來之前著急哥問我的一個問題,一個DBA刪除了Windows登錄用戶,而且SQLSERVER服務器的驗證

談談fastjson序列方法JSON.parseObject(String text, Class<T> clazz)--來源於生產實踐

名稱 種類 種類型 oba hashmap tde font 關註 內存 fastjson這一工具包幫助我們進行java對象和json格式的字符串之間的相互轉換。對象到字符串的過程,我們稱之為序列化;反之,我們稱為反序列化。 現在我們就來談談fastjson提供的反序列化方