基於HOOK和MMF的Windows密碼滲透技術

來源:互聯網
上載者:User
摘 要 隨著電腦與網路的普及,資訊安全越來越成為人們所普遍關心的大事。密碼的滲透與反滲透在此領域表現的愈演愈烈。本文深入分析了各個版本windows密碼的特點,尤其是針對windws2K/XP安全性提高的情況下,提出了擷取windows密碼的關鍵技術及方法。並進一步分析了windows鉤子(Hook)和記憶體映像檔案(MMF)的技術細節。在基於MMF的核心類CIPC中為鉤子控制代碼在記憶體中的共用提供了方法,並且解決了線程間的同步問題。然後深入討論了WM_COPYDATA訊息的特點。接著分析了執行個體程式重要代碼及註解並示範了結果。最終給出一些反密碼滲透的應對策略。

  關鍵詞 記憶體映像檔案;windows鉤子;處理序間通訊;多線程

  1、引言

  上世紀90年紀使用過windows3.x的人可能很少有人瞭解這類作業系統中存在著密碼保護的漏洞,如果選擇密碼控制項中的“****”文本然後複製到剪貼簿上,那麼看到的將不是“****”而是密碼的原始文本。微軟發現了windows3.x這個問題並在新的版本window95中修改了這個漏洞。但是windows95存在著新的安全性漏洞,可以設計出間諜程式從當前啟動並執行程式中得到密碼控制項中的密碼,這些間諜程式並非是如同softice一樣的破解程式。然而,微軟在window2000中又修補了這個問題,如何通過MMF與HOOK技術擷取任何版本windows 密碼控制項的內容,這正是本文討論的重點問題。

  圖1 Windows 2K/XP密碼校正

  擷取Windows密碼技術主要是利用了windows的安全性漏洞。在windows NT/95/98/ME等作業系統下,如果在間諜程式中發送WM_GETTEXT訊息到密碼控制項,返回的文本將不再是“****”而是實際的常值內容,而在windows2K/XP系統中微軟加了安全控制,如果發送WM_GETTEXT到密碼控制項,系統將校正請求的進程判斷該進程是否有許可權,1所示:如果請求進程與密碼控制項所在進程是同一進程,那麼WM_GETTEXT訊息將仍舊返回密碼的真實文本。如果兩個進程不一樣,就返回一個ERROR_ACCESS_DENIED的錯誤。所以擷取windows2K/XP密碼的關鍵技術在於:從密碼控制項所在的進程中擷取WM_GETTEXT訊息,而不是在滲透進程中得到。而這種在其它進程中運行使用者代碼的技術完全可以利用windows 鉤子(hook)技術來實現。首先我們需要瞭解一下什麼是鉤子。

  2、Windows鉤子

  Windows系統是建立在事件驅動的機制上的,即整個系統都是通過訊息的傳遞來實現的。鉤子(hook)是一種特殊的訊息處理機制,鉤子可以監視系統或進程中的各種事件訊息,截獲發往目標視窗的訊息並進行處理。這樣,我們就可以在系統中安裝自訂的鉤子,監視系統中特定事件的發生,完成特定的功能,比如截獲鍵盤、滑鼠的輸入,螢幕取詞,日誌監視等等。鉤子的種類很多,每種鉤子可以截獲並處理相應的訊息,如鍵盤鉤子可以截獲鍵盤訊息,外殼鉤子可以截取、啟動和關閉應用程式的訊息等。2是一全域鉤子。

  在執行個體程式中運用WH_GETMESSAGE鉤子,這個鉤子監視投遞到訊息佇列中的Windows訊息。

  圖2 全域鉤子的原理圖

  3、Windows鉤子在此處的應用

  安裝鉤子的函數為SetWindowsHookEx,利用這個函數可以為整個系統或為某一特定進程安裝鉤子,不同的鉤子監視特定鉤子事件的發生,當某一事件觸發後,與之對應的代碼就會被系統調用。

  運用windows鉤子的一個痛點是如何妥善儲存鉤子的控制代碼。在設定鉤子前需要解決兩件事:

  1) 一個包括了鉤子函數的動態連結程式庫;

  2) 要注入鉤子的進程ID。

  現在假設進程A為進程B注入了一個鉤子。鉤子注入後,鉤子的控制代碼返回給了進程A並且動態連結程式庫映射到了進程B的地址空間。當進程B中觸發了一個鉤子事件,鉤子代碼被進程B調用(需要特別指出的是,鉤子代碼被一個遠程進程所調用,被調用的鉤子代碼中如果調用GetCurrentProcessId這個函數,得到的是被注入了鉤子進程的進程ID,而不是注入進程)。在鉤子代碼中通過發訊息擷取密碼真實文本,在鉤子代碼結束前需調用CallNextHookEx函數,如果這個函數調用失敗,安裝的其它鉤子將得不到訊息。現在出現的問題是CallNextHookEx需要一個鉤子的控制代碼,但那個所需的控制代碼已返回給了進程A而鉤子程式目前運行在進程B的程式碼片段內。這樣就需要用到處理序間通訊IPC(Inter Process Communication)來傳遞鉤子控制代碼。

  4、處理序間通訊的一般方法

  解決以上問題的一般方法是在動態連結程式庫中建立一個“共用”部分,寫入如下代碼:

