基于NLP的威胁检出引擎
huoji 历史精选 4293浏览 · 2022-03-25 15:38

NLP引擎出自于我的一个简单的想法 - 既然人可以通过汇编看出软件是否是病毒 那么机器是否可以通过汇编看呢?

为了让机器能看得懂代码,我首先想到的是非常经典的NLP分类问题,所谓的NLP分类问题,就是训练的时候给一堆词语+词频,推理的时候先把句子中的词语分出来,再然后计算这些词语的词频,最后得出这条句子属于什么类别的结论

v1.0

为了验证我的猜想,我使用了capstone作为反汇编引擎,将单个汇编向量化,结果如下:

之后,我提取了10w个样本的.text段,并且将他们以一个单词一个单词的作为分割,也就是说,一个汇编作为一个单词,而一句话为一个程序。这样就可以被tf-idf转化后送入神经网络.
举个例子:

部分代码如下

from sklearn.model_selection import train_test_split, GridSearchCV, KFold

tf_idf_transformer = TfidfTransformer()
vectorizer = CountVectorizer(max_features=5000)
y = np.array(list(csv_data.label.values))
x_data = np.array(list(csv_data.Data.values))
tf_idf = tf_idf_transformer.fit_transform(
    vectorizer.fit_transform(csv_data['OpCode']))
x_train_weight = tf_idf.toarray()

之后送到xgboost里面,之所以使用xgboost是因为以后方便移植.

model = XGBClassifier(**{"n_estimators":300,"max_depth":8})
model.fit(X_train, y_train, eval_set=[(X_train, y_train), (X_test, y_test)], early_stopping_rounds=5, verbose=True)

效果如下:

嗯...对整体模型毫无帮助...
所以问题出在哪? 哪里遇到了问题?

问题出在哪

经过测试,直接送入汇编代码存在的问题包括不限于:

  1. 机器视角能用于做特征的非常少
  2. 没有全局意义,比如push eax 只看push eax没有任何意义

为了解决这个问题,我们需要做语句切割,提取具体含义的代码块,而不是单个汇编

语句切割

我们的要做的这个NLP学习引擎不同于用VM的切割.并且我们不需要考虑去混淆、去虚拟化之类的.只是简单的分片.但是我们会面临一个巨大的问题: 压根不知道从哪开始切片,从哪结束切片.

因此我们需要引入一些简单的逻辑去解决他

为了分割词语,我们需要定义这个 语句 所影响的范围,如 push eax 所造成的影响是esp/rsp,而mov eax,ebp影响的是eax

我们简单的定义一下会造成影响的指令:

push

mov

xor

add

sub

...

我们简单定义一下会消除影响的指令:

pop

mov

sub

add

test

....

那么问题就简单了,所谓的分片 就是 寻找出 有影响 <--> 消除影响的对应关系,此外我们不是追踪控制流,我们需要规定边界,一旦触及,则启用 "激励机制":

jmp

test

jnz

ret

....

"激励"机制是为了划分出 "边界"后,在边界外寻找的一种机制.诺找不到/找到下一段影响,则回滚到边界.诺找到无影响/消除影响 则加入.

这是一个简单的例子:

在这个例子中,我们就能获取一段具有实际意义的切片:

mov
mov
mov
mov
mov
mov
call
test
jz

很明显,我们得到了类似于下面的代码的三个切片:

切片1:

a[0] = 1;
a[1] = 2;
a[2] = 3;
if (!function_unk_1()) {
    .....
}

切片2:

a[0] = 1;
a[1] = 2;
a[2] = 3;

切片3:

int x = X;
if (!function_unk_2(x)) {
    ....
}

现在 我们就具有了代码识别能力,如此反复,就会得到类似于如下的数据:

now....

v2.0

把程序想象成一段话 把我们提取的汇编想象成一个单词.现在我们就有把一句话拆分成单词的能力了:

现在只需要跟传统NLP一样,但值得注意的是,我们不再需要CountVectorizer的分词,直接送入tf-idf就行了.

这是我使用500个黑文件 500个白文件训练的结果:

Accuracy: 87.74%

请记住,NLP需要大量的样本训练,同时提词的时间复杂度很高,就1000个文件在我的垃圾电脑上跑了几个小时才出结果.

但是,在实际测试的时候,这个识别的效果挺让我震惊的:

100%|██████████| 1102/1102 [08:32<00:00,  2.15it/s]
扫描的文件总数 927 是病毒的文件总数 428

效果看起来还不错(虽然只有40%左右的识别率,但是因为样本数量严重不足+词库严重不足的情况下).

后续让我们来优化它....

0 条评论
某人
表情
可输入 255
目录