An open API service indexing awesome lists of open source software.

https://github.com/explangcn/aliyun_malwaredetection

阿里云-安全恶意程序检测
https://github.com/explangcn/aliyun_malwaredetection

Last synced: 5 months ago
JSON representation

阿里云-安全恶意程序检测

Awesome Lists containing this project

README

          

# Aliyun_MalwareDetection

# 阿里云-安全恶意程序检测

## 赛题说明

赛题链接:[阿里云:安全恶意程序检测](https://tianchi.aliyun.com/competition/entrance/231694/information)

代码仓库:[阿里云-安全恶意程序检测--代码仓库](https://github.com/wxydaydayup/Aliyun_MalwareDetection/tree/master)

### 一、背景介绍

恶意软件是一种被设计用来对目标计算机造成破坏或者占用目标计算机资源的软件,传统的恶意软件包括蠕虫、木马等,这些恶意软件严重侵犯用户合法权益,甚至将为用户及他人带来巨大的经济或其他形式的利益损失。近年来随着虚拟货币进入大众视野,挖矿类的恶意程序也开始大量涌现,黑客通过入侵恶意挖矿程序获取巨额收益。当前恶意软件的检测技术主要有特征码检测、行为检测和启发式检测等,配合使用机器学习可以在一定程度上提高泛化能力,提升恶意样本的识别率。

### 二、任务介绍

本题目提供的数据来自文件(windows 可执行程序)经过沙箱程序模拟运行后的API指令序列,全为windows二进制可执行程序,经过脱敏处理。
其中恶意文件的类型有感染型病毒、木马程序、挖矿程序、DDOS木马、勒索病毒等,数据总计6亿条。

### 三、数据集

1、训练数据(train.zip):调用记录近9000万次,文件1万多个(以文件编号汇总)

+ 一个文件调用的api数量有可能很多,对于一个tid中调用超过5000个api的文件,我们进行了截断,按照顺序保留了每个tid前5000个api的记录。

+ 不同线程tid之间没有顺序关系,同一个tid里的index由小到大代表调用的先后顺序关系。
注3:index是单个文件在沙箱执行时的全局顺序,由于沙箱执行时间有精度限制,所以会出现一个index上出现同线程或者不同线程都在执行多次api的情况,可以保证同tid内部的顺序,但不保证连续。

2、测试数据(test.zip):调用记录近8000万次,文件1万多个。

说明:格式除了没有label字段,其他数据规格与训练数据一致。

### 四、字段说明

train.csv和test.csv字段说明

| 字段 | 类型 | 解释 |
| ------- | ------ | ------------------------------------------------------------ |
| file_id | bigint | 文件编号 |
| label | bigint | 文件标签,0-正常/1-勒索病毒/2-挖矿程序/3-DDoS木马/4-蠕虫病毒/5-感染型病毒/6-后门程序/7-木马程序 |
| api | string | 文件调用的API名称 |
| tid | bigint | 调用API的线程编号 |
| index | string | 线程中API调用的顺序编号 |

## BaseLine V1_lgb--分数: 0.715840

### 一、数据探索

**写法1**

Pandas使用chunksize分块处理大型csv文件,加载数据

```python
import pandas as pd
# 分段数据加载基础方法
def get_data(file_name):
result = []
chunk_index = 0
for df in pd.read_csv(open(file_name, 'r'), chunksize = 1000000):
result.append(df)
chunk_index += 1
result = pd.concat(result, ignore_index=True, axis=0)
return result

#数据加载
train = get_data('./security_train.csv')
test = get_data('./security_test.csv')

#将数据采用pickle方式存储,加快文件的读取速度
import pickle
with open('./train.pkl', 'wb') as file:
pickle.dump(train,file)
with open('./test.pkl', 'wb') as file:
pickle.dump(test,file)
with open('./train.pkl', 'rb') as f:
train = pickle.load(f)
with open('./test.pkl', 'rb') as f:
test = pickle.load(f)
```

**写法2**

```python
# 获取读文件指针
data=pd.read_csv(filename, iterator=True)
# 顺序读取100000行数据
chunk = data.get_chunk(100000)
```

查看内存使用情况

```python
import os
import psutil
mem = psutil.virtual_memory()
print('总内存:',mem.total/1024/1024)
print('已使用内存:',mem.used/1024/1024)
print('空闲内存:',mem.free/1024/1024)
print('使用占卜:',mem.percent)
print('当前线程PID:',os.getpid())
```

查看某个变量的资源使用情况

```python
import sys
sys.getsizeof(df_all)/1024/1024
```

针对不同的变量,进行内存释放

### 二、特征工程

对File_id做聚合处理,并去重操作和使用统计特征,主要包括数量,最大值,最小值,平均值,并保存下来

1. 去除完全重复的行数据

```python
data.drop_duplicates(inplace=True)
```

2. 去除某几列重复的行数据

```python
data.drop_duplicates(subset=['A','B'],keep='first',inplace=True)
```

+ subset: 列名,可选,默认为None
+ keep: {‘first’, ‘last’, False}, 默认值 ‘first’
+ first: 保留第一次出现的重复行,删除后面的重复行。
+ last: 删除重复项,除了最后一次出现。
+ False: 删除所有重复项。
+ inplace:布尔值,默认为False表示生成一个副本,inplace=True表示直接在原来的DataFrame上删除重复项。

```python
#定义重要特征,主要包括数量,最大值,最小值,平均值等等
def get_features(df):
df_file = df.groupby('file_id')
if 'label' in df.columns:
df1 = df.drop_duplicates(subset=['file_id', 'label'], keep='first')
else:
df1 = df.drop_duplicates(subset=['file_id'], keep='first')
df1 = df1.sort_values('file_id')
features = ['api', 'tid', 'index']
for f in features:
df1[f+'_count'] = df_file[f].count().values
df1[f+'_nunique'] = df_file[f].nunique().values
df1[f+'_min'] = df_file[f].min().values
df1[f+'_max'] = df_file[f].max().values
df1[f+'_mean'] = df_file[f].mean().values
df1[f+'_median'] = df_file[f].median().values
df1[f+'_std'] = df_file[f].std().values
df1[f+'_ptp'] = df1[f+'_max'] - df1[f+'_min']
return df1
#训练集与测试集添加特征
df_train = get_features(train)
df_test = get_features(test)
#将特征的结果集保持,一遍后续直接使用
df_train.to_pickle('.df_train.pkl')
df_test.to_pickle('./df_test.pkl')
```

### 三、建立模型

```python
import lightgbm as lgb
import pandas as pd
clf = lgb.LGBMClassifier(num_leaves=2**5-1,reg_alpha=0.25,reg_lambda=0.25,objective='multiclass',
max_depth=-1,learning_rate=0.005,min_child_sample=3,random_state=2021,
n_estimators=2000,subsample=1,colsample_bytree=1)
#,device= gpu,gpu_platform_id=0,gpu_device_id = 0)

clf.fit(df_train.drop(['label'],axis=1),df_train['label'])

result = clf.predict_proba(df_test)
result_lgb = pd.DataFrame(result, columns=['prob0','prob1','prob2','prob3','prob4','prob5','prob6','prob7'])
result_lgb['file_id'] = df_test['file_id'].values
columns=['file_id','prob0','prob1','prob2','prob3','prob4','prob5','prob6','prob7']
result_lgb.to_csv('./baselineV1.csv',index=False,columns = columns )
print("已完成")
```

## BaseLine V2_lgb--分数: 0.715840

## 一、特征工程优化

针对file_id 按照线程tid 和 顺序index进行排序 , 并拼接成字符串

```python
def get_apis(df):
# 按照file_id进行分组
group_fileid = df.groupby('file_id')
# 统计file_id 和对应的 api_sequence
file_api = {}
# 计算每个file_id的api_sequence
for file_id, file_group in group_fileid:
# 针对file_id 按照线程tid 和 顺序index进行排序
result = file_group.sort_values(['tid', 'index'], ascending=True)
#得到api的调用序列
api_sequence = ' '.join(result['api'])
#print(api_sequence)
file_api[file_id] = api_sequence
return file_api

train_apis = get_apis(train)
test_apis = get_apis(test)
```

将文本信息与BaselineV1中的统计特征合并

```python
import pandas as pd
with open('./df_train.pkl', 'rb') as file:
df_train = pickle.load(file)

with open('./df_test.pkl', 'rb') as file:
df_test = pickle.load(file)

df_train.drop(['api','tid','index'],axis=1,inplace=True)
df_test.drop(['api','tid','index'],axis=1,inplace=True)

temp = pd.DataFrame.from_dict(train_apis, orient='index', columns=['api'])
temp = temp.reset_index().rename(columns={'index': 'file_id'})
df_train = df_train.merge(temp, on='file_id', how='left')
temp = pd.DataFrame.from_dict(test_apis, orient='index', columns=['api'])
temp = temp.reset_index().rename(columns={'index': 'file_id'})
df_test = df_test.merge(temp, on='file_id', how='left')

df_all = pd.concat([df_train, df_test], axis=0)

```

放入TfidfVectorizer做训练

```python
from sklearn.feature_extraction.text import TfidfVectorizer
#使用1-3元语法(1元语法 + 2元语法 + 3 元语法)
vec=TfidfVectorizer(ngram_range=(1,3),min_df=0.01)
api_features=vec.fit_transform(df_all['api'])

df_apis = pd.DataFrame(api_features.toarray(), columns=vec.get_feature_names())
df_apis.to_pickle('./df_apis.pkl')
df_apis
```

将tfidf特征 与原特征进行合并

```python
df_train_apis=df_apis[df_apis.index<=13886]
df_test_apis=df_apis[df_apis.index>13886]
#将tfidf特征前面的索引重新开始
df_test_apis.index=range(len(df_test_apis))

# 将tfidf特征 与原特征进行合并
df_train = df_train.merge(df_train_apis, left_index=True, right_index=True)
df_test = df_test.merge(df_test_apis, left_index=True, right_index=True)

#去掉object类型api后保存
df_train.drop('api', axis=1, inplace=True)
df_test.drop('api', axis=1, inplace=True)
df_train.to_pickle('./df_train2.pkl')
df_test.to_pickle('./df_test2.pkl')
```

## BaseLine V3_lgb&xgb--分数: 0.715840

### 一、模型融合

#### 1、lightgbm与xgboost做模型融合

```python
import xgboost as xgb
model_xgb = xgb.XGBClassifier(
max_depth=5, learning_rate=0.005, n_estimators=3250,
objective='multi:softprob', tree_method='gpu_hist',
subsample=0.8, colsample_bytree=0.8,
min_child_samples=3, eval_metric='logloss', reg_lambda=0.5)
model_xgb.fit(df_train.drop('label', axis=1), df_train['label'])
result_xgb = model_xgb.predict_proba(df_test)
result_xgb = pd.DataFrame(result_xgb, columns=['prob0','prob1','prob2','prob3','prob4','prob5','prob6','prob7'])
result_xgb['file_id'] = df_test['file_id'].values

# 对两个模型的结果 进行加权平均
result = result_lgb.copy()
weight_lgb, weight_xgb = 0.5, 0.5
result['prob0'] = result['prob0'] * weight_lgb + result_xgb['prob0'] * weight_xgb
result['prob1'] = result['prob1'] * weight_lgb + result_xgb['prob1'] * weight_xgb
result['prob2'] = result['prob2'] * weight_lgb + result_xgb['prob2'] * weight_xgb
result['prob3'] = result['prob3'] * weight_lgb + result_xgb['prob3'] * weight_xgb
result['prob4'] = result['prob4'] * weight_lgb + result_xgb['prob4'] * weight_xgb
result['prob5'] = result['prob5'] * weight_lgb + result_xgb['prob5'] * weight_xgb
result['prob6'] = result['prob6'] * weight_lgb + result_xgb['prob6'] * weight_xgb
result['prob7'] = result['prob7'] * weight_lgb + result_xgb['prob7'] * weight_xgb
columns = ['file_id', 'prob0','prob1','prob2','prob3','prob4','prob5','prob6','prob7']
result.to_csv('./baselineV3.csv', index=False, columns=columns)
```
**全部代码已放代码仓库:**[阿里云-安全恶意程序检测--代码仓库](https://github.com/wxydaydayup/Aliyun_MalwareDetection/tree/master)