#pragma data_seg(“Shared”)
HHOOK g_hHook = NULL;
#pragma data_seg()
#pragma comment(linker, “/section:Shared,rws”)

  簡單地說這幾行代碼建立了一個共用的變數,如果5個進程載入這個動態連結程式庫,5個進程都有訪問的許可權。但這個方法有一些問題:一是一些編譯器可能並不支援這種方法。二是如果未來的windows版本發生了改變,這種方法就行不通。三是這個方法沒有規定線程同步,如果有多線程訪問這個變數,線程同步是非常重要的,沒有線程間的同步可能會觸發諸如衝突等一些問題。解決這個問題的方法是利用記憶體映像檔案(MMF)。

  5、記憶體映像檔案(MMF)

  在WIN32中,通過使用映像檔案在進程間實現共用檔案或記憶體共用,如果利用相同的映像名字或檔案控制代碼,則不同的進程可以通過一個指標來讀寫同一個檔案或者同一記憶體資料區塊,並把他們當成該進程記憶體空間的一部分。記憶體映像檔案可以映射一個檔案、一個檔案中的指定地區或者指定的記憶體塊,其中的資料就可以用記憶體讀取指令來直接存取,而不用頻繁的使用操作檔案的I/O系統函數,從而提高檔案的存取速度和效率。

  映像檔案的另一個重要作用就是用來支援永久命名的共用記憶體。要在兩個應用程式之間共用記憶體,可以在一個應用程式中建立一個檔案並映射,然後另外一個程式通過開啟和映射此檔案,並把它當作自己進程的記憶體來使用。

  6、建立基於MMF的類CIPC

  運用記憶體映像檔案解決處理序間通訊問題,並且建立一個互斥變數來解決線程的同步問題。所有這些封裝在一個CIPC的類中。通過運用記憶體映像檔案解決了不同編譯器的相容問題,因為使用的都是標準Win32 API。加上MMF支援進程間的資料共用,在未來的windows版本中微軟不會改變MMF的定義及方法。並且互斥變數保持了線程訪問的同步。以下給出CIPC的類定義。

