引子
前些日子由于項目要求,在網上到處找資料,于無意中發現了 CodeProject 上的一篇很老的文章,文章标題為:
Three Ways to Inject Your Code into Another Process
這篇文章呢,出來很久咯,還是 03 年的文章了,可惜我弄底層弄得時間不久哦,不然應該早就看過這篇大作了,
由于是大作,而且出來的又久了,自然在網上也就到處流傳咯,
是以也有人将這篇文章翻譯成了中文版的,下面給出這篇大作的兩個連結:
然後呢,這邊由于老大給弄了蠻多好書過來了,其中一本就是所謂的駭客之類的東西,
雖然是繁體的,但是知識點都很不錯哦,是以也拿過來看了看,就發現其中對這個遠端線程的注入有很多的介紹,
而且貌似前些年的很多病毒或者木馬就是通過這屁東西來隐藏的,
看着看着就來勁了,而後呢,自己就根據書中的思路,
然後再結合自己的了解,将了解整理出了代碼,然後就出了這篇文章咯 !
然後注意一點的是,在 CodeProject 上的那篇文章中介紹了三種注入代碼技術,
第一種就是衆所周知的 Hook 了;
第二種是直接将所要執行的代碼全部拷貝到宿主程序中,即代碼遠端注入技術;
第三種則是 DLL 的遠端注入技術了,其通過在宿主程序加載自己寫的另外的一個 DLL 來實作注入;
然後在我的這篇博文中,我也隻是總結前人的思想,然後再加入我自己的立即,
同時由于 Hook 太常見了,常見得不行了,是以我并不會介紹 Hook 了,而隻介紹後面的兩種方式。
代碼遠端注入技術
Demo 的效果:
建立的項目為 RemoteThreadCode,即遠端注入代碼,其實作的功能是當運作 RemoteThreadCode.exe 時,
會在 Explorer.exe 程序中建立一個線程,而這個建立的線程功能實作很簡單,
就是彈出一個消息框即 OK !
Demo 的效果展示:
當輕按兩下執行 RemoteThreadCode.exe 時,則會注入一個線程到 Explorer.exe 中

