20242323 2026-2027-1 《网络与系统攻防技术》实验三实验报告
20242323 2026-2027-1 《网络与系统攻防技术》实验三实验报告
0.实验环境
- 攻击机:Kali Linux 虚拟机(IP: 192.168.61.129)
- 目标机:Windows 10 虚拟机(运行于物理宿主机上,网络模式为 NAT,IP: 192.168.61.137)
- 杀毒软件:Windows Defender(反恶意软件客户端版本 4.18.26090.9,防病毒引擎版本 1.461.96.0)
1.基础知识
1.1 现代杀毒软件的多层检测机制
现代杀毒软件(如 Windows Defender)早已不再依赖单一的文件哈希比对,而是构建了一套静态与动态结合的多层防御体系:
- 特征码静态检测:杀软会提取文件中的特定字节序列、字符串片段或计算整个文件的哈希值。只要文件里有一丁点与病毒库中已知恶意代码匹配的“指纹”,就会立即被查杀。这种方法速度极快,但无法防御未知变种。
- 启发式静态扫描:为了解决未知病毒,杀软会分析文件的结构。例如,正常的软件很少会申请“可读可写可执行”的内存权限,也很少会使用某些高危的底层 API。如果文件包含了这种异常特征,或者文件的熵值(混乱度)极高(说明被加密或压缩了),就会被判定为“形迹可疑”。
- EDR 动态行为监控:这是现代杀软最核心的防线。程序在运行时,杀软的底层内核驱动会实时监控进程的所有敏感操作,比如是否试图修改其他进程、是否在内存中解压执行代码、是否发起了异常的网络连接。一旦发现,直接切断进程。
1.2 Windows 底层内存操作与敏感 API
为了让自制的 Shellcode 在内存中运行,我们编写的 C 语言加载器(Loader)必须要调用 Windows 的核心 API,而这些正是 EDR 监控的重点:
- VirtualAlloc:用于在进程的虚拟地址空间里申请一块内存。如果申请时的权限标志位包含
PAGE_EXECUTE_READWRITE(即 RWX,可读可写可执行),极易引起杀软警觉,因为绝大多数正常程序不会在运行时动态申请这种权限的内存。 - memcpy:将加密后的 Shellcode 密文从数据段复制到刚刚申请的那块内存中。
- VirtualProtect:用于修改内存页的访问保护属性。很多高级免杀代码会先申请
PAGE_READWRITE权限(避免引起怀疑),等写入代码后,再通过这个函数将内存改为PAGE_EXECUTE_READ,从而执行里面的机器码。 - 函数指针:C 语言中无法直接执行内存里的数据,必须将这块内存的地址强制转换为函数指针
((void(*)())exec)();,让 CPU 的指令寄存器跳转到该地址去执行。
1.3 PE 文件结构与 UPX 加壳原理
- PE 结构:Windows 下的可执行文件(如 exe、dll)遵循 PE 格式。它包含了文件头以及多个节区,如存放代码的
.text段。杀软静态扫描时,会重点检查这些节区的内容。 - UPX 加壳:加壳工具 UPX 会把原始 PE 文件中的代码段进行压缩,并附加一段解压代码(Stub)。程序运行时,Stub 首先获得控制权,在内存中把原本的代码解压还原,再跳转执行。加壳后,原来的节区结构改变,恶意特征码被隐藏,从而绕过静态扫描。但高强度的压缩会导致文件熵值变高,容易触发启发式查杀。
1.4 异或(XOR)加密原理
异或运算有两个特性:一是消除特征,将 MSF 生成的 Shellcode 与固定密钥(如 0xAA)异或,其恶意机器码特征会被破坏,变成无害的十六进制数组;二是解密可逆,假设原始代码为 A,密钥为 B,加密得到 C = A ^ B。程序运行时,只需用 C ^ B 就能还原出 A。这让 C 语言可以通过简单的循环在内存中动态解密,无需在硬盘暴露原始代码。
2.实验内容
- 测试 MSF 编码器、Jar 文件格式以及 UPX 加壳的实际免杀效果。
- 使用 Python 脚本对纯二进制 Shellcode 进行
0xAA异或加密。 - 编写 C 语言加载器(Loader),在内存中解密并执行 Shellcode。
- 在开启 Windows Defender 的 Windows 10 虚拟机上验证静态查杀与动态运行效果,并记录杀软版本信息。
3.实验过程
3.1 传统工具与编码器测试
【方案简介】:直接使用 msfvenom 生成原始载荷、多次编码载荷及 Jar 格式文件,验证传统特征码修改手段在现代杀软面前的存活率。
操作步骤:使用 msfvenom 生成原始 exe、经过 5 次编码的 exe 以及 jar 格式文件。
测试结果:传入 Win10 虚拟机后,Defender 瞬间弹窗并删除了文件。在 VirScan 平台上,原始木马与编码木马的检出率均为 16/48,Jar 文件为 15/48。
【Defender查杀raw弹窗截图】