class CIPC
{
 public:
  CIPC();
  virtual ~CIPC();
  bool CreateIPCMMF(void);//建立一個處理序間通訊的MMF
  bool OpenIPCMMF(void);//開啟一個處理序間通訊的MMF
  void CloseIPCMMF(void);//關閉一個處理序間通訊的MMF
  bool IsOpen(void) const {return (m_hFileMap != NULL);}//判斷MMF是否開啟
  bool ReadIPCMMF(LPBYTE pBuf, DWORD &dwBufSize);//讀MMF
  bool WriteIPCMMF(const LPBYTE pBuf, const DWORD dwBufSize);//寫MMF
  bool Lock(void);//進入臨界區,建立互斥訊號量
  void Unlock(void);//退出臨界區,撤消互斥訊號量
 protected:
  HANDLE m_hFileMap;//MMF檔案控制代碼
  HANDLE m_hMutex;//互斥變數控制代碼
};

  7、利用WM_COPYDATA訊息來解決進程間的通訊

  在解決進程間的通訊問題方面,WM_COPYDATA訊息是一個非常好的工具,可以節省程式員的許多時間。

  當記憶體映像檔案被建立時,系統就發送訊息來填充它。然後系統再轉回到最初調用SendMessage的進程,從共用記憶體映像檔案中將資料複製到所指定的緩衝區中,然後從SendMessage調用返回。

  對於系統已經知道的訊息,發送訊息時都可以按相應的方式來處理。如果要建立自己的(WM_USER+x)訊息,並從一個進程向另一個進程的視窗發送,那又會怎麼樣?系統並不知道使用者要用記憶體映像檔案並在發送訊息時改變指標。為此,微軟建立了一個特殊的視窗訊息, WM_COPYDATA以解決這個問題:

COPYDATASTRUCT cds;
SendMessage(hwndReceiver,WM_COPYDATA,(WPARAM)hwndSender,(LPARAM)&cds);
COPYDATASTRUCT是一個結構,定義在winuser.h檔案中,形式如下面的樣子:
Typedef struct tagCOPYDATASTRUCT{
 ULONG_PTR dwData;
 DWORD cbData;
 PVOID lpData;
}COPYDATASTRUCT;

  當一個進程要向另一個進程的視窗發送一些資料時,必須先初始化COPYDATASTRUCT結構。資料成員dwData是一個備用的資料項目,可以存放任何值。例如,使用者有可能向另外的進程發送不同類型或不同類別的資料。可以用這個資料來指出要發送資料的內容。cbData資料成員規定了向另外的進程發送的位元組數,lpData資料成員指向要發送的第一個位元組。lpData所指向的地址,當然在發送進程的地址空間中。

  當SendMessage看到要發送一個WM_COPYDATA訊息時,它建立一個記憶體映像檔案,大小是cbData位元組,並從發送進程的地址空間中向這個記憶體映像檔案中複製資料。然後再向目的視窗發送訊息。在接收訊息的視窗過程處理這個訊息時,lParam參數指向已在接收進程地址空間的一個COPYDATASTRUCT結構。這個結構的lpData成員指向接收進程地址空間中的共用記憶體映像檔案的視圖。

 

8、關於WM_COPYDATA訊息,應該注意三個重要問題

  1)只能發送這個訊息,不能登記這個訊息。不能登記一個WM_COPYDATA訊息,因為在接收訊息的視窗過程處理完訊息之後,系統必須釋放記憶體映像檔案。如果登記這個訊息,系統不知道這個訊息何時被處理,所以也不能釋放複製的記憶體塊。

  2)系統從另外的進程的地址空間中複製資料要花費一些時間。所以不應該讓發送程式中啟動並執行其他線程修改這個記憶體塊,直到SendMessage調用返回。

  3)利用WM_COPYDATA訊息,可以實現1 6位和3 2位之間的通訊。它也能實現3 2位與6 4位之間的通訊。這是使新程式同舊程式交流的便捷方法。

  9、重要代碼及註解

  9.1鉤子函數void ExtractPassword(const HWND hWnd, const HWND hPwdSpyWnd),該函數是擷取密碼的主要函數

