天天看點

dll 源碼_萌新逆向學習筆記——遠端線程注入DLL

dll 源碼_萌新逆向學習筆記——遠端線程注入DLL

本文為看雪論壇精華文章

看雪論壇作者ID:psycongroo

  前言 今天的主題——遠端線程注入DLL,用以在他人EXE中實作自己代碼功能的操作,這次就不僅限于鍵盤記錄了。

準備工作

閱讀并實作本文主題,需要以下工具及知識:

1. C++/C語言的基本知識 2. 程序監控軟體procexp 當然,倘若讀者并沒有掌C++/C語言,也可以繼續閱讀浏覽。因為本文主要為萌新筆者的學習筆記,是以也并沒有過于深奧晦澀難懂的地方。隻要對基本原理,核心API函數留有印象即可。

原理 在講解遠端注入DLL原理之前,讀者需要知道從代碼層級上DLL加載時的函數調用流程。

代碼中加載DLL 要在一個Win32 app中,也就是我們的exe程式中加載DLL隻需要調用一個函數——LoadLibraryA/W。 以下是 LoadLibrary文檔 :

HMODULE LoadLibraryA/W(  LPCWSTR lpLibFileName   //DLL檔案的全路徑);
           

以下為一個控制台程式加載DLL示例:

#include int main(){    LoadLibrary(L"F://Project//MyDll.dll");}
           

參數 LPCWSTR lpLibFileName為DLL檔案的路徑,需要說的是,當加載的DLL檔案和EXE在同一檔案夾下可隻寫DLL為檔案名。   當DLL被使用LoadLibraryA/W加載後,在DLL檔案中的DllMain函數會被自動調用。

以下為建立的DLL檔案:

BOOL APIENTRY DllMain( HMODULE hModule,                       DWORD  ul_reason_for_call,                       LPVOID lpReserved ){    switch (ul_reason_for_call)    {    case DLL_PROCESS_ATTACH:        MessageBox(NULL, L"内容", L"标題", MB_OK);        break;    case DLL_THREAD_ATTACH:    case DLL_THREAD_DETACH:    case DLL_PROCESS_DETACH:        break;    }    return TRUE;}
           

DllMain函數在我們建立DLL檔案時會自動建立,沒有程式設計基礎的讀者也不用過于害怕,我們隻要記住,在EXE調用LoadLibraryA/W函數後,DLL檔案就會執行DllMain函數中的代碼。   是以,如果我們想在"别人的EXE"中實作自己的代碼功能,隻要想辦法,讓别人的EXE調用LoadLibraryA/W 函數加載我們自己寫的DLL檔案即可。   可,這要怎麼做呢?而這正是本文記載的主要内容。

遠端線程使别人加載自己的DLL 要使"别人的EXE"加載我們的DLL其實很簡單,這是因為微軟設計的時候提供了一個函數用來在"别人的EXE"裡執行一個指定函數——CreateRemoteThread。

HANDLE CreateRemoteThread(  HANDLE                 hProcess,  //程序句柄  LPSECURITY_ATTRIBUTES  lpThreadAttributes,  SIZE_T                 dwStackSize,  LPTHREAD_START_ROUTINE lpStartAddress,  //函數位址  LPVOID                 lpParameter,  //傳遞給函數的參數  DWORD                  dwCreationFlags,  LPDWORD                lpThreadId);
           

雖然參數過多,但我們隻需要關注三個參數即可:

1. HANDLE hProcess 為一個程序的句柄,我們隻需要通過另一個函數OpenProcess擷取即可。 2. LPTHREAD_START_ROUTINE lpStartAddress 為我們需要"别人EXE"執行的函數的位址,同時這個函數的傳回值,參數必須符合給定的模闆規格。這個稍後再講是核心。 3. 傳遞給函數的參數,該參數值須存在于"别人EXE"的虛拟記憶體當中,我們可以通過VirtualAllocEx函數向EXE中申請記憶體空間并調用 WriteProcessMemory函數寫入參數,最後再傳遞過去。

傳遞被調用的函數

先前說過,我們傳遞給CreateRemoteThread的函數必須符合一定格式,這個格式可以在 微軟文檔 )中查得到。

DWORD WINAPI ThreadProc(  _In_ LPVOID lpParameter);
           

請記住上面的這個隻是模闆規格,它要求我們傳遞的函數必須符合這樣的格式。大家應該還記得我們的目标吧——調用CreateRemoteThread來迫使"别人的EXE"調用LoadLibraryA/W函數來加載我們的DLL。是以,如果我們能把LoadLibraryA/W函數傳過去該多好。   可要傳遞過去就必須符合上面的格式呀,LoadLibraryA/W函數的格式符合嗎?我們來再次看看:

HMODULE LoadLibraryA/W(  LPCWSTR lpLibFileName   //DLL檔案的全路徑);
           

啊這,這簡直就很像嘛,模闆中傳回值DWORD是表示一個unsigned long值,而參數中的LPVOID則可以指向任何類型。   是以除了傳回值似乎有所不同以外,其他除了名字不同,簡直就很像。是以我們可以通過把LoadLibraryA/W強行轉換為模闆的類型(微軟定義了一個類型LPTHREAD_START_ROUTINE 來代指模闆)傳遞過去即可。   可就算我們知道我們要傳遞的LoadLibraryA/W函數符合了模闆格式,那要怎樣才知道這個函數在"别人的EXE"中的位址呢?因為我們傳遞的LoadLibraryA/W函數位址必須是在"别人的EXE"中的位址,是以我們不能平白無故的把自己的位址傳過去。   這裡有一個常識,那就是每個EXE的虛拟位址是不一樣,換句話來說我在自己程式裡寫了一個和别人EXE裡相同的代碼,加載出來的記憶體虛拟位址完全不同。   但凡事都有例外,系統核心的函數位址在每個EXE中都是一樣的,而LoadLibraryA/W正是系統核心的函數之一。其位于系統核心檔案kernel32.dll之中。   是以我們隻要:通過GetProcAddress函數擷取系統核心函數LoadLibraryA/W的位址->轉換成模闆格式->傳遞到CreateRemoteThread中便可大功告成。

實踐 隻貼出部分核心源碼,需要注意的是編碼的程式涉及到兩個檔案,一個是藥引子EXE,也就是我們調用CreateRemoteThread的地方,另一個是自己編寫的DLL檔案,也就是迫使"别人EXE"加載并執行的檔案。

EXE中代碼:

//參數1:擷取别人的EXE的句柄。程序ID可用procexp檢視并手動輸入mProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 程序ID); // 參數2:擷取位址,并轉換為規定格式HMODULE hMod = GetModuleHandle(L"kernel32.dll");LPTHREAD_START_ROUTINE fun =  (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW"); // 參數3:傳遞給函數的參數,需申請并寫入記憶體// 調用VirtualAllocEx申請記憶體空間CString path = "F:\\Projec\\MyDLL.dll"; SIZE_T pathSize = (path.GetLength()+1) * sizeof(TCHAR);LPVOID mBuffer =  VirtualAllocEx(mProcess, NULL, pathSize, MEM_COMMIT, PAGE_READWRITE);//  調用WriteProcessMemory寫入記憶體WriteProcessMemory(mProcess, mBuffer, path, pathSize, NULL) //調用CreateRemoteThread使别人的EXE加載我們的DLLmRemoteThread = CreateRemoteThread(mProcess, NULL, 0, fun, mBuffer, 0, NULL);
           

DLL中代碼:

BOOL APIENTRY DllMain( HMODULE hModule,                       DWORD  ul_reason_for_call,                       LPVOID lpReserved ){    switch (ul_reason_for_call)    {    case DLL_PROCESS_ATTACH:        MessageBox(NULL, L"内容", L"标題", MB_OK);        break;    case DLL_THREAD_ATTACH:    case DLL_THREAD_DETACH:    case DLL_PROCESS_DETACH:        break;    }    return TRUE;}
           

一些結果:  

dll 源碼_萌新逆向學習筆記——遠端線程注入DLL
dll 源碼_萌新逆向學習筆記——遠端線程注入DLL
dll 源碼_萌新逆向學習筆記——遠端線程注入DLL
dll 源碼_萌新逆向學習筆記——遠端線程注入DLL
dll 源碼_萌新逆向學習筆記——遠端線程注入DLL
dll 源碼_萌新逆向學習筆記——遠端線程注入DLL

總結 作為使用者我們隻要知道調用CreateRemoteThread函數來實作DLL注入即可,參數則靠其他方法去湊。   作為學習者,我們要知道CreateRemoteThread更廣泛的含義并不隻有DLL注入,就如同其文檔所述是在另一個程序中新建立一個線程,并從參數中的起始位址運作。隻是不知道是微軟故意如此設計還是有奇人無意中的發現,才造就了這樣的DLL注入技術。   其實筆者的c++程式設計技術有限,WIN32中的API了解也捉襟見肘,文中大部分内容是筆者閱讀《逆向工程核心原理》後的總結,可能存在疏漏和錯誤,若可指出感激不盡。

dll 源碼_萌新逆向學習筆記——遠端線程注入DLL

- End -

dll 源碼_萌新逆向學習筆記——遠端線程注入DLL

看雪ID:psycongroo

https://bbs.pediy.com/user-899080.htm

  *本文由看雪論壇 psycongroo 原創,轉載請注明來自看雪社群。

推薦文章++++

dll 源碼_萌新逆向學習筆記——遠端線程注入DLL

* Sandboxie循序漸進耳之監控篇上

* CVE-2017-0263 win32k漏洞分析筆記

* 0基礎也能看懂的函數棧結構分析

* CVE-2020-1054分析

* 對比總結32/64位下Windows部分資料結構的異同

dll 源碼_萌新逆向學習筆記——遠端線程注入DLL

公衆号ID:ikanxue 官方微網誌:看雪安全 商務合作:[email protected]

dll 源碼_萌新逆向學習筆記——遠端線程注入DLL

求分享

dll 源碼_萌新逆向學習筆記——遠端線程注入DLL

求點贊

dll 源碼_萌新逆向學習筆記——遠端線程注入DLL

求在看

dll 源碼_萌新逆向學習筆記——遠端線程注入DLL

點選