本文转载自:https://resources.infosecinstitute.com/machine-learning-naive-bayes-rule-for-malware-detection-and-classification/
目录
0x01 摘要
0x02 人造模型
0x03 条件概率
0x04 实施
0x05 结论
本文将统计学和机器学习原理用于分析恶意软件。我们将使用条件概率或贝叶斯概率来深入了解从样本集中收集到的数据,以及如何使用它来制作自己简单的恶意软件分类器。
贝叶斯定理具有广泛的应用,包括自动音乐转录,语音识别和垃圾邮件分类器。本文中,我们将首先概述条件概率的全部内容,然后我们将为Android平台构建我们自己的恶意软件分类器。
贝叶斯规则揭示了人类思维也在概率模型方面起作用。人的思想可以根据期望来建模,可以归结为数字。
考虑学习一门新语言并从原生语言中去听它 - 您会尝试从预设的最适合上下文的学习单词列表中挑选出一组单词。如果能够将思想简化为等式,那就是贝叶斯的主要思想。你正在按照特定的顺序选择一组单词 - 例如你正在听的法语 - “Je suis tres bon。”翻译为“我很好。”你可以选择Je / Vous(我/你),suis / etre(动词“to be”在不同的declension中)和同样。如果你发现'Je'这个词后跟'suis'你已经猜到说话者正试图说一些关于他自己(或类似的背景)的话。
第二个例子是音乐软件中的音乐键转录。在这里,最可能的一组音高被收集在我们将称为“结构”的东西中,这些“结构”编辑在特定键中的歌曲中播放的一组最可能的音高。熟悉的主要和次要标度具有预设模式。因此,分析大量音乐将为我们提供在如此多的歌曲中使用的每个键中的每个音符的统计值。然后,通过简单地计算包含样本语料库中的音调的音乐的语料库,可以将这些直方图数字转换为概率模型。这将构成训练数据集。因此,给定来自测试语料库的任何歌曲的输入序列,音乐的分段识别部分 - 例如4个小节或任何其他优化的音乐单元,可以立即搜索概率分数列表,并且在将每个音调概率相乘后得出最高分数将给出我们最有可能的关键指示。贝叶斯规则在统计分布中使用概率搜索模式非常好,其中变量是依赖的,可以作为前一个变量的结果发生。这使其对预测和分类目的非常有吸引力。
概率的一个比较好的定义是将其表示为数学函数,其中它将变量作为相应输出的输入,其表示该变量具有输入值的概率或概率。输出必须在0和1之间。因此概率可以表示为0。分布将简单地是输入变量的所有值的单个概率的集合。
熟悉的摇骰子的例子很好地说明了某一面朝上的结果的概率。对于立方体的每一侧,分配一个数字,因此单个骰子的变化总数为6,我们可以将单个数字的集合表示为样本集。
S1 = {1,2,3,4,5,6}
对于每次投掷,我们都对顶部立方体上的数字感兴趣。样本空间中只能有一个这样的数字。因此,样本集中每个数字的个体概率将是每个投掷的样本集内的任何一个数字。鉴于骰子是平衡的,所有数字的个体概率相等。因此概率之和为1,P(1)= 1/6,P(2)= 1/6等。每种情况下分子将是唯一值。这个组合的个体概率将是分布。在这种情况下,由此获得的分数的总和必须等于1(1/6 X 6等于1)。
在第二种情况下,假设我们有两个骰子A和B,并且我们想知道基于一个骰子摇到1的前提下,第二次摇到骰子为2的概率。这里的变量是完全独立的。这将在维恩图中表示为两个概率A和B的交点。在这种情况下,单个概率简单地相乘。
进入相互依赖变量的更相关场景将我们带入贝叶斯规则。用最简单的术语来说,当将定义重新定义为恶意软件分类时,它是给定BINARY的CLASS的概率。由P(CLASS | BINARY)代表。CLASS可以表示MALWARE和BENIGN这两种主要类型。“| ”符号可以理解为'给定'。可以证明 -
P(CLASS | BINARY)与P(BINARY | CLASS)* P(CLASS)成正比
这里P(CLASS)是先验概率,P(CLASS | BINARY)是后验概率。这些参数非常重要,尤其是先前值,因为它给出了整个样本集中得到的CLASS的统计偏差。
证明是合乎逻辑的。这里条件质量表示为我们想要知道给定二进制文件的类型并尝试确认它是恶意软件还是良性软件。
因此,我们得到CLASS中的类型并计算每个类型的概率:
P(BENIGN | BINARY)= P(BINARY | BENIGN)P(BENIGN)
P(MALWARE | BINARY)= P(BINARY | MALWARE)P(MALWARE)
由于值是成比例的,我们只需比较两个值并将更大的值指定为最终结果。
对于我们的目的而言,这都是有条件的概率。其他技术如回归和排名将在后续文章中介绍。隐马尔可夫模型的其他有趣主题,也涉及概率及其预测用法,将需要这作为前体。
为了对一组Android二进制文件进行分类,我为初步分类采用的方法涉及使用公开可用的研究数据集。此外,统计相关的研究数据对我们的目的是有用的。这里有一个1260个恶意软件的Android Genome Project数据集。其中一个图表表示1260个恶意软件和1260个良性Android应用程序中的权限直方图。这对于NaïveBayes分类的第一阶段来说是非常好的测试集。我们假设先验概率并调整值以获得正确的分类。前20个权限是根据具有此权限的1260个恶意软件集中的恶意软件数量绘制的。这正是我们已经完成的数据过滤。不可否认,在我自己的Android恶意软件集合上重新运行Android权限提取代码,然后在一组Android合法应用程序上,我得到了99%的准确率。代码提取完整的权限并将其存储在列表中,并在样本集完成后按降序排序,以便为每个样本集提供前20个权限。
关于贝叶斯规则,计算引入的另一件事是将变量集内的每个概率相乘。将其应用于我们获得的权限直方图,我们只需获取包含每个权限的列表(通过获取该权限的恶意软件数量/集合中的恶意软件总数)。重复并冲洗良性收集。
我们得到的是2个列表,其中包含恶意软件和合法.apk文件的前20个权限中的每一个的概率。获得正确代码的第一步是为每个概率分布编写C#枚举器。下面的每个枚举都从int数据类型继承,表示所有数值都是整数类型。枚举声明采用以下格式 -
enum {}
枚举是一种为常量命名的方法。这里为每个权限字符串分配一个整数值。调用名称时,可以将它们类型化为int。此处,各样本集中每个权限的恶意软件频率的格式为 -
PERMISSION_NAME = FREQUENCY (COUNT OF FILES IN THE SAMPLE SET)
public enum perm20 : int{
INTERNET = 1232,
READ_PHONE_STATE=1179,
ACCESS_NETWORK_STATE = 1023,
WRITE_EXTERNAL_STORAGE=847,
ACCESS_WIFI_STATE=804,
READ_SMS=790,
RECEIVE_BOOT_COMPLETED=688,
WRITE_SMS=658,
SEND_SMS=553,
RECEIVE_SMS=499,
VIBRATE=483,
ACCESS_COARSE_LOCATION=480,
READ_CONTACTS=457,
ACCESS_FINE_LOCATION=432,
WAKE_LOCK=425,
CALL_PHONE=424,
CHANGE_WIFI_STATE=398,
WRITE_CONTACTS=374,
WRITE_APN_SETTINGS=349,
RESTART_PACKAGES=333
}
public enum perm20Benign : int {
INTERNET=1122,
ACCESS_NETWORK_STATE=913,
WRITE_EXTERNAL_STORAGE=488,
READ_PHONE_STATE=433,
VIBRATE=287,
ACCESS_FINE_LOCATION=285,
ACCESS_COARSE_LOCATION=263,
WAKE_LOCK=218,
RECEIVE_BOOT_COMPLETED=137,
ACCESS_WIFI_STATE=134,
CALL_PHONE=114,
CAMERA=73,
READ_CONTACTS=71,
GET_TASKS=60,
GET_ACCOUNTS=54,
SET_WALLPAPER=49,
SEND_SMS=43,
WRITE_SETTINGS=39,
CHANGE_WIFI_STATE=34,
RESTART_PACKAGES=33
}
实际计算只涉及将每个Android文件中的权限集相乘,计算每个恶意软件的每个权限集的贝叶斯概率,并对良性集重复相同。
CAVEAT:划分训练集和测试集非常重要,以确保测试是最佳的,并且培训不会过度拟合。也就是说它只适用于训练集而不是现实世界数据。因此,调整必须通过将样本集分成训练和测试数据集来完成。这对于任何机器学习过程都是必须的,无论它们是神经网络还是贝叶斯分类器。
计算函数看起来像这样 -
public void setScore(List p) {
intmalIdx = 0; intgoodIdx = 0;
for each (perm20 mal in Enum.GetValues(typeof(perm20)))
{
foreach (string l in p ){
stringtmp = getUpper(l);
if (tmp.Contains(mal.ToString()))
{
malScore *= (float.Parse(((int)mal).ToString())/ 1260);
//above does the probability multiplication
PermCount++;
mar[malIdx] = 1; //hit flagger for viz
}
} malIdx++;
}
foreach (perm20Benign good in Enum.GetValues(typeof(perm20Benign)))
{
foreach (string l in p)
{
if (getUpper(l).Contains(good.ToString()))
{
benignScore *= (float.Parse(((int)good).ToString()) / 1260);
ben[goodIdx] = 1;
}
} goodIdx++;
}
一个实用函数,用于从枚举值中获取大写字符:
private string getUpper(string a) {
char[] c = a.ToCharArray();
StringBuilder s = new StringBuilder();
foreach (char f in c) {
if (Char.IsUpper(f) || f=='_') { s.Append(f); }
}
returns.ToString();
}
注意到其他研究数据,我包括了权限计数以及后期分析值,以便做出最终决定。
intPermCount = 0;
publicint COUNT {
get {return PermCount;}
}
归一化:在此阶段可能不需要,但是使用各种方法完成范围表示或标准化。sigmoid表示用于标准化正值。如果需要负值或更具体地说需要双极性表示,则使用双曲线函数代替。在许多情况下,最好从简单地取一个特定范围的值的倒数开始。这实际上将整个范围归一化为0到1的值。
双曲线
倒数
我将最终得分变量初始化为浮点数据类型。
表示概率范围最好用0到1的值来完成,并且因为在乘以浮点数之后中间值将非常小。
floatmalScore=0.001f;
floatbenignScore=0.001f;
string verdict = String.Empty;
下面的这些属性用于将值返回到另一个类。
public string VERDICT { get { return verdict; } }
public double MALSCORE { get { return malScore; } }
public double GOODSCORE { get { return benignScore; } }
我还使用了两个整数数组来初始化权限可视化,以便以后在需要时进一步显示。它们将前20个权限存储为命中标志集。每次点击1次,空地点0次。它们各自的属性也被初始化以供以后调用。
int[] mar = new int[20];
int[] ben = new int[20];
publicint[] MALVIZ {
get { return mar; }
}
publicint[] BENVIZ {
get { return ben; }
}
所有上述代码都可以封装在C#类中,并为模块化使用做好准备。该类名为bayesClassifier.cs。
在发生大量提取的另一个类中,IO函数将训练集中每个文件的计算值写入当前目录中名为stats.txt的文件中。请记住使用每个样本集的一半。保持另一半用于testing.IO()获取从bayesClassifier.cs计算的两个值。虽然IO()函数有两个字符串,但我目前提供文件大小和权限计数以及恶意软件贝叶斯概率和良性概率字符串。
bayesClassifier.cspS = new bayesClassifier.cs(); //instance of the permissionScore class
pS.setScore(_MANSET[idx]._PERMSET); // setScore() called passing extracted permissions string list.
IO(pS.COUNT.ToString() + "," + _FILEPROPS[0].FILESIZE.Substring(0, _FILEPROPS[0].FILESIZE.Length-6) + "," + pS.MALSCORE.ToString(), pS.GOODSCORE.ToString());
private void IO(string malScore, string benignScore)
{
using (FileStreamfs = new FileStream(Environment.CurrentDirectory + "\\stats.txt", FileMode.Append, FileAccess.Write))
{
using (StreamWritersw = new StreamWriter(fs))
{
sw.WriteLine(malScore + "," + benignScore);
}
}
}
运行一半的恶意软件和良性样本集合为我们提供了一组csv数据,可以对模式和分数进行调查,以进一步调整测试集的分类。
应该提醒您本练习的“Naïve”部分的事情是在概率乘法完成后在bayesClassifier.cs代码中设置的以下值。
benignScore * = 0.80f;
malScore * = 0.20f;
这些是基于合法与恶意软件应用程序的整体空间统计假设的每个样本集的先验概率。在提供正确的分类之前,可能需要调整此值。良性应用程序的值为0.80表示假设Android应用程序空间中约80%的应用程序是合法应用程序,而恶意软件约占总数的20%。
最终stats.txt中的3行摘录在500个恶意软件样本上运行 -
计数 | 尺寸 | MAL_BAYES_PROBABILITY | BENIGN_BAYES_PROBABILITY |
8 | 1860822 | 2.80749645753531E-06 | 3.45789041844569E-09 |
4 | 48869 | 2.28490225708811E-05 | 9.41584949032404E-06 |
您可以立即看到恶意软件概率值大于同一恶意软件样本的计算良性概率。在良性集上重新执行此操作也会提供有趣且预期的数据集。有关这方面的更多信息以及下一篇文章中的数据集参数的进一步调整。
如果你以实际的方式接近它,机器学习就不会令人生畏。源于统计和概率,贝叶斯定理的应用已经像野火一样流行起来,并且有一个原因 - 一旦数据被正确地策划,它就能很好地工作。您已经了解了NaïveBayes定理的基本原理,并对条件概率进行了概述。
您还逐步了解了贝叶斯规则对Android恶意软件检测和分类的实施,这是迈向工作分类引擎的初步步骤。
在下一部分中,我将讨论构建Android恶意软件分析器的其他机器学习方法,同时利用从本练习中收集的数据。垃圾邮件检测是另一个很好的例子,将在下一篇文章中讨论,作为恶意软件分析和安全研究的这一系列机器学习基础的延续。