TCHAR szBuffer[256] = {_T('/0')};//分配一個緩衝區
SendMessage(hWnd,WM_GETTEXT,//向注入鉤子進程發訊息獲得密碼文本
sizeof(szBuffer)/sizeof(TCHAR), (LPARAM)szBuffer);//儲存在緩衝區中
COPYDATASTRUCT cds = {0};//定義一個cds結構體
cds.dwData = (DWORD)hWnd;//dwData儲存該進程控制代碼
cds.cbData = (lstrlen(szBuffer) + 1) * sizeof (TCHAR); //cbData儲存資料長度
cds.lpData = szBuffer;//lpData指向緩衝首地址
SendMessage(hPwdSpyWnd,WM_COPYDATA,
 (WPARAM)hWnd, (LPARAM)&cds);//利用WM_COPY DATA訊息給擷取密碼進程發送密碼

  9.2鉤子過程LRESULT WINAPI GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam),該過程主要完成從記憶體映像檔案中讀出儲存的鉤子控制代碼。

if(g_hHook == NULL)
{
 //從共用資源中讀資料,最終擷取鉤子控制代碼
 DWORD dwData = 0, dwSize = sizeof (DWORD);
 g_obIPC.Lock();//g_obIPC為CIPC對象,進入線程的同步
 g_obIPC.OpenIPCMMF();//開啟MMF檔案
 g_obIPC.ReadIPCMMF((LPBYTE)&dwData, dwSize);//讀資料給dwData
 g_obIPC.Unlock();//取消線程同步,退出臨界區
 g_hHook = (HHOOK)dwData;//將讀到的資料賦值給鉤子控制代碼,本文的關鍵所在
}

if(nCode >= 0)//忽略小於0的值
{
 HWND hWnd = NULL; //密碼控制項所在的視窗控制代碼
 HWND hPwdSpyWnd = NULL;//擷取密碼進程的視窗控制代碼
 MSG *pMsg = (MSG*)lParam;
 if(pMsg->message == g_wmScanPassword)//是否我們登記的訊息
 {
  hWnd = (HWND)pMsg->wParam;
  hPwdSpyWnd = (HWND)pMsg->lParam;
  ExtractPassword(hWnd, hPwdSpyWnd); //通過發送訊息得到密碼
 }
}

return CallNextHookEx(g_hHook, nCode, wParam, lParam);//返回下一鉤子過程

  10、示範介面

  3所示:執行個體是MFC下基於對話方塊的工程。在window XP下,拖動圖片控制項放大鏡來檢索密碼控制項中的密碼。下面的文字框顯示一些相關的視窗資訊以及密碼文本。

  11、反密碼滲透應對策略

  通過以上介紹的原理、方法及實現我們瞭解了如何得到windows系列密碼的方法,一個邏輯的問題是如何防止別人利用這樣的間諜程式複製我們的密碼?例如我們上網時如果被這樣的鉤子程式入侵,怎麼才能保護密碼的安全。首選的解決方案是欺騙間諜程式,在使用者程式中不要顯示真實的密碼,最好是在密碼控制項中顯示一條虛假的密碼。這樣如果有人用以上的程式來擷取密碼,那他得到的是虛假的密碼而不是真實密碼。

  當然還有其它的應對策略,一種可行的方法是攔截WM_GETTEXT。但用虛假密碼還有其它的好處,通過利用虛假密碼代替真密碼,那麼看到的密碼控制項上***長度就不能判斷密碼到底有多長。如果一個程式在其密碼控制項中顯示了“***”的文本,我們立即知道密碼只有三個字元的長度,密碼的安全性大大降低。但如果通過一些密碼編譯演算法將密碼控制項的顯示變為一長串的“*”,這種方法常見於微軟的密碼保護策略。那麼密碼攻擊者將無從下手。

  12、小結

  本文以評論windows系列的密碼特點為起點,主要針對2k/XP下的密碼滲透進行了分析。通過在進程內注入windows鉤子以及利用記憶體映像檔案安全傳遞鉤子控制代碼等技術,找出一條擷取2K/XP中密碼的途徑。但不可否認這都是建立在利用windows安全性漏洞的基礎之上的。為了彌補這些安全性漏洞,本文在最後也提出一些設想供讀者參考。當然只是在技術上解決一些問題是不夠的,關鍵還是人的因素,加強保密觀念對於密碼的保護起到了至關重要的作用。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.