小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

使用 Windwos 鉤子獲取丟失的密碼

 Frank_Chia 2009-07-26

使用 Windwos 鉤子獲取丟失的密碼

作者:Brian Friesen
編譯:VCKBASE


原文出處:PasswordSpy - Retrieving lost passwords using Windows hooks

下載源代碼

關(guān)鍵字:鉤子 進(jìn)程間通訊 單實(shí)例 操作系統(tǒng)版本

簡(jiǎn)介

  幾年前我在CodeGuru 上下載了一個(gè)叫 Eureka的程序,如果你忘記了密碼,你可以用程序把密碼“取”回來。它不是密碼破解程序,相反,它利用了一個(gè)Windows的安全漏洞來拷貝另外一個(gè)運(yùn)行中的程序的密碼。我對(duì)這個(gè)程序很感興趣,決定寫一個(gè)自己的版本。后來,Windows 2000 發(fā)布,我失望地發(fā)現(xiàn),微軟修補(bǔ)了那個(gè)漏洞,這樣一來那個(gè)程序在Windows 2000上也就不靈了。經(jīng)過一番嘗試,我終于找到一個(gè)方法拷貝任何在32-位Windows 系統(tǒng)上運(yùn)行程序的密碼。

本文例子程序:

使用方法:

  PasswordSpy程序的使用非常簡(jiǎn)單。你只要運(yùn)行包含忘記了密碼的程序,再運(yùn)行PasswordSpy。然后將放大鏡拖動(dòng)到密碼輸入域上,PasswordSpy則會(huì)將密碼顯示出來。PasswordSpy程序并沒有惡意,開發(fā)它的目的只是想把密碼找回來,該程序在Win95/98/ME and WinNT/2K/XP/Windows 2003 上測(cè)試通過。

功能說明:

除了PasswordSpy本身的用途之外,它還示范了一些有用和有趣的代碼:

  • 單實(shí)例應(yīng)用——如果用戶啟動(dòng)了PasswordSpy的第二個(gè)實(shí)例,系統(tǒng)會(huì)找到第一個(gè)實(shí)例,并在所有窗口的最前端顯示出PasswordSpy界面;
  • Always on top——總是在最頂層,只用一行代碼就可以在你的程序中啟動(dòng)和禁用這個(gè)功能;
  • 進(jìn)程間通訊——PasswordSpy 使用幾種形式的IPC,包括WM_COPYDATA消息以及內(nèi)存映射文件;
  • 設(shè)置窗口鉤子——為了在Windows 2000/Windows XP中吸取密碼,你得使用在遠(yuǎn)程進(jìn)程中置入一個(gè)鉤子。

代碼實(shí)現(xiàn)細(xì)節(jié):

  到目前為止,PasswordSpy 程序最有趣的部分其實(shí)是使用 SetWindowsHookEx API.函數(shù)設(shè)置Windows 鉤子。利用該函數(shù)你可以將鉤子安裝到操作系統(tǒng)中或者某個(gè)特定的進(jìn)程中。鉤子的種類有很多種,每種鉤子作用也不盡相同,用來監(jiān)視特定的一組事件。當(dāng)某一類事件發(fā)生時(shí),鉤子代碼被調(diào)用。PasswordSpy使用WH_GETMESSAGE鉤子,它監(jiān)視對(duì)GetMessage 和PeekMessage 的調(diào)用。關(guān)于鉤子更詳細(xì)的信息請(qǐng)參考MSDN庫的SetWindowsHookEx。
  我在網(wǎng)上、書本以及MSDN上找到幾個(gè)有關(guān)鉤子的例子,每個(gè)都至少有一個(gè)Bug。本文我用自己的方案解決了這些問題。使用Windows鉤子最難的部分是妥善存儲(chǔ)鉤子句柄。設(shè)置鉤子之前,你需要做兩件事情:

  1. 包含鉤子函數(shù)的DLL;
  2. 鉤子要作用的線程ID;

  現(xiàn)在假設(shè)進(jìn)程A要在進(jìn)程B中設(shè)置鉤子。鉤子注入進(jìn)程B以后,該鉤子句柄被返回到進(jìn)程A,同時(shí)DLL被映射到進(jìn)程B的地址空間。當(dāng)進(jìn)程B中某個(gè)鉤子事件發(fā)生時(shí),你的鉤子代碼便在進(jìn)程B中被調(diào)用。(應(yīng)該注意的一點(diǎn)是你的鉤子代碼是從遠(yuǎn)程進(jìn)程空被調(diào)用的!鉤子代碼里,如果調(diào)用GetCurrentProcessId 函數(shù),那么獲得的是鉤子進(jìn)程的ID,而不是設(shè)置鉤子的進(jìn)程ID)。你可以在鉤子代碼中做任何想做的事情,但是在鉤子代碼退出之前,你應(yīng)該調(diào)用CallNextHookEx。如果這個(gè)函數(shù)調(diào)用失敗,其它任何已經(jīng)安裝的鉤子無法獲得消息。因?yàn)镃allNextHookEx需要該鉤子句柄,但我們當(dāng)前是在進(jìn)程B中,而句柄被返回到進(jìn)程A,因此,此時(shí)需要進(jìn)程間通訊來傳輸鉤子句柄。