【Defender查杀encoded弹窗截图】

【Defender查杀jar弹窗截图】

【VirScan raw 16/48截图】

【VirScan encoded 16/48截图】

【VirScan jar 15/48截图】

结论:MSF 自带的编码器只是增加了一个解码外壳,而解码器的机器码早已被各大杀软记录,因此单纯修改特征码或更换文件格式无法实现免杀。
3.2 C + Shellcode 加密编程与加壳
【方案简介】:采用组件分离的思路,提取原始机器码进行异或加密,利用 C 语言编写 Loader 在内存中解密执行,最后用 UPX 加壳改变文件结构以绕过静态扫描。
操作步骤:
- 提取原始机器码,用 Python 进行
0xAA异或加密,转为 C 语言数组格式。 - 编写 C 语言加载器,实现内存申请、密文拷贝、循环解密与执行。
- 编译生成
loader_20242323.exe并进行 UPX 加壳。 - 上传至 VirScan 平台验证。
测试结果:加壳后的 loader_upx_20242323.exe 在 VirScan 上的检出率降至 5/48。报毒的 5 个引擎触发的多为 packed(加壳)规则,说明恶意特征码已被成功抹除。
【VirScan loader_upx 5/48截图】

关于替代 Veil-Evasion 的说明:
在实验初期,我尝试按照指导书执行 git clone https://github.com/Veil-Framework/Veil.git 并运行 sudo ./setup.sh -c 安装 Veil 框架。但由于该框架依赖的 Python 环境较老,与当前 Kali 系统存在严重兼容性问题,多次运行后报错无法正常加载模块。鉴于其固定模板特征早已被现代杀软广泛查杀,我决定放弃该工具,转而采用更底层的手写 C 语言 Loader 方案。
3.3 实机测试与回连验证
【方案简介】:在开启 Defender 的 Win10 虚拟机上验证加密 Loader 的静态查杀与动态运行情况,并进行反弹回连测试。
- 静态查杀测试:保持 Defender 实时保护全开,将
loader_upx_20242323.exe下载至 Win10。文件成功落地且未被删除,实现了静态免杀。
【Win10 Defender全开,文件存活截图】

- 动态拦截现象:双击运行文件时,系统弹窗提示“无法成功完成操作,因为文件包含病毒或潜在的垃圾软件”。这说明程序运行时申请内存、执行解密代码的底层行为,触发了 Defender 的 EDR 行为监控,导致进程被阻断。
【双击运行被拦截报错截图】

- 回连验证测试与反思:
为了确认自身编写的 C 语言代码(解密逻辑、网络连接)完全正确,而非代码 Bug 导致无法上线,我暂时关闭了 Defender 的实时保护进行了测试。再次双击运行后,成功回连到 Kali,执行sysinfo获取到了目标信息。
这证明我的免杀代码逻辑是可行的,之前的拦截纯粹是杀软动态行为监控在起作用。本次实操虽然未能用纯手写的本地数组 Loader 绕过 Defender 内核层的 EDR 拦截,但让我深刻认识到:要对抗现代顶级的动态防御,必须采用远程拉取 Shellcode 或间接 API 调用等更高级的分离加载技术。
【Kali 成功回连并执行 sysinfo 截图】

