日前遇到一件事:WebBrowser中的網頁會用到一個「大衆」ActiveX控件,爲了保證兼容性以及和其它程序互不干擾,咱們採用這樣一種方案:
1. 咱們的軟件會自帶該控件;
2. 若是系統中已註冊有該控件的話,咱們不用會咱們的控件進行覆蓋註冊;
3. 無論怎麼樣,咱們的程序都只會加載咱們自帶的控件。
要作到第3條,顯然要HOOK控件位置有關的註冊表項。由於以前在作播放器時使用過一樣的手段來處理媒體解碼器,因此其實並無什麼難度。但事實上卻差點陰溝裏翻船。
我必定肯定以及確定的是,我須要HOOK的只有幾個API:RegQueryValue、RegQueryValueEx、RegGetValue。用ZwQueryKey還原一下路徑,若是路徑是"CLSID\{GUID}\InprocServer32",把咱們自帶控件的路徑返回便可。
然而,程序實際運行卻並無預期效果,程序雖然執行到了API的替代函數中,可是結果卻要麼加載到其它版本的控件,要麼加載失敗。
修正了數遍代碼,把捕獲條件放寬收窄N次,嘗試HOOK其它一些API以後,換了N臺機器,檢查了N遍註冊表後,問題依舊。
跟蹤了無數遍,程序始終會執行到API的替代函數中,也返回了正確結果。可是在procemon的監測裏,卻又始終能看到返回註冊表中真實值的註冊表讀取操做。
我花了一些時間後,意識到:在API替代品中就已經被我處理掉的請求,應該是不會進入到Procemon紀錄中的。也就是說,procemon中監控到的請求,跟被我HOOK到的請求,實際上是來自徹底不一樣的調用路徑。可是查看procemon紀錄中這些操做的調用堆棧,無一不是來自已經被我HOOK了的API。
這說明了一個更加難以解釋的問題:一樣的API,一樣的參數(路徑),爲何有些可以HOOK到,有些則HOOK不到?
爲此又回過頭去檢查和修正捕獲操做的代碼,但毫無收穫。
最後告訴我答案的來自美工使用舊版本程序的一個錯誤報告:XP系統下提示Advapi32.dll找不到某註冊表API。我忽然想起,procemon紀錄中的調用堆棧中的API,彷佛並非Advapi32.dll模塊的,而是Kernel32.dll。立刻查詢了一下,確認程序連接的都是Advapi32.dll,而procemon中監控到的,也確認屬於Kernel32.dll。
答案呼之欲出,用depends看了一下Lernel32.dll,果真如此,如出一轍的API,一個很多!!!也就是說,我HOOK了advapi32.dll的API,但程序卻明修棧道,暗渡陳倉,調用了一兩次advapi32.dll中的API,最後卻從Kernel32.dll繞道去拿了數據。
雖然問題找到了,可是依然仍是不太明白。之前HOOK註冊表並無出現過相似問題,顯然,那些程序裏註冊表調用都走的是Advapi32.dll,MSDN中全部的註冊表API也都註明在Advapi32.dll裏,那爲何這一次卻到了Kernel32.dll,惟一能想到的解釋,或許這IE內核有關。但這一點就無力求證了。
最後,雖然沒有文檔告訴我Kernel32.dll中註冊表函數的原型,但嘗試用Advapi32.dll中的原型HOOK了一下,程序正常。可見是一個牌子,兩套班子。
Tip:RegGetValue要求Vista以上或XP64bit。