通常解決這個(gè)問題的方法是通過在DLL中創(chuàng)建一個(gè)“共享”內(nèi)存區(qū):

#pragma data_seg("Shared")
            HHOOK g_hHook = NULL;
            #pragma data_seg()
            #pragma comment(linker, "/section:Shared,rws")
            
  其實(shí),此處創(chuàng)建了一個(gè)變量,所有已經(jīng)被加載的DLL實(shí)例共享這個(gè)變量。但這個(gè)方法有幾個(gè)問題,第一,有些編譯器不支持這個(gè)選項(xiàng),第二,如果微軟要是在未來的Windows中改變“共享”內(nèi)存區(qū)的工作模式該怎么辦?這意味著這個(gè)技術(shù)不再適用。此外,這個(gè)方法不是線程同步的,由于有多個(gè)線程要訪問這個(gè)變量,線程同步就變得很重要。為了解決這些問題,我在進(jìn)程間通訊(IPC)過程中使用了內(nèi)存映射文件,并利用互斥機(jī)制進(jìn)程線程同步。我將這方面的代碼全部封裝在一個(gè)類中,這個(gè)類就是 CIPC。通過使用內(nèi)存映射文件,我解決了特定編譯器選項(xiàng)問題,不用再考慮編譯器是否支持共享內(nèi)存區(qū);僅僅借助Win32 API調(diào)用以及用MMFs來提供多進(jìn)程間共享數(shù)據(jù)的機(jī)制就可以解決問題,在未來的Windows版本中,這些東西是不太可能改變的?;コ獗WC了線程存取的同步:
