前言
冲鸭安全突破3000粉丝了,应该国内大半个搞安全的人都在看了.所以整个大的活.
为什么突然想搞这个,因为在做国内安全业务的时候,我意识到,国内的平均技术水平还有很大的挖掘价值.很多人从事安全,可能也对自己的电脑上的安全软件的工作原理感兴趣.也有很多人把做安全软件视为自己的梦想.或者一个努力方向.所以我觉得,有必要花一些时间,系统的整理一下杀毒引擎的工作原理,在整理工作原理的时候我发现网上基本0资料,有也停留在2006年之前什么特征码扫描,云查杀毒.仿佛杀毒软件这玩意就是个黑盒.
简而言之,为了系统性的科普知识,而不是其他公众号那种胡言乱语,meme,免杀巫术,我花了大概两天时间,写了一个符合现代(2025年)情况的杀毒引擎.现在我将介绍他是如何工作的.以及他的缺陷是什么.并且在文末我还会开源源码,能直接VS编译.方便大家学习
!!!警告:本次代码是示例代码,机器学习以及特征以及动态行为用到的数据量都非常小所以效果是很有限的.本来就是以学习为目的,不要拿去测你的”免杀”木马发现检出不了然后私聊或者留言说无法检测到,这个不是给你拿去搞免杀的.要想进步需要自己研究哪里有问题.而不是隔着复制粘贴代码然后问为什么
杀毒引擎分类
目前查杀引擎各家瞎吹的什么NGAV无非就这几种:
-
云查引擎
这包括:
模糊hash引擎(ssdeep,simhash等都算),模糊hash是一种算法,能比较文件相似度(某些PPT叫病毒基因),具体可以看我之前的文章:
[2021]余弦定理检测文件相似度 & 病毒样本基因检测
https://key08.com/index.php/2021/08/19/1306.html
hash base引擎,没什么好说的,基于sha1或者sha256等固定唯一hash
背后的各种沙箱/人工/自动机鉴定 -
特征引擎 -
ai机器学习引擎 -
启发式沙箱引擎
云引擎说起来非常复杂,属于是各家的核心能力,我们不讨论其实现(某些直接买了VT当云引擎的除外).所以除了1外,2,3,4往往是同时打包在一起的,
这几个引擎各有特点:
-
特征引擎不具备启发能力,纯靠人力堆.但是是效果最好的,各家的数据差异其实是这玩意造成的(除云之外) -
启发的沙箱引擎检出弱,很容易被针对,技术落后一代.而且也会造成轻微误报 -
AI机器学习引擎高检出,但是也高误报,对业务造成很大影响,很多人开VS编译出hello world都告警,基本上目前所有的模型都或多或少过拟合了,变成了看到没签名的就告警.所以基本上也就ToC的开.提高自己的产品形象,其他的纯靠白名单压误报
我们要做什么
我们今天所做的,是一个机器学习+沙箱行为检测的引擎,为什么不做特征引擎,因为特征引擎太普通了,如果对其感兴趣的,可以去看yara.
整个引擎的构造如下图所示:
我们需要实现两个模块,沙箱模块和机器学习模块,我们逐步介绍每个模块的作用
沙箱模块
一般来说,沙盒模块负责脱壳以及部分行为检测,本质上是一个PE模拟器
本沙箱使用unicorn engine作为模拟CPU执行程序, unicorn engine是一个轻量级的多平台、多架构 CPU 仿真器框架。支持包括不限于 MIPS、ARM、PowerPC、X86、X64的系统CPU模拟.并且同时支持windows和linux,在2015年的黑帽大会上由grayshift安全团队基于qemu研发
一般需要这几步:
1.2 初始化模拟环境
(1)重定位
(2)初始化栈
(3)初始化unicorn engine,分配虚拟机
(4)得到PE展开后的内存大小,映射PE文件到虚拟机中
(5)映射关键DLL到虚拟机中
(6)Patch 关键dll中的函数实现监视调用
(7)初始化虚拟机的handle
(8)初始化堆栈、peb、teb等基本执行环境
(9)记录关键PE信息用于脱壳操作
重定位
一般来说,PE如果拥有重定位表,系统在执行PE文件的时候会先根据重定位表重定位PE的资源与函数(一般是基址+偏移),不进行重定位PE将无法运行.
初始化栈
程序在运行的时候会为系统分配一块内存区域作为栈,由栈选择子SS和栈定指针(esp/rsp)来确定当前栈的大小,CPU则直接操作EBP/RBP来存取数据。栈的作用包括不限于保存临时的值、保存程序现场、传递函数参数、保存局部变量等。因此程序要模拟实现它
得到PE展开后的内存大小,并且映射到内存中
PE在硬盘中和在内存中的大小是不相同的,内存中的大小比硬盘上的”大”,因此要”展开”。
为了得到真实的展开后的大小,需要遍历PE的每个区段,然后对每个区段的虚拟大小进行相加
映射关键DLL到虚拟机中
遍历导入表,把导入表的需要的DLL全部映射到里面,当作虚拟模块
注意: 自己的主模块也需要映射
监控API调用
我们先把导入表里面的API放到一个DLL里面
然后就是暴力的模拟API了…这包括堆/栈/security cookie等一堆API,麻烦并且快乐着
整个API是最麻烦的,这块是沙箱的能力体现,我这边并没有完全的模拟API.只模拟了几个测试用例的API list.所以实际效果不太好.但是就为了模拟这几个都花了一天时间,这块非常麻烦
记录关键信息用于脱壳
对于一般的压缩壳类程序,加壳时会划分两个区段,一个是壳段,用于执行壳的代码,一个是内容为空或者内容为0的实际代码段,在执行代码的时候,壳段先被执行,之后填充内容给内容为0的代码段.
这里以UPX压缩壳为例,再未执行壳段代码时候,代码段内容如图所示
执行壳段代码,程序被释放后的代码如图
因此,脱壳机核心思想为,首先记录大小为0的区段,然后监视内存写入,当内存写入到大小为0的区段并且开始执行代码后(即EIP/RIP为被写入的区段地址),则视为壳已经脱下.
然后就dumpPE就行,上次的IP被视为是新程序的入口点.
这个是效果:
看起来不错
注意: 这里有一个严重的问题,就懒得处理了:
壳里面吐出来的代码的导入表和壳的导入表不是同样一个.
这个修的是壳的 导入表,所以导入表 修 不 全
有个很简单的办法,需要搜索IAT结构,然后修改脱壳后的IAT的字段到壳的字段里面,然后再执行一次fix_imports
懒得写了,家庭作业.自己完成
行为检测
我们可以把一些关键行为做检出,简单来说
比如winhttp下载pe
不知道哪个大兄弟的马:
urlString: https://fdaxzld-3-1326101028.cos.ap-chongqing.myqcloud.com/dkhzxka.png
sleep太长:
尝试读敏感目录:
访问LDR
注意: 我只做了几个特定样本的,不具备通用性,感兴趣的可以自己加一些行为特征,比如直接 syscall,SEH加密,直接访问LDR,间接加载winhttp,栈字符串访问,字符串加密等等一切所谓的恶意行为.
沙箱效果
实际效果如下:
至此 我们的沙箱模块就结束了。不过还有一些需要你们自己来操作了:
-
沙箱跑完脱完壳后跑yara -
多线程,线程轮转,切换 -
seh/veh异常处理 -
其他的更多API模拟 -
TLS回调 -目前所有带TLS的都拉闸了 -
异常代码访问,比如mov ss,rdtsc,ollvm jmp,xor加密,rc4等等操作
以上三个在key08.com都有相关文章,可以自己搜索参阅.这里就不说了.
机器学习模块
相较于沙箱模块,机器学习模块相对更简单,主要负责将PE特征转换成标准的特征向量,并使用XGBoost模型进行恶意性的预测和分类。
特征工程
特征工程的目的是从原始数据中提取出具有强泛化能力的有效特征。当前机器学习模块提取的PE文件二进制特征包括:
- PE文件属性特征
-
配置目录、调试信息、异常目录、导出表、导入表、数据执行保护(NX)标志、重定位表、资源目录、签名、安全Cookie、延迟加载导入表、Rich头、TLS表、镜像基址存在性URL属性等共14类基础属性标记是否存在。
-
- 导入DLL特征
-
从导入表中获取DLL列表,使用特定列表库名作为特征并判断其是否存在于导入列表中,共计140个目标DLL库。
-
- 文件整体熵
-
将整个PE文件当作字节流,计算香农熵值来表征PE文件整体随机性的特征。
-
- 入口点(EP)字节
-
分析PE文件入口点所在位置后连续64字节(一种启发式分析)的标准化字节序列特征,反映是否有特征性恶意载荷或混淆方法。
-
- 节区(Section)统计特征
-
提取节区个数、节区熵分布(最大熵、平均熵及熵值归一化特征)以及节区大小比率特征,反映PE文件结构和节区性质。
-
- 代码段大小比率
-
计算代码段大小占总映像文件大小的比例,用于区分不同类型的PE文件。
-
上述特征集合形成PE文件的数字特征向量,以便送入XGBoost模型进行分类训练或预测。
导入CSV
为了便于机器学习模型的训练,我们需要提供大量标记的数据。我们的特征提取工具将原始特征保存为CSV文件,每条记录为一个样本,包括:
-
样本文件路径(第一列,仅用于溯源) -
提取的全部数字特征向量(从第二列起) -
恶意标签(恶意软件标记为1,正常软件标记为0,将在后续训练代码部分添加)
生成CSV的数据过程如下所示:
-
遍历待分析PE文件夹,调用特征提取模块对每个文件生成特征向量。 -
将每个文件的特征向量追加到一个CSV文件,用于后续模型训练。 -
为便于管理,分开存储并标记恶意软件(malware)以及白文件(whitelist)的CSV文件。
找了1000个白样本和1000个黑样本,搜集特征后打包为csv:
!!!注意!!!: 由于是演示的缘故,给的样本太少,所以默认的模型泛化能力很差,也就是说基本上检测不了多少样本,如果你需要训练,起码10W黑样本+10W白样本起步.
模型训练代码
我们采用XGBoost模型用于训练恶意软件分类模型,流程简单清晰:
-
首先读取处理恶意样本CSV和正常样本CSV,进行缺失值处理和长度统一填充。 -
合并为一个完整的数据集,随机分割成训练集和验证集。 -
使用XGBClassifier分类器进行二分类(正常与恶意)的训练,训练时应用参数调整措施(如学习率、树深、随机抽样比例)来防止过拟合。 -
在训练结束后,评估模型准确性。 -
将训练好的模型导出为C语言源代码(m2cgen工具),便于部署到C++环境当中。
训练过程就长这样:
训练模型导出为C++代码
我们使用m2cgen库将训练后的Python XGBoost模型直接导出成纯C/C++代码,这样可以直接嵌入到项目里面:
注意: 我用的是决策树,xgboost,树可以这样做,神经网络等其他的就不行了.但是一般来说,客户端带树就行,因为足够快
预测
预测代码就很简单了,我们输入特征,模型会输出是白文件的概率,这边设置小于0.5就告警了:
我们随便试一下同一批样本但是没进训练的:
!!!注意!!!: 由于是演示的缘故,给的样本太少,所以默认的模型泛化能力很差,也就是说基本上检测不了多少样本,如果你需要训练,起码10W黑样本+10W白样本起步.所以基本上其他的样本都不咋报.
还可以继续优化,这里是家庭作业:
-
考虑NLP,把代码也考虑到模型的特征库里面 -
做特征入库之前使用fuzzhash分类,然后做特定蠕虫入库
但是记住: 越复杂,误报越高.到最后就会变成,误报全靠白名单压.
PE异常检测模块
这个模块就负责对异形PE进行检测
一般加壳或者花里胡哨的PE就会被检测了~
比如这种效果
这块误报挺大的,得自己调整,我这边懒得搞了
演示
机器学习:
异形PE格式:
沙箱:
不足
目前项目存在如下不足:
-
AI部分样本太少,泛化能力弱 -只训练了1000个样本.所以弱是很正常的 -
沙箱部分很多还没模拟,包括TLS和API,以及动态行为为了演示就加了几个,可以自己多加一点.完善它,另外还没加多线程,异常的处理.这块可以去key08.com看各个部分要怎么操作 -
没带yara,理论上沙箱脱壳后,应该转yara扫描 -
没带云,所以可能会存在误报.这块只能靠云策略压误报.
但是无论如何,这个项目无论做到多少,人力给了多少,训练了多少个样本,最高的上限就是目前杀毒软件的上限(比如卡巴斯基的上限),不可能有新的突破了因为现代杀毒已经陷入了死局,必须依靠EDR以及下一代杀毒才能解决现在的安全问题.
关于下一代杀毒方案:
2024年终: 木马病毒自动化特征提取&云端机器学习的思路分享
github源码:
https://github.com/huoji120/awesome_anti_virus_engine
原文始发于微信公众号(冲鸭安全):从0制作现代启发式AI杀毒引擎,附源码
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论