Windows Hook 易核心編程遠程線程注入 上

上一期我們講了勾子基本概念和一些簡單的應用

這一期我們就來學習用用鉤子技術和內存文件映射共享技術來實現遠程線程插入
 
  現在網上關於這項編程技術的介紹滿天飛,因爲要想寫出一個好的後門,該後門至少要達到高隱蔽.
防查殺,無端口,自啓動等要求,而將木馬以DLL的形式嵌入到系統進程中,基本上可以滿足要求,而
這種遠程線程注入技術也成爲現代後門和木馬程序的一項標準技術指標.
如果大家要想更爲清晰地掌握該項編程技術,強烈推薦細讀jeffery Richter的<<Windows核心技術>>.
該書個人覺得是每個學習Windows黑客編程技術愛好者的聖經.

不過,由於易語言出來的時間不長,網上用易語言具體實現這項編程技術的資料廖廖無幾

今天,我們就來用易語言來實現遠程線程插入:

大家知道,傳統的遠程線程插入是通過以下幾個API來完成的;

·OpenProcess - 用於打開要寄生的目標進程。

·VirtualAllocEx/VirtualFreeEx - 用於在目標進程中分配/釋放內存空間。

·WriteProcessMemory - 用於在目標進程中寫入要加載的DLL名稱。

·CreateRemoteThread - 遠程加載DLL的核心內容,用於控制目標進程調用API函數。

·LoadLibrary - 目標進程通過調用此函數來加載病毒DLL。

這種方法雖然好,但有個缺點:只能在NT核心的系統上有效,在98中無效

並且由於易DLL的特殊性,上面的方法並不奏效,雖然可以用寫入彙編碼來解決問題

但也較不方便,鉤子的出現爲我們解決了這個難題

通過鉤子實現遠程線程插入的思路如下:

通過安裝windows 消息鉤子WH_GETMESSAGE,把待插線程代碼所在的DLL注入到其他進程裏
在鉤子回調函數中,判斷當前進程ID是否是要插入的進程ID,如果是則創建一個新線程
這個新線程函數就是我們要執行的代碼所在的函數,到這裏也就達到了我們的目地.

現在就產生了一個新問題,由於我們的要執行的代碼是放在一個DLL裏面的,創建新線程就需要加載
這個DLL,就需要知道DLL路徑,還有判斷當前進程ID是否是要插入的進程ID,首先也要知道要插入的
進程ID是多少等等這些信息,這就涉及到進程通訊,我們可以用文件映射技術來進行進程通訊.

文件映射主要是通過以下幾個API來完成的:

*CreateFileMapping    //創建文件映射對象 ,成功返回文件映射對象句柄
   Dll命令名:CreateFileMapping
    所處動態鏈接庫的文件名:kernel32
    在所處動態鏈接庫中的命令名:CreateFileMappingA
    返回值類型:整數型
    參數<1>的名稱爲“文件映射句柄”,類型爲“整數型”。註明:指定欲在其中創建映射的一個文  

        件句柄。&HFFFFFFFF&(-1)表示在內存中創建一個文件映射。
    參數<2>的名稱爲“安全對象”,類型爲“SECURITY_ATTRIBUTES”。註明:SECURITY_ATTRIBUTES  

       指定一個安全對象,在創建文件映射時使用。如果爲NULL(用ByVal As Long傳遞零),       

      表示使用默認安全對象。
    參數<3>的名稱爲“打開映射方式”,類型爲“整數型”。註明:下述常數之一:;PAGE_READONLY  

       以只讀方式打開映射;PAGE_READWRITE:以可讀、可寫方式打開映射;PAGE_WRITECOPY:爲      

      寫操作留下備份可組合使用下述一個或多個常數;SEC_COMMIT:爲文件映射一個小節中的        

     所有頁分配內存;SEC_IMAGE:文件是個可執行文件;SEC_RESERVE:爲沒有分配實際內存的        

    一個小節保留虛擬內存空間
    參數<4>的名稱爲“文件映射最大長度”,類型爲“整數型”。註明:文件映射的最大長度(高32位

)。
    參數<5>的名稱爲“文件映射的最小長度”,類型爲“整數型”。註明:文件映射的最小長度(低32

位)。如這個參數和dwMaximumSizeHigh都是零,就用磁盤文件的實際長度。
    參數<6>的名稱爲“映射對象名”,類型爲“文本型”。註明:指定文件映射對象的名字。如存在這