//***********************************************
            // IPC.h
            //***********************************************
            #ifndef _IPC_H_
            #define _IPC_H_
            #define IPC_SHARED_MMF  _T("{34F673E0-878F-11D5-B98A-00B0D07B8C7C}")
            #define IPC_MUTEX       _T("{34F673E1-878F-11D5-B98A-00B0D07B8C7C}")
            // 使用內(nèi)存映射文件進(jìn)行進(jìn)程間通訊的封裝類
            class CIPC
            {
            public:
            CIPC();
            virtual ~CIPC();
            bool CreateIPCMMF(void);
            bool OpenIPCMMF(void);
            void CloseIPCMMF(void);
            bool IsOpen(void) const {return (m_hFileMap != NULL);}
            bool ReadIPCMMF(LPBYTE pBuf, DWORD &dwBufSize);
            bool WriteIPCMMF(const LPBYTE pBuf,
            const DWORD dwBufSize);
            bool Lock(void);
            void Unlock(void);
            protected:
            HANDLE m_hFileMap;
            HANDLE m_hMutex;
            };
            #endif
            //***********************************************
            // IPC.cpp
            //***********************************************
            #include "IPC.h"
            //***********************************************
            CIPC::CIPC() : m_hFileMap(NULL), m_hMutex(NULL)
            {
            }
            //***********************************************
            CIPC::~CIPC()
            {
            CloseIPCMMF();
            Unlock();
            }
            //***********************************************
            bool CIPC::CreateIPCMMF(void)
            {
            bool bCreated = false;
            try
            {
            if(m_hFileMap != NULL)
            return false;    // Already created
            // Create an in-memory 4KB memory mapped
            // file to share data
            m_hFileMap = CreateFileMapping((HANDLE)0xFFFFFFFF,
            NULL,
            PAGE_READWRITE,
            0,
            4096,
            IPC_SHARED_MMF);
            if(m_hFileMap != NULL)
            bCreated = true;
            }
            catch(...) {}
            return bCreated;
            }
            //***********************************************
            bool CIPC::OpenIPCMMF(void)
            {
            bool bOpened = false;
            try
            {
            if(m_hFileMap != NULL)
            return true;    // Already opened
            m_hFileMap =
            OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE,
            FALSE,
            IPC_SHARED_MMF);
            if(m_hFileMap != NULL)
            bOpened = true;
            }
            catch(...) {}
            return bOpened;
            }
            //***********************************************
            void CIPC::CloseIPCMMF(void)
            {
            try
            {
            if(m_hFileMap != NULL)
            CloseHandle(m_hFileMap), m_hFileMap = NULL;
            }
            catch(...) {}
            }
            //***********************************************
            bool CIPC::ReadIPCMMF(LPBYTE pBuf, DWORD &dwBufSize)
            {
            _ASSERTE(pBuf);
            bool bSuccess = true;
            try
            {
            if(m_hFileMap == NULL)
            return false;
            DWORD dwBaseMMF = (DWORD)MapViewOfFile(m_hFileMap,
            FILE_MAP_READ | FILE_MAP_WRITE,
            0, 0, 0);
            _ASSERTE(dwBaseMMF);
            // The first DWORD in the MMF contains the size of the data
            DWORD dwSizeofInBuf = dwBufSize;
            CopyMemory(&dwBufSize, (LPVOID)dwBaseMMF, sizeof(DWORD));
            if(dwSizeofInBuf != 0)
            {
            if(dwBufSize > dwSizeofInBuf)
            bSuccess = false;
            else
            CopyMemory(pBuf,
            (LPVOID)(dwBaseMMF + sizeof(DWORD)),
            dwBufSize);
            }
            UnmapViewOfFile((LPVOID)dwBaseMMF);
            }
            catch(...) {}
            return bSuccess;
            }
            //***********************************************
            bool CIPC::WriteIPCMMF(const LPBYTE pBuf, const DWORD dwBufSize)
            {
            _ASSERTE(pBuf);
            bool bSuccess = true;
            try
            {
            if(m_hFileMap == NULL)
            return false;
            DWORD dwBaseMMF = (DWORD)MapViewOfFile(m_hFileMap,
            FILE_MAP_READ | FILE_MAP_WRITE,
            0, 0, 0);
            _ASSERTE(dwBaseMMF);
            // The first DWORD in the MMF contains the size of the data
            CopyMemory((LPVOID)dwBaseMMF, &dwBufSize, sizeof(DWORD));
            CopyMemory((LPVOID)(dwBaseMMF + sizeof(DWORD)),
            pBuf,
            dwBufSize);
            UnmapViewOfFile((LPVOID)dwBaseMMF);
            }
            catch(...) {}
            return bSuccess;
            }
            //***********************************************
            bool CIPC::Lock(void)
            {
            bool bLocked = false;
            try
            {
            // First get the handle to the mutex
            m_hMutex = CreateMutex(NULL, FALSE, IPC_MUTEX);
            if(m_hMutex != NULL)
            {
            // Wait to get the lock on the mutex
            if(WaitForSingleObject(m_hMutex, INFINITE) ==
            WAIT_OBJECT_0)
            bLocked = true;
            }
            }
            catch(...) {}
            return bLocked;
            }
            //***********************************************
            void CIPC::Unlock(void)
            {
            try
            {
            if(m_hMutex != NULL)
            {
            ReleaseMutex(m_hMutex);
            CloseHandle(m_hMutex);
            m_hMutex = NULL;
            }
            }
            catch(...) {}
            }
            
PasswordSpy的反向工程

  上述內(nèi)容是關(guān)于通過編程途徑從其它程序“拷貝”密碼,下面的內(nèi)容我們將討論:如何防止PasswordSpy這樣的程序從你的程序中獲取密碼信息?如果你的應(yīng)用程序存儲(chǔ)并顯示密碼,你有特別關(guān)注安全問題,你可能會(huì)考慮讓應(yīng)用堤防類似PasswordSpy這樣的程序。
  因?yàn)镻asswordSpy可以拷貝其它程序的密碼,為了防范這樣的程序,你首先就決不能將真正的密碼信息顯示出來。最佳辦法是在密碼框中顯示假密碼。這樣一來,如果有人使用PasswordSpy 獲取密碼,那他們得到的是一個(gè)假密碼。本文附帶的程序AntiPwdSpy示范了如何保護(hù)密碼框控件免遭“偵測(cè)”。AntiPwdSpy實(shí)際上類似于Windows NT服務(wù)對(duì)話框和Windows NT 用戶管理程序。
  防范諸如PasswordSpy這類程序的其它方法還可以通過截獲WM_GETTEXT消息來實(shí)現(xiàn)。但使用虛假密碼的方法有額外的好處,用假密碼替代真密碼,僅檢查密碼控件是無法確定密碼的長(zhǎng)度的。如果某個(gè)程序顯示密碼控件中的文本“***”,那么就可以知道密碼是三位長(zhǎng)度。這樣的信息肯定危及密碼的安全。但是,如果將密碼控件中的信息顯示成“**************”便可以有效地保護(hù)密碼,微軟的很多程序產(chǎn)品就是這么做的。

參考資料


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多