- 杀软版本记录:Windows Defender,反恶意软件客户端版本 4.18.26090.9,防病毒引擎版本 1.461.96.0。
【Windows 安全中心版本信息截图】

4.问题及解决方案
问题1:在编写 C 语言 Loader 时,第一次编译出来的程序双击运行后一闪而过,Kali 端 msfconsole 显示 Meterpreter session 1 opened 但紧接着提示 Reason: Died(会话死亡断开)。
解决方案:通过排查代码逻辑发现,C 语言主函数在调用执行 Shellcode 后立刻执行了 return 0;。主线程一退出,整个进程就被系统回收,导致内存中的木马程序也被强制终止。后来我在代码末尾添加了 while(1) { Sleep(1000); } 的死循环,让主进程保持挂起状态,成功解决了会话掉线的问题。
问题2:在提取加密 Shellcode 数组并粘贴到 C 代码中时,编译一直报错,或者生成的程序运行后内存报错崩溃。
解决方案:由于 msfvenom 生成出来的十六进制代码带有引号和换行符,手动复制极其容易漏掉字符或引入非法字符。后来我改用 Python 脚本,读取原始的二进制文件(raw),自动进行异或加密,并严格按照 C 语言数组的格式 0xXX, 0xXX 输出。通过脚本自动化处理,彻底解决了格式错误和偏移量计算错误的问题。
问题3:用浏览器直接通过 HTTP 下载生成的 loader_upx_20242323.exe 时,一直被 Edge 浏览器的 SmartScreen 拦截,提示文件不安全无法下载。
解决方案:为了绕过浏览器的信誉检查,我使用了 Windows 下的 ncat.exe 工具,在 Kali 端监听端口并输入文件内容,在 Windows 端使用 ncat.exe > 文件名 的重定向方式。通过这种底层的 TCP 数据流传输,成功将免杀文件传入了目标机。
5.学习感悟、思考等
这次实验让我对免杀技术有了更加具体的认识。
一开始,我以为使用 MSF 编码器多次编码就能绕过杀软,但在本地测试时,发现文件依然被瞬间查杀。后来,我通过手写 C 语言代码、使用异或加密和 UPX 加壳,成功将 VirScan 上的检出率降到了 5/48,并且文件能够在开启 Defender 的桌面上存活,这让我觉得静态免杀已经起作用了。
但在双击运行被拦截的那一刻,我意识到免杀是一个需要不断更新的过程。单纯修改文件特征已经不足以绕过现代杀软的防御,程序在内存中的运行行为同样会被监控。虽然这次回连测试是在关闭防护的情况下完成的,但这让我确认了我的代码逻辑没有问题。这次实验让我明白了,要对抗现代的安全机制,仅仅改变文件表面是不够的,还需要深入学习更底层的加载和执行技术,比如分离式加载或远程拉取,这也是我以后需要继续摸索的方向。
6.回答问题
(1)杀软是如何检测出恶意代码的?
主要通过三种方式:一是特征码检测,通过比对文件中的特定字节或哈希值;二是启发式检测,通过分析文件的结构、是否加壳或调用了敏感函数来判断;三是行为监控,在程序运行时监控其是否执行了恶意操作,如内存注入等。
(2)免杀是做什么?
免杀就是对恶意代码进行处理,使其在静态文件扫描、启发式分析或运行时行为监控中,不被杀毒软件发现,从而能够顺利执行。
(3)免杀的基本方法有哪些?
- 修改特征码:如使用 MSF 编码器、添加花指令。
- 加壳与混淆:使用 UPX 等工具改变文件结构和熵值。
- 组件分离与内存加载:自己编写加载器,将加密的 Shellcode 分离存放,运行时在内存中解密执行。
- 无文件攻击:利用脚本语言在内存中直接执行代码。
参考资料
- 《网络与系统攻防技术》课程实验指导书(0x23 免杀原理与实践)
- VirScan 多引擎在线扫描平台
- MITRE ATT&CK - Defense Evasion
浙公网安备 33010602011771号