個名字的一個映射,函數就會打開它。用vbNull創建一個無名的文件映射;。

*OpenFileMappingA   //打開一個已存在的文件映射對象,成功返回打開的文件映射對象句柄
  Dll命令名:OpenFileMapping
    公開
    所處動態鏈接庫的文件名:kernel32
    在所處動態鏈接庫中的命令名:OpenFileMappingA
    返回值類型:整數型
    參數<1>的名稱爲“常數”,類型爲“整數型”。註明:帶有前綴FILE_MAP_???的一個常數。參考

MapViewOfFile函數的dwDesiredAccess參數的說明。
    參數<2>的名稱爲“進程繼承”,類型爲“整數型”。註明:如這個函數返回的句柄能由當前進程啓

動的新進程繼承,則這個參數爲TRUE。
    參數<3>的名稱爲“文件映射對象名稱”,類型爲“文本型”。註明:指定要打開的文件映射對象名

稱;。

*MapViewOfFile /將一個文件映射對象映射到當前應用程序的地址空間
 Dll命令名:MapViewOfFile
    將一個文件映射對象映射到當前應用程序的地址空間。MapViewOfFileEx允許我們指定一個基本地址

來進行映射文件映射在內存中的起始地址。零表示出錯。會設置GetLastError
    所處動態鏈接庫的文件名:kernel32
    在所處動態鏈接庫中的命令名:MapViewOfFile
    返回值類型:整數型
    參數<1>的名稱爲“hFileMappingObject”,類型爲“整數型”。
    參數<2>的名稱爲“dwDesiredAccess”,類型爲“整數型”。
    參數<3>的名稱爲“dwFileOffsetHigh”,類型爲“整數型”。
    參數<4>的名稱爲“dwFileOffsetLow”,類型爲“整數型”。
    參數<5>的名稱爲“dwNumberOfBytesToMap”,類型爲“整數型”。

通過以上API再結合易自帶的寫到內存(),指針到字節集(),指針到文本(),取字節集數據()等命令就可以

在進程間讀寫數據了.


內存文件映射技術就介紹到這裏,在下面的實例中有具體應用,我就不多說了.


以資源管理器進程(explorer.exe)爲例,我們來開始解析程序:

程序基本原理:
start.exe 先在內存中創建一個映射文件,把自己的線程ID和查找到的 Explorer進程ID
以及HookDL.dll的路徑寫到映射文件,再安裝 HookDL.dll 中的 WH_GETMESSAGE 鉤子,
此時,start.exe進入消息循環,直到收到被插進程發來的線程退出消息WM_QUIT
   在鉤子回調函數中,首先把start.exe在內存中創建的映射文件映射到當前進程,然後
判斷當前進程ID是否先前 Start.exe 查找到的 Explorer進程ID, 是的話,則
再次LoadLibrary(HookDLL.dll),並定位到其中ThreadPro函數. 此時創建一個
新線程,線程函數就是ThreadPro,該新線程首先往Start.exe消息隊列放置一個線
程退出消息 WM_QUIT,導致其消息循環結束.
    此時插入線程完成..可以看到屏幕左上角不斷變化的數字..說明我們的代碼正在執行.
進程列表卻沒有Start.exe,用進程管理觀察,可發現Explorer進程,的確多了個線程,且來自
HookDLL.dll ..如果希望插入Explorer的線程結束,按 Alt+L 即可...  :) 

