動態連線庫注入到其他程序中的一種新方法

2021-04-01 02:05:55 字數 2497 閱讀 3030

我們知道將動態連線庫注入到其他程序中有很多種方法。最常見的方法是使用鉤子函式(hook),但是這種方法主要有兩個缺點:第一如果某個程序沒有載入user32.dll,那麼hook dll將永遠也不會被載入。第二hook dll載入的時機問題,只有在程序發出user32呼叫的時候, hook dll才有可能被載入。也就是說假設程序正在進行複雜的數值計算而沒有時間進行訊息呼叫的時候,hook dll是不會被載入。理論上我們沒有精確的辦法來確定我們的hook dll是否已經注入到我們想要的程序中。另外一種最常見的方法是使用函式createremotethread,在其他程序中開啟乙個執行緒來裝載dll。應該說這是一種比較完美的解決放案,這種方法避免了上述使用鉤子函式的所有缺點,但是遺憾的是這個函式只能使用在winnt/2000下。

本文將討論一種將動態連線庫注入到其他程序中的一種新方法。它的思路與使用函式createremotethread的方法相類似,只不過可以使用在win9x,win2k,winxp等作業系統下。在這裡我們將向讀者演示我們是如何將dll(injectdll.dll)注入到explorer.exe程序中!

程式的思路如下

1:得到explorer.exe程序中任意乙個執行緒的id.

2:根據這個執行緒的id,得到這個執行緒的控制代碼handle

3:掛起這個執行緒,並儲存執行緒當前的「上下文」

4:改變這個執行緒的eip指標,使它指向我們裝載dll的函式(injectcodefun),然後恢復這個執行緒。

5:我們的裝載dll的函式執行完成後,再次掛起這個執行緒,使用我們以前儲存的「上下文」,恢復這個執行緒到它被改變前的狀態,並繼續執行。

經過上述幾個步驟,explorer.exe程序中就會替我們裝載我們的dll(injectdll.dll)了,有趣的是explorer.exe對此絲毫沒有察覺任何異常 !

下面我們將詳細解釋一下如何程式設計實現上述過程。

步驟1的實現是很容易的,我們只需要呼叫toolhelp的函式就可以得到我們所要得,這裡我們就不詳細說明了,請參考源**中getprocessid, getthreadid 兩個函式。

步驟2就比較麻煩了,在win9x中沒有提供乙個函式可以由thread id得到thread handle(幸運的是win2k提供這種功能)。好在我們在國外一些bbs上可以找到這個函式,它使用了一些未公開的結構,本文的目的不是討論這個問題,讀者如果有興趣的話,可以參考我們的源**openthread2函式。這個函式的作用就是傳入乙個thread id引數返回相應的 thread handle。

步驟3 的實現也是很容易和規範的,我們可以用suspendthread,getthreadcontext等sdk函式輕鬆完成。

步驟4 這個步驟是最重要的步驟了。為了說明方便,我們將引用我們源**中的語句,請讀者參考源**中injectcodeintothread 函式。

首先改變執行緒的eip指標,我們可以用下列**完成

threadcontext.eip = (dword)m_lpcodebase;

setthreadcontext(m_hinjectthread,&threadcontext);

變數m_lpcodebase指向我們的裝載dll的函式(injectcodefun)的首位址。

在我們寫的裝載dll函式(injectcodefun)中還有兩個問題我們需要解釋一下,第一 在這個函式中我們不能使用任何我們自己程式中定義的變數,道理跟上面講的一樣,因為位址空間不同。還有我們不能直接呼叫函式,例如在injectcodefun中直接使用loadlibray。這是因為如果直接使用loadlibray那麼就需要經過程式的import表,跳轉一下才能到達真正的windows的loadlibray函式。但是不同的程序有不同的import,所以我們不能直接呼叫函式。我們可以使用一種叫做「動態建構函式」的技術來建立我們的函式。首先用getprocaddress得到函式loadlibray的直接位址,然後在呼叫loadlibray的地方,使用乙個特殊的數字來代替它如 0x11111111,最後在將我們的函式拷貝到共享位址空間之後,搜尋共享記憶體找到這個特殊數字,用我們先前得到的正確位址替換它既可。第二個有趣的現象是我們所寫的裝載dll函式(injectcodefun)是不應該返回的。這是因為這個函式是在explorer的執行緒中執行的,我們不知道堆疊的正確內容,不知道esp所指向的位址是什麼,如果函式返回的話,我們將失去對程式的控制。我們的辦法是,當呼叫完loadlibray之後,向我們的主程式傳送乙個自定義訊息,通告我們的程式已經完成裝載任務,然後讓執行緒進入死迴圈狀態。

步驟5當我們的程式接受到了自定義訊息後,就會再次掛起這個執行緒,把我們以前儲存的執行緒的「上下文」用函式setthreadcontext恢復,然後恢復執行這個執行緒。結果是explorer.exe絲毫沒有感覺到自己被中斷過。

以上就是我們所介紹的方法,讀者可以參考我們的源**來具體了解上述方法。源**的功能是將我們的dll(injectdll.dll)注入到explorer.exe 中,在injectdll.dll中我們建立了乙個新的執行緒,然後在螢幕的左上角顯示當前的時間。源**分為win9x版本和win2k版本,這兩個版本的主要差別是分配共享記憶體的方法不同而已。源**已經在pwn98,pwinme,win2k,winxp等作業系統下,使用vc6編譯通過。

vs 中呼叫QT的動態連線庫

1 建立乙個 qt c 的動態連線庫 2 在標頭檔案中宣告要匯出的介面 ifndef qtdlltest h define qtdlltest hextern c declspec dllexport void init endif qtdlltest h 3 在cpp檔案中對介面進行實現 void...

將LAPACK靜態庫編譯到自己的動態庫中

最近用lapack庫中的函式來實現一些矩陣求逆和擬合的演算法,為了不引入第三方庫,就想著將lapack庫編進自己的庫中。在網上搜了很多,發現這個指令可以解決問題 wl,whole archive 靜態庫全稱 wl,no whole archive 所以我的鏈結方式示例如下 cflags fpic l...

通過反射呼叫動態連線庫中的方法

description 通過dll路徑,實現動態呼叫動態鏈結庫中指定類的 靜態 方法和屬性 public class dynamicreflectdll marshalbyrefobject endregion region 反射函式 public dynamicreflectdll string ...