病毒检测是一个常见的模式识别问题。传统的病毒检测方式以病毒特征码为基础,对文件进行特征匹配。这样的检测方式不能很好的检测未知病毒。未知病毒的特征码尚未纳入特征码数据库,所以不能立即识别。杀毒软件厂商需要对病毒进行分析,然后才能防御该未知病毒的攻击。这样的模式不利于现今的网络环境,最近基于机器学习的检测方法被提出,并显示出了良好的效果。仅做病毒检测的准确率已经达到了99%以上。
常见的机器学习方法一般为特征提取->数据分析建模。本文的主要内容为病毒的N-gram特征提取系统。N-gram特征常见于自然语言处理中,现在我们将该特征引入病毒检测问题。N-gram需要将n个词连起来作为一个特征。病毒中一个词即一个bit序列,一般取4-bit为一个gram。4bit即hex编码,可用DumpHex软件提取hex编码。N-gram特征以此有重复地提取n个hex作为一个特征,比如有hex序列:ff
00 22 32 3a,那么可以得到4-gram: ff 00 22 32 和 00 22 32
3a。每个4-gram特征含有4byte。然后我们依据每个特征与分类类别的互信息值进行特征提取(互信信息恒大于零):
IG[j]=∑vj=0.1∑CP(vj,C)log(P(vj,C)/(P(vj)P(C)))
其中$P(v_j,C)$表示j特征为vj且类别为C的概率(占所有文件的比例),$P(v_j)$表示j特征为vj的概率,$P(C)$为类别C的概率,如果IG值为0,表示不相关;越大相关性却强。
我们选取IG值最大的几个特征(例如,我们选取500个)。
一般上病毒的数据集比较大,几百MB到几十GB不等,其中几乎包括所有的N-gram(该实验中,N=4)。内存将无法存储所有的特征信息,因为最差的情况下,总共有1<<32个不同的4-gram。所以我采取分块处理的方式,将N-gram分为256个batch,batch
i 处理前缀为 i 的特征,将这批特征的最大500个存入文本。256个子处理程序运行完成后,再结合256个文本中的数据,产生最后的特征。
这里,即使每个batch只处理1<<24个n-gram,我们仍难以对这些n-gram进行排序。同样的,我将这些数据分而治之。
Java编程技术
因为这是我第一次用Java编写较完整的项目,所以这次编程编写得比较艰难,Java与C++还是有比较大的出入。下面记录编程过程中出现的问题,供以后查看。
- 数组不能直接在申明的时候定义,即不能 int a[10];
- 对象数组申明之后,让要对数据中的每个对象进行创建操作,sArray[i] = new String();
- >>>表示无符号位移。
- FileInputStream用于输入字节流,Scanner也可用于文本数据读取。PrintWriter用于文本流输出。
- File类型不用close,其length()方法可以得到文件的大小(byte)。
- Java中将char数组转换成String时,将会拷贝所有内容,而不是遇\0停止。
- 排序可用Array.sort(array, new Comparator()){ public int compare(... ...
- new
File("")得到当前文件夹,getAbsolutePath得到绝对路径。File.getSeperator是静态方法,可以得到该系统的路径分割符。file.listFiles可以得到路径下的所有文件。 - <<操作符的优先级比=低,尽量都加()。
类间处理进度消息传递
在软件编写过程中,我们可能会碰到这样的情况:A是界面类,B为处理类。A在交互过程中会触发B,B可能是个耗时的任务,所以A要输出B的处理进度。(一般上处理进程与界面进程要分开,这个内容放在后面讲。)这时,我们要对B设定一个Listener,监听B处理的进度。具体的参照如下代码
A中B(WorListBuilder)触发代码: WordListBuilder wordListBuilder = new
WordListBuilder(500, benignFilePath, malwareFilePath);
wordListBuilder.setOnProcessingListener(new OnProcessingListener(){ @Override
public void onProgress(int progress) { informationPresenter.append("Batch:" +
progress + " is being processed.\n"); } }); B中代码: public class WordListBuilder
extends Thread{ WordListBatchBuilder batchbuilder; public interface
OnProcessingListener{ public void onProgress(int progress); } public
OnProcessingListener mOnProcessingListener; public void
setOnProcessingListener(OnProcessingListener onProcessingListener){
mOnProcessingListener = onProcessingListener; } ..... 这样就能使用回调函数监听B内的消息了。
Java多线程初步
继承runnable共享类内数据。扩展thread不共享类内数据。 thread建议用start函数启动,建议使用runnable接口。
编程风格注意要点
- 程序中尽量不要出现数字。
- 相同的代码封装成函数,便于修改。
- 函数功能要单一。
- for循环的下标尽量有意义。