<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    通過PsSetLoadImageNotifyRoutine學習模塊監控與反模塊監控

    VSole2021-12-20 16:16:43

    本文要實現的是對模塊加載的監控,并卸載掉目標模塊。實驗是在WIN 7 X86系統上進行,需要使用的文件是InjectDll.dll和TestDriver.sys。這兩個文件的內容非常簡單,InjectDll.dll在加載進進程中以后只會彈出加載的對話框,而TestDriver.sys只是在驅動加載和卸載的時候打印字符提醒。

    模塊監控

    1、實現原理

    在內核中可以通過PsSetLoadImageNotifyRoutine來設置模塊監控,監控系統中各個應用程序加載的DLL以及系統加載的驅動。在函數在中文檔的定義如下:

    NTSTATUS  PsSetLoadImageNotifyRoutine(    IN PLOAD_IMAGE_NOTIFY_ROUTINE  NotifyRoutine);
    

    其中NotifyRoutine是一個LOAD_IMAGE_NOTIFY_ROUTINE的函數指針,該函數在文檔中的定義如下:

    typedefVOID(*PLOAD_IMAGE_NOTIFY_ROUTINE)(    __in PUNICODE_STRING FullImageName,    __in HANDLE ProcessId,                // pid into which image is being mapped    __in PIMAGE_INFO ImageInfo    );
    

    參數

    說明

    FullImageName

    指向模塊的完整路徑

    ProcessId

    加載模塊的進程PID。如果是驅動文件,該值為0

    ImageInfo

    指向IMAGE_INFO結構體,包含了模塊信息

    IMAGE_INFO在文檔中的定義如下:

    typedef struct _IMAGE_INFO {    union {        ULONG Properties;        struct {            ULONG ImageAddressingMode  : 8;  // Code addressing mode            ULONG SystemModeImage      : 1;  // System mode image            ULONG ImageMappedToAllPids : 1;  // Image mapped into all processes            ULONG ExtendedInfoPresent  : 1;  // IMAGE_INFO_EX available            ULONG Reserved             : 21;        };    };    PVOID       ImageBase;    ULONG       ImageSelector;    SIZE_T      ImageSize;    ULONG       ImageSectionNumber;} IMAGE_INFO, *PIMAGE_INFO;
    

    最關鍵的兩個是ImageBase和ImageSize,分別代表了模塊的基地址和模塊的大小。

    而要卸載模塊監控,則需要使用PsRemoveLoadImageNotifyRoutine,該函數在文檔中的定義如下,參數含義和設置模塊監控一樣。

    NTSTATUS  PsRemoveLoadImageNotifyRoutine(    IN PLOAD_IMAGE_NOTIFY_ROUTINE  NotifyRoutine );
    

    驅動的卸載和DLL的卸載是不一樣的。

    對于驅動的卸載,只需要找到驅動入口點,并且直接返回STATUS_ACCESS_DENIED(0xC0000022)錯誤碼就好。這樣,已經加載的驅動就會在執行的時候出錯,導致驅動啟動失敗。

    對于DLL的卸載則需要使用未到出函數MmUnmapViewOfSection用來進行卸載。當由于加載進程模塊的時候,系統會有一個內部鎖,為了避免死鎖。要通過創建線程進程延遲等待,等待DLL加載完成以后在調用函數進行卸載。

    具體代碼如下:

    #include #include  #define DRIVER_NAME L"TestDriver.sys" //要攔截的驅動名#define DLL_NAME L"InjectDll.dll" //要攔截的DLL名 typedef struct _DLL_INFO{    HANDLE ProcessId;    PVOID pImageBase;}DLL_INFO, *PDLL_INFO; //Dll的信息,用來作為線程的參數傳遞 VOID DriverUnload(IN PDRIVER_OBJECT driverObject);VOID LoadImageNotifyRoutine(PUNICODE_STRING FullImageName, HANDLE ProcessId, PIMAGE_INFO ImageInfo);  //模塊監控回調函數BOOLEAN DenyLoadDriver(PVOID pLoadImageBase); //對驅動的加載進行攔截BOOLEAN DenyLoadDll(HANDLE ProcessId, PVOID pImageBase);    //對DLL的加載進行攔截NTSTATUS MmUnmapViewOfSection(PEPROCESS Process, PVOID BaseAddr);   //未導出函數聲明VOID ThreadProc(PVOID StartContext);  //運行的線程函數 NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath){    NTSTATUS status = STATUS_SUCCESS;     DbgPrint("驅動加載完成\r");    status = PsSetLoadImageNotifyRoutine(LoadImageNotifyRoutine);    if (!NT_SUCCESS(status))    {        DbgPrint("模塊監控設置失敗 0x%X\r", status);    }    else    {        DbgPrint("模塊監控設置成功\r");    }exit:    driverObject->DriverUnload = DriverUnload;    return STATUS_SUCCESS;} VOID LoadImageNotifyRoutine(PUNICODE_STRING FullImageName, HANDLE ProcessId, PIMAGE_INFO ImageInfo){    PDLL_INFO pDllInfo = NULL;    HANDLE hThread = NULL;     /*    DbgPrint("===========================================================================\r");    DbgPrint("檢測到新加載的模塊,模塊信息如下:\r");    DbgPrint("加載該模塊的進程ID:%d 模塊完整名:%wZ 模塊基址:0x%X 模塊大小:0x%X", ProcessId, FullImageName, ImageInfo->ImageBase, ImageInfo->ImageSize);    DbgPrint("===========================================================================\r");    */     // 是否是exe或者dll文件    if (ProcessId)    {        if (wcsstr(FullImageName->Buffer, DLL_NAME) != NULL)        {            pDllInfo = (PDLL_INFO)ExAllocatePool(NonPagedPool, sizeof(DLL_INFO));            if (!pDllInfo)            {                DbgPrint("ExAllocatePool Error");            }            else            {                pDllInfo->ProcessId = ProcessId;                pDllInfo->pImageBase = ImageInfo->ImageBase;                PsCreateSystemThread(&hThread, 0, NULL, NtCurrentProcess(), NULL, ThreadProc, pDllInfo);                if (hThread) ZwClose(hThread);            }        }    }    else    {        //加載的是驅動,判斷是否是要攔截的驅動        if (wcsstr(FullImageName->Buffer, DRIVER_NAME) != NULL )        {            if (DenyLoadDriver(ImageInfo->ImageBase))            {                DbgPrint("成功攔截驅動%wZ的加載\r", FullImageName);            }        }    }} VOID ThreadProc(PVOID StartContext){    PDLL_INFO pDllInfo = (PDLL_INFO)StartContext;    LARGE_INTEGER liTime = { 0 };     //延時5秒    liTime.QuadPart = -50 * 1000 * 1000;    KeDelayExecutionThread(KernelMode, FALSE, &liTime);    //卸載DLL    if (DenyLoadDll(pDllInfo->ProcessId, pDllInfo->pImageBase))    {        DbgPrint("Dll卸載完成\r");    }     if (pDllInfo) ExFreePool(pDllInfo);} BOOLEAN DenyLoadDll(HANDLE ProcessId, PVOID pImageBase){    BOOLEAN  bRet = TRUE;    NTSTATUS status = STATUS_SUCCESS;    PEPROCESS pEprocess = NULL;  //保存加載DLL的進程的EPROCESS     //根據進程PID獲取EPROCESS    status = PsLookupProcessByProcessId(ProcessId, &pEprocess);     if (!NT_SUCCESS(status))    {        DbgPrint("PsLookupProcessByProcessId Error 0x%X", status);        bRet = FALSE;        goto exit;    }     //卸載模塊    status = MmUnmapViewOfSection(pEprocess, pImageBase);    if (!NT_SUCCESS(status))    {        DbgPrint("MmUnmapViewOfSection Error 0x%X\r", status);        bRet = FALSE;        goto exit;    }exit:    return bRet;} BOOLEAN DenyLoadDriver(PVOID pLoadImageBase){    BOOLEAN bRet = TRUE;    NTSTATUS status = STATUS_SUCCESS;    PVOID pVoid = NULL;    PIMAGE_DOS_HEADER pDosHead = NULL;    PIMAGE_NT_HEADERS pNtHeader = NULL;    PVOID pDriverEntry = NULL;    PMDL pMdl = NULL;    // 要寫入的ShellCode,硬編碼的意思是    // mov eax, 0xC0000022    // ret    UCHAR szShellCode[6] = { 0xB8, 0x22, 0x00, 0x00, 0xC0, 0xC3};    ULONG uShellCodeLength = 6;     pDosHead = (PIMAGE_DOS_HEADER)pLoadImageBase;    pNtHeader = (PIMAGE_NT_HEADERS)((ULONG)pLoadImageBase + pDosHead->e_lfanew);    pDriverEntry = (PVOID)((ULONG)pDosHead + pNtHeader->OptionalHeader.AddressOfEntryPoint); //獲取驅動入口點位置     //創建MDL并為內存屬性添加可寫屬性    pMdl = MmCreateMdl(NULL, pDriverEntry, uShellCodeLength);    if (pMdl == NULL)    {        bRet = FALSE;        goto exit;    }     //建立內存頁的MDL描述    MmBuildMdlForNonPagedPool(pMdl);    //改變MDL的標記為可寫    pMdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;    //映射MDL空間    pVoid = MmMapLockedPages(pMdl, KernelMode);    //將shellcode拷到目標地址    RtlCopyMemory(pVoid, szShellCode, uShellCodeLength);    //釋放MDL    MmUnmapLockedPages(pVoid, pMdl);    IoFreeMdl(pMdl);    pMdl = NULL;exit:    return bRet;} VOID DriverUnload(IN PDRIVER_OBJECT driverObject){    NTSTATUS status = STATUS_SUCCESS;     status = PsRemoveLoadImageNotifyRoutine(LoadImageNotifyRoutine);    if (!NT_SUCCESS(status))    {        DbgPrint("模塊監控刪除失敗 0x%X\r", status);    }    else    {        DbgPrint("模塊監控刪除成功\r");    }    DbgPrint("驅動卸載完成\r");}
    

    2、實驗結果

    對于DLL加載來說,當沒有開起監控程序卸載的時候,在加載DLL文件以后可以在監控軟件中查找到對應的DLL。

    而當開起監控完成DLL卸載以后,就沒辦法找到相應的DLL了。

    對于驅動來說,當沒有開起監控的時候,可以正常的加載與卸載。

    而開起監控以后,驅動的加載就會被攔截。

    反模塊監控

    1、逆向分析PsSetLoadImageNotifyRoutine

    PsSetLoadImageNotifyRoutine在IDA中的反匯編代碼如下:

    PAGE:005709B3 ; NTSTATUS __stdcall PsSetLoadImageNotifyRoutine(PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine)PAGE:005709B3                 public PsSetLoadImageNotifyRoutinePAGE:005709B3 PsSetLoadImageNotifyRoutine proc near   ; CODE XREF: sub_580241+215↓pPAGE:005709B3PAGE:005709B3 NotifyRoutine   = dword ptr  8PAGE:005709B3PAGE:005709B3                 mov     edi, ediPAGE:005709B5                 push    ebpPAGE:005709B6                 mov     ebp, espPAGE:005709B8                 push    ebxPAGE:005709B9                 push    esiPAGE:005709BA                 push    ediPAGE:005709BB                 xor     edi, edi        ; edi清0PAGE:005709BD                 push    edi             ; 將0入棧PAGE:005709BE                 push    [ebp+NotifyRoutine] ; 將函數地址入棧PAGE:005709C1                 call    AllocateAssign  ; 分配12字節的內存,低4位和高4位清0,中間4位存放函數地址PAGE:005709C6                 mov     ebx, eax        ; 申請到的內存地址賦給ebxPAGE:005709C8                 cmp     ebx, edi        ; 判斷是否為0,也就是是否分配失敗PAGE:005709CA                 jz      short loc_5709F1 ; 如果內存分配失敗則退出PAGE:005709CC                 mov     esi, offset LoadImageFuncArray ; 將一個數組地址賦給esiPAGE:005709D1PAGE:005709D1 loc_5709D1:                             ; CODE XREF: PsSetLoadImageNotifyRoutine+36↓jPAGE:005709D1                 push    0               ; 將0入棧PAGE:005709D3                 mov     ecx, ebx        ; 將分配的地址賦給ecxPAGE:005709D5                 mov     eax, esi        ; 將數組地址賦給eaxPAGE:005709D7                 call    SetArrayPAGE:005709DC                 test    al, alPAGE:005709DE                 jnz     short loc_5709FD ; 判斷返回值是否為0,不為0則執行成功,跳轉PAGE:005709E0                 add     edi, 4          ; edi加4PAGE:005709E3                 add     esi, 4          ; esi,也就是數組地址+4,所以這是在取數組的下一個元素PAGE:005709E6                 cmp     edi, 20h        ; 判斷edi是否小于0x20,小于則跳轉過去執行函數PAGE:005709E9                 jb      short loc_5709D1 ; 根據前面的清0操作知道這里是為了保證循環調用8次,所以可以判斷這個數組中最多保存7個地址PAGE:005709EB                 push    ebx             ; BufferPAGE:005709EC                 call    FreeAllocate    ; 否則函數執行失敗,釋放申請到的內存PAGE:005709F1PAGE:005709F1 loc_5709F1:                             ; CODE XREF: PsSetLoadImageNotifyRoutine+17↑jPAGE:005709F1                 mov     eax, STATUS_INSUFFICIENT_RESOURCES ; 賦值失敗的返回值PAGE:005709F6PAGE:005709F6 loc_5709F6:                             ; CODE XREF: PsSetLoadImageNotifyRoutine+6B↓jPAGE:005709F6                 pop     ediPAGE:005709F7                 pop     esiPAGE:005709F8                 pop     ebxPAGE:005709F9                 pop     ebpPAGE:005709FA                 retn    4PAGE:005709FD ; ---------------------------------------------------------------------------PAGE:005709FDPAGE:005709FD loc_5709FD:                             ; CODE XREF: PsSetLoadImageNotifyRoutine+2B↑jPAGE:005709FD                 xor     ecx, ecxPAGE:005709FF                 mov     eax, offset unk_542BA0PAGE:00570A04                 inc     ecxPAGE:00570A05                 lock xadd [eax], ecxPAGE:00570A09                 mov     eax, dword_542B78PAGE:00570A0E                 test    al, 1PAGE:00570A10                 jnz     short loc_570A1CPAGE:00570A12                 mov     eax, offset dword_542B78PAGE:00570A17                 lock bts dword ptr [eax], 0PAGE:00570A1CPAGE:00570A1C loc_570A1C:                             ; CODE XREF: PsSetLoadImageNotifyRoutine+5D↑jPAGE:00570A1C                 xor     eax, eaxPAGE:00570A1E                 jmp     short loc_5709F6PAGE:00570A1E PsSetLoadImageNotifyRoutine endp
    

    基本上和這篇一樣:

    通過對PsSetCreateProcessNotifyRoutineEx的逆向分析得出的結果來實現反進程監控(https://bbs.pediy.com/thread-269831.htm)

    那這篇就不再詳細說,唯一的區別就是這里的數組的大小是8。

    2、反模塊監控

    接下來就根據下圖選擇0x7425BE作為硬編碼來查找模塊數組:

    得出如下的反模塊監控代碼:

    #include #include  VOID DriverUnload(IN PDRIVER_OBJECT driverObject);PULONG GetImageArray(); NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath){    NTSTATUS status = STATUS_SUCCESS;    PULONG pImageArray = NULL;    PULONG pFuncAddr = NULL;    ULONG i = 0;     pImageArray = GetImageArray();    if (pImageArray)    {        for (i = 0; i < 8; i++)        {            if (pImageArray[i] & ~0x7)            {                pFuncAddr = (PULONG)(pImageArray[i] & ~0x7 + 4);                status = PsRemoveLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)*pFuncAddr);                if (NT_SUCCESS(status))                {                    DbgPrint("模塊監控刪除成功 模塊地址:0x%X\r", *pFuncAddr);                }            }        }    }     exit:    driverObject->DriverUnload = DriverUnload;    return STATUS_SUCCESS;} VOID DriverUnload(IN PDRIVER_OBJECT driverObject){    DbgPrint("驅動卸載完成\r");} PULONG GetImageArray(){    PULONG pImageArray = NULL;    //要獲取的函數地址的函數名    UNICODE_STRING uStrFuncName = RTL_CONSTANT_STRING(L"PsSetLoadImageNotifyRoutine");    PUCHAR pPsSetCreateThreadNotifyRoutine = NULL;     //獲取函數地址    pPsSetCreateThreadNotifyRoutine = (PUCHAR)MmGetSystemRoutineAddress(&uStrFuncName);    while (*pPsSetCreateThreadNotifyRoutine != 0xC2)    {        if (*pPsSetCreateThreadNotifyRoutine == 0x74 &&             *(pPsSetCreateThreadNotifyRoutine + 1) == 0x25 &&             *(pPsSetCreateThreadNotifyRoutine + 2) == 0xBE)        {            pImageArray = (PULONG)*(PULONG)(pPsSetCreateThreadNotifyRoutine + 3);            break;        }        pPsSetCreateThreadNotifyRoutine++;    }     return pImageArray;}
    

    3、運行截圖

    首先在驅動卸載前,可以看到所有模塊的加載都會監控到:

    接下來運行反監控代碼可以看到模塊的加載就不再被監控到:

    infodll文件
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    本文要實現的是對模塊加載的監控,并卸載掉目標模塊。實驗是在WIN 7 X86系統上進行,需要使用的文件是InjectDll.dll和TestDriver.sys。這兩個文件的內容非常簡單,InjectDll.dll在加載進進程中以后只會彈出加載的對話框,而TestDriver.sys只是在驅動加載和卸載的時候打印字符提醒。
    在2022年2月,卡巴斯基實驗室的研究人員首次觀察到將shellcode放入Windows事件日志的技術。該技術允許在文件系統中隱藏“無文件”最后stager的木馬。這種對活動中事件日志的關注不僅限于存儲 shellcode。Dropper 模塊還修復了與事件跟蹤 (ETW) 和反惡意軟件掃描接口 (AMSI) 相關的 Windows 原生 API 函數,以使感染過程更加隱蔽。
    GuLoader_VBS惡意加載器分析報告
    MySQL UDF提權
    2021-12-01 07:56:57
    sqlmap中的udf文件提供的函數:sys_eval,執行任意命令,并將輸出返回。sys_get,獲取一個環境變量。sys_set,創建或修改一個環境變量。
    驗證子域郵箱名Invoke-DomainHarvestOWA-ExchHostname -Domain -UserList .\userName.txt -OutFile sprayed-ews-creds.txt. Office 365近源滲透物理滲透、物理攻擊、近源滲透,這幾個的意思都是在接近目標進行安全測試。Wi-Fi網線沒有終端準入控制,直接插網線 DHCP 獲取 IP。Bad USBBlack Hat 上提出 Bad USB。社會工程學在信息收集過程中就開始。釣魚本質是利用人的信任。Windows 主機FTP服務端開啟 FTP 服務。使用 certutil 下載的文件會原封不動在?目錄下保存一份,文件名位隨機字符,使用 delete 可以刪除剛下載的緩存。
    淺談ms17-010多種利用方式
    網上關于ShellCode編寫的文章很多,但介紹如何在ShellCode里面使用異常處理的卻很少。Windows程序的異常處理,其實是三者結合的:操作系統、編譯器和程序代碼。因為x86下異常處理的文章太多,所以本文只介紹Win64下的。而Win64的異常處理,是基于表的。也就是說,編譯器在編譯代碼的時候,會同時對每個函數生成一個異常表,最后鏈接到PE的異常表里。相對來說,這個比X86更加安全和高效。
    APT29,又名CozyBear, Nobelium, TheDukes,奇安信內部編號APT-Q-77,被認為是與東歐某國政府有關的APT組織。該組織攻擊活動可追溯至2008年,主要攻擊目標包括西方政府組織機構、智囊團。APT29曾多次實施大規模魚叉攻擊,收集攻擊目標機構或附屬組織的人員信息,并針對其中的高價值目標采取進一步的網絡間諜活動。
    剛好404之前有一篇博客寫過這個漏洞,我在它的參考資料里面找到了github上面提供的poc生成代碼,以及j00sean在twitter上面發的6行代碼,以這兩者為基礎對該漏洞進行分析。
    二進制程序分析
    2021-09-25 17:18:46
    分析惡意軟件的第一步是收集二進制程序在主機上執行的行為事件,研究人員根據這些行為大體形成一個思路來描述惡意軟件的功能。 這包含應用釋放或者從互聯網下下載的文件,寫入什么樣的注冊表、訪問了什么網絡地址,修改讀寫本地的什么文件等等。那么研究人員通過行為會確定惡意樣本的類型。通常類型如下:
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类