當點選确定後,注入到 Explorer.exe 中的線程執行完畢,進而 WaitForSingleObject 等待成功 !
基本思路以及所對應的代碼:
1. 提升程序權限,如果權限不夠的話,很容易造成 OpenProcess 失敗;
2. 确定你的宿主程序,即你所要注入代碼的程序,這個其實很好辦,你要是不想你的木馬或者病毒被别個一下子就結束了的話,
最好是選擇系統要想運作,則必須開啟的那種程序,比如資料總管程序 Explorer.exe,
Windows 子系統程序 csrss.exe 等等,但是這裡注意的是,我注入 System 程序的時候造成了失敗哦,
是以最好還是别拿 System 做實驗,而且如果你注入失敗了的話,是會造成宿主程序崩潰的,
等下一不小心把 System 程序給弄崩潰了就不好了;
3. 打開宿主程序了(我這裡打開的是 Explorer.exe 程序),思路是首先變量目前系統下運作的所有的程序,
然後周遊擷取到得所有的程序的 PID,再調用 ProcessIsExplorer 函數來判斷這個程序是否為 Explorer.exe 程序,
如果是則記錄下這個程序的 PID 就可以了,這樣就獲得了 Explorer.exe 程序的 PID 了,
再通過 OpenProcess 來打開這個 Explorer.exe 程序就 OK 了;
4. 在宿主程序中配置設定好存儲空間,這個存儲空間是用來存放我們将要建立的遠端線程的線程處理例程的,
這裡需要注意的是:我們配置設定的記憶體必須标記必須帶有 EXECUTE,因為配置設定的這塊記憶體是用來存放線程處理例程的,
而線程處理例程必須得執行,是以必須得帶有 EXECUTE 标記,而至于 WRITE 标記的話,很明顯是需要的,
因為我們在後面的代碼中還必須調用 WriteProcessMemory 來将線程處理例程寫入到這塊記憶體中,自然其必須可寫;
5. 将遠端線程處理例程寫入到 4 中在宿主程序中所配置設定的記憶體中,這個可以直接調用 WriteProcessMemory 來實作;
6. 在宿主程序中配置設定好存儲空間,這個存儲空間是用來存放我們将要傳遞給遠端線程線程處理例程的參數,
從下面的結構體中可以看出,其由三個參數組成,第一個參數代表要在對話框中顯示的内容,
第二個參數代表要在對話框中顯示的标題,第三個參數則是 MessageBox 這個 API 的位址,
因為在 Explorer.exe 中 MessageBox 的位址會發生重定向,是以需要将其位址通過參數傳遞給線程處理例程;
7. 将參數寫入到 6 中在宿主程序中所配置設定的記憶體中,同樣是調用 WriteProcessMemory 來完成;
8. 調用 CreateRemoteThread 在 Explorer.exe(宿主程序)中建立遠端線程;
注意,當遠端線程沒有執行完時,不能夠通過 VirtualFreeEx 來将遠端程序中的記憶體釋放掉,
你想啊,我他媽的線程都還在 Explorer.exe 裡面執行,你他媽的在外面把我占的記憶體給釋放掉了,我還執行個屁啊 !
是以這裡調用了 WaitForSingleObject 來等待這個遠端線程執行完畢,
其執行完畢後再釋放在 Explorer.exe 中所配置設定的存儲空間 !
9. 編寫好遠端線程的線程處理例程即可;
DLL 遠端注入技術
建立的項目為 RemoteThreadDll,即遠端注入 DLL,其實作的功能是當運作 RemoteThreadDll.exe 時,
會在 Explorer.exe 程序中建立一個線程,而這個建立的線程功能實作則相對于上面的遠端注入代碼來說複雜一點,
線上程的處理例程中,首先是由線程參數傳遞過來的 LoadLibrary 的位址
和 GetProcAddress 的位址來找到 LoadLibrary 和 GetProcAddress API,
然後再通過 LoadLibrary(“MyDllName”) 來加載到我自己的 DLL,
然後再通過 GetProcAddress 在這個 DLL 中找到我的 DLL 所公開的函數,
再就是調用這個公開的函數了,我建立的 DLL 項目為 – ZacharyDll.dll,
該 DLL 中導出了兩個函數,一個函數用來彈出一個對話框,一個函數則是用來列印出調試資訊;
當輕按兩下執行 RemoteThreadCode.exe 時,則會注入一個線程到 Explorer.exe 中,
而後注入的這個線程就會調用我自己的 ZacharyDll.dll,
再調用 ZacharyDll.dll 中導出的兩個函數了,一個輸出調試資訊,一個彈出對話框:
這一部分的代碼同上面的遠端注入代碼是一樣的;
從下面的結構體中可以看出,其由六個參數組成,
第一個參數代表 ZacharyDll.dll 中導出的 PrintMessageBox 的名稱,
第二個參數代表 ZacharyDll.dll 中導出的 PrintDbgStr 的名稱題,
第三個參數則是 ZacharyDll.dll 所在的路徑,
第四個參數則是代表 LoadLibrary 的位址,
第五個參數代表 FreeLibrary 的位址,
第六個參數代表 GetProcAddress 的位址;
這一部分的代碼同上面的遠端注入代碼是類似的;
10. 編寫好要注入的 DLL – ZacharyDll.dll;
兩種注入技術的優點和缺點總結
使用代碼遠端注入技術的話,其相對于使用 DLL 遠端注入技術來說,
有一個優點,就是其不會無緣無故的讓宿主程序加載其他的 DLL,
為什麼說這是一個優點 ? 那是因為很多的監控軟體或者殺軟都在實時監控着每個程序,
當一個程序中加載了其他的 DLL 時(加載 DLL 的動作相對來說是比較大的)很容易被發覺,
而且當一個 DLL 被加載到程序中以後,可以利用很多的工具,
比如 Process Explorer 之類的将該程序所加載的 DLL 枚舉出來,這樣你所注入的 DLL 也就暴露無遺了 !
而如果你使用的是代碼注入,那相對來說會安靜很多(畢竟是小動作),而且也不會讓宿主程序加載其他的 DLL,
是以相對來說,其成功的可能性會更高,但是使用代碼遠端注入有一個緻命的弱點,
那就是你所注入的代碼中所使用的 API 都必須要重定向,
而且如果是自定義的函數的話,則必須将這個函數也全部拷貝到宿主程序中,
注入的代碼中所使用的全局變量以及所使用的字元串都必須重新拷貝到宿主程序中,
聽起來貌似沒什麼,但是事實上,這屁東西會搞得很複雜,就比如你在注入的代碼中所使用的一個字元串,
你也必須先在宿主程序中配置設定虛拟記憶體,然後将這個字元串寫入到這個新配置設定的虛拟記憶體中,
如果你字元串多的話,這樣的操作會煩死人去,而且這還僅僅是字元串,對于你所需要使用的一些 Win32 API,
你也都得先擷取好這些 API 的位址,然後又重複上面的操作,配置設定虛拟記憶體,寫入位址,最後才能夠在遠端線程中調用,
是以如果你所注入的代碼需要完成很複雜的功能的話,還是使用 DLL 的遠端注入技術比較好,使用遠端注入代碼會搞死人的 !
使用 DLL 的遠端注入技術的病毒或者木馬通常都位于一個 DLL 中,
在系統啟動時,通過另外的一個 EXE 程式來在另外的一個程序(宿主程序,比如使用 Explorer.exe)中建立一個遠端線程,
然後再在這個遠端線程的線程處理函數中将這個帶有病毒或者木馬主體的 DLL 加載到宿主程序中,
這樣的話,這個帶有病毒或者木馬主體的 DLL 就會被宿主程序加載,進而得以在宿主程序中執行,
這樣,即使我們自己的 EXE(這個程序通常被稱之為 Loader)程序被關閉了也不會影響到病毒或者木馬主體代碼的執行,
因為這些主體代碼位于 Explorer.exe 程序中執行,而 Explorer.exe 基本上不會被關閉的。
并且使用這種方法,你的惡意代碼也很難被什麼任務管理器之類的發現,因為隻要宿主程序沒有終止運作,
那麼這個 DLL 也就不會在記憶體中解除安裝(當然被解除安裝還是可能的,殺軟就可以利用這點來将這個 DLL 解除安裝掉)。
Demo 展望:
上面的這種注入技術用來實作木馬或者其他的惡意程式其實是比較友善的,
首先由一個 Loader.exe (這個 Loader 可以通過其他的方式來設定為随機器自動啟動,
這可以通過修改 system.ini 或者系統資料庫或者服務之類的來實作)
來通過 CreateRemoteThread 來在 Explorer.exe 程序中建立一個遠端線程,
而後由這個遠端線程神不知鬼不覺的調用一個另外的 DLL,
然後在另外的那個 DLL 中,我們就可以做很多的事情了啊,比如最簡單的,設個全局鍵盤鈎子,用來捕獲鍵盤的記錄,
再進行一定的解析就有可能擷取使用者有效的密碼之類的資訊,同時,既然 DLL 都注入到 Explorer.exe 中了,
那麼還可以做很多邪惡的事情,比如在其中悄悄的掃描使用者磁盤上的檔案,隻要是 .jpg, .png 之類的就全部給記錄下來,
或者再在 DLL 中建立個什麼 SOCKET 之類的,并且将這些什麼 .png 啊,.jpg 啊之類的圖檔資料悄悄的傳出去,
然後說不準第二個豔照門就出來了 ~
當然這些都是後話了,不過有了上面的這幾個技術,要實作這種簡單的木馬功能還是很容易了哦 !
當然,這裡再提一下的是,這樣做不道德 ! 針對女朋友的屬于合法行為 ! 哈哈哈 !
然後還有一個要提一下的是,現在這種注入方式,殺軟或者安全衛士是能夠捕捉到了,也就是過不了殺軟或安全衛士這一關了哦 !
畢竟 03 年就有大牛弄這種東西了,這麼些年了,人家做反病毒做安全的也不是吃飯的 !
不過如果将上面的技術和 Rootkit 做個結合,可能效果會很不一樣了哦,尚待研究 ~