現在我們來看看主程序代碼,爲照顧新手,我會逐行分析:

.版本 2
'系統核心支持庫
.應用接口支持庫

.程序集 窗口程序集1
.程序集變量 Explorer_PID, 整數型
.程序集變量 hhook, 整數型
.程序集變量 FileMapH, 整數型
.程序集變量 DLLPath, 文本型

.子程序 __啓動窗口_創建完畢
.局部變量 nil, SECURITY_ATTRIBUTES
.局部變量 TheNodeP, 整數型
.局部變量 ThreadMessage, MSG
.局部變量 MainPath, 字節集
.局部變量 ExplorerID, 字節集
.局部變量 MainThread, 字節集
.局部變量 Mainhhook, 字節集

' 指定DLL路徑
DLLPath = 取運行目錄 () + “HookDLL.dll”

' 檢查插入線程是否已經存在
FileMapH = api_OpenFileMapping (#FILE_MAP_ALL_ACCESS, 0, “hacker0058Explorer8Mazi”)
api_CloseHandle (FileMapH)

.如果真 (FileMapH = 0)  '如果插入線程不存在,開始插入
    Explorer_PID = 取進程PID (“explorer.exe”)  ' 這裏指定要插入的進程,用到了子程序:取進

程PID()                                                  
   
   .如果真 (Explorer_PID = 0)    '查找explorer失敗
        信息框 (“尋找指定進程出錯!”, 0, )
        結束 ()
    .如果真結束
'創建內存映射文件 
    FileMapH = api_CreateFileMapping (-1, nil, #PAGE_READWRITE, 0, 100,“HookExplorer8Mazi

”) 
   
'映射到本進程空間  
 TheNodeP = api_MapViewOfFile (FileMapH, #FILE_MAP_ALL_ACCESS, 0, 0, 0)
   
'寫入共享數據
    ExplorerID = 到字節集 (Explorer_PID)
    MainThread = 到字節集 (當前線程標誌符_ ())
    MainPath = 到字節集 (DLLPath) + { 0, 0, 0 }  ' 字符串是以兩字節的0爲結束標誌的,所以這

里加上{ 0, 0, 0 }                                                   
    寫到內存 (ExplorerID + MainThread + MainPath, TheNodeP, )
   
'關閉內存映射
   API_UnmapViewOfFile (TheNodeP)

'掛DLL跳板鉤子  
   hMod = GetMsgHookOn ()
    .如果真 (hMod = 0)
        輸出調試文本 (“掛DLL跳板鉤子失敗!”)
        api_CloseHandle (FileMapH)  ' 關閉映射文件
        結束 ()
    .如果真結束
'等待插入Explorer的新線程發來消息   
   api_GetMessage (ThreadMessage, 0, 0, 0)

'脫DLL跳板鉤子  
   GetMsgHookOff ()
' 御載DLL     
    api_FreeLibrary (hMod)
' 關閉映射文件
    api_CloseHandle (FileMapH) 
  
.如果真結束
結束 ()

.子程序 取進程PID, 整數型, , 成功返回進程PID,失敗返回0
.參數 標誌文本, 文本型, , 進程名或窗口名
.局部變量 進程, 進程信息, , "0"
.局部變量 PID, 整數型
.局部變量 i, 整數型

PID = 0
 .如果真 (倒找文本 (標誌文本, “.”, , 真) ≠ -1)
    進程 = 取系統進程列表 ()
    .計次循環首 (取數組成員數 (進程), i)
        .如果真 (倒找文本 (進程 [i].進程名稱, 標誌文本, , 真) ≠ -1)
            PID = 進程 [i].進程標識符
            跳出循環 ()
        .如果真結束

    .計次循環尾 ()
 .如果真結束
 .如果真 (PID = 0)
    API_取進程標識符 (api_FindWindow (0, 標誌文本), PID)
 .如果真結束
返回 (PID)

============================================================

待續...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章