草庐IT

CNN+LSTM:智能合约漏洞检测

安静的秃头怪 2023-09-21 原文

今天记录一下最近将深度学习方法用于智能合约漏洞检测的第一次实验,顺便给研究这方向的同行们提供一点借鉴意义。这个方法跟NLP有点相似,但又不太一样,因为操作码序列虽然具备一定语义信息,但偏向底层机器语言,所以刚开始我并不确定最终能不能达到很好的训练效果。这个实验的完整过程如下:首先通过插桩在本地链上同步当前以太坊的部分区块交易数据,借此拿到每笔交易的操作码序列、合约地址等等原始数据;接着通过word2vec或one-hot编码将每个操作码转成词向量;最后搭建CNN+LSTM的深度学习模型完成多分类训练。


0. 导包

from keras.models import Sequential

from keras.layers import Dense, Dropout

from keras.layers import Embedding

from keras.layers import LSTM

from keras.layers import Convolution1D, MaxPooling1D

from keras.saving.save import load_model

from keras.utils import to_categorical

import gensim

from gensim.models import word2vec

import tensorflow as tf

import numpy as np

import pickle as pkl

from gensim.corpora.dictionary import Dictionary

from sklearn.model_selection import train_test_split

import pandas as pd

from tensorflow.keras.preprocessing import sequence

import matplotlib.pyplot as plt

import logging

1. 从数据库获取数据

我使用的是MongoDB数据库,因此可以使用可视化软件MongoDB CompassNavicat for MongoDB直接查询获取,同样也可以通过python连接数据库获取,本质上都是编写MongoDB的查询语句,导出格式一般是csv或txt,csv因为携带了标签比较容易处理。

# 连接数据库

client = MongoClient('mongodb://admin:123456@172.22.60.69:27017/')

db = client.geth

# 获取对应数据库表的对象

collection = db.transaction

i = 0

for collection in collection.find({}, {"tx_trace": 1, "_id": 0}):

    i = i + 1

    with open('./trace.txt', 'a') as f:

        f.write(collection.get('tx_trace'))

        f.write('\n')

    if i == 3685499:

        break

2. 训练词向量

对于文本的向量化其实有很多方式,包括独热(one-hot)词袋模型(bag of words)逆文本特征频率(tf-idf)word2vec等,在本实验中我使用现成的word2vec预训练模型直接训练得到词向量,同样也可以用自己搭建的模型训练。word2vec是使用深度学习的方式将词映射为一个多维向量,维度可以自行选择。

# 设置输出日志

logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)

# 直接用gemsim提供的API去读取txt文件,读取文件的API有LineSentence和Text8Corpus, PathLineSentences等。

sentences = word2vec.LineSentence("./trace.txt")

print("*****************")

# 训练模型,词向量的维度设置为128,迭代次数为8,采用skip-gram模型,模型保存为bin格式,并发数为5

model = gensim.models.Word2Vec(sentences, vector_size=128, sg=1, epochs=8, min_count=1, negative=8, workers=5)

model.save("word2vec1.model")

model.wv.save_word2vec_format("./word2vec1.bin", binary=True)

# 加载bin格式的模型

model1 = gensim.models.KeyedVectors.load_word2vec_format("word2vec1.bin", binary=True)

model1.save_word2vec_format('./vector1.txt', binary=False)

3. 数据预处理

读取csv或txt格式的原始数据并处理成嵌套列表的形式。

# 读取csv源数据并处理成嵌套列表格式

def csv_to_trace_list(csv_path, trace_list1):

    trace = pd.read_csv(csv_path, usecols=['tx_trace'])

    # 将DataFrame转成list

    p_list = np.array(trace).tolist()

    # 将每个序列分词并转成list,并将每个list存入trace_list1,此时trace_list1为嵌套列表

    for i in p_list:

        trace_list1.append(i[0].split())

4. 根据词向量创建词语字典

加载上面生成的word2vec模型创建出对应的词向量字典(操作码向量字典)。

def create_dictionaries(model1):

    # 创建词语字典,并返回word2vec模型中词语的索引,词向量

    gensim_dict = Dictionary()  # 创建词语词典

    gensim_dict.doc2bow(model1.wv.index_to_key, allow_update=True)

    w2index = {v: k + 1 for k, v in gensim_dict.items()}  # 词语的索引,从1开始编号

    w2vec = {word: model1.wv[word] for word in w2index.keys()}  # 词语的词向量

    return w2index, w2vec

model = word2vec.Word2Vec.load("word2vec1.model")

index_dict, word_vectors = create_dictionaries(model)  # 索引字典、词向量字典

5. 将序列文本转成字典索引数字

将输入操作码序列中出现在词向量字典中的操作码转换为索引数字,未出现的转换为0即可。

def text_to_index_array(p_new_dic, p_sen):

    # 文本或列表转换为索引数字

    if type(p_sen) == list:

        new_sentences = []

        for sen in p_sen:

            new_sen = []

            for word in sen:

                try:

                    new_sen.append(p_new_dic[word])  # 单词转索引数字

                except:

                    new_sen.append(0)  # 索引字典里没有的词转为数字0

            new_sentences.append(new_sen)

        return np.array(new_sentences)  # 转numpy数组

    else:

        new_sentences = []

        sentences = []

        p_sen = p_sen.split(" ")

        for word in p_sen:

            try:

                sentences.append(p_new_dic[word])  # 单词转索引数字

            except:

                sentences.append(0)  # 索引字典里没有的词转为数字0

        new_sentences.append(sentences)

        return new_sentences

6. 统一序列长度

定义必要参数,加载词向量数据并填充词向量矩阵。

# 参数设置

vocab_dim = 128  # 词向量维度

max_len = 5000  # 序列保留的最大长度

batch_size = 100  # 训练过程中每次传入模型的特征数量

n_epoch = 5  # 迭代次数

# Convolution  卷积

filter_length = 3  # 滤波器长度

nb_filter = 64  # 滤波器个数

pool_size = 4  # 池化长度

将原始数据集分为训练集和测试集,把序列操作码转成对应索引并统一长度。

# 划分训练集和测试集,此时都是list列表

X_train_l, X_test_l, y_train_l, y_test_l = train_test_split(trace_list, label_list, test_size=0.2)

x_train = text_to_index_array(index_dict, X_train_l)

x_test = text_to_index_array(index_dict, X_test_l)

y_train = np.array(y_train_l)  # 转numpy数组

y_test = np.array(y_test_l)

# 将不够max_len的用0补足,超过max_len的去掉

x_train = sequence.pad_sequences(x_train, maxlen=max_len)

x_test = sequence.pad_sequences(x_test, maxlen=max_len)

print('训练集shape:', x_train.shape)

print('测试集shape:', x_test.shape)

7. 搭建模型并训练

本来我只用了LSTM,但因为序列长度太大,所以只能加上CNN层来对矩阵进行降维,这样训练速度会更快,结果发现效果也还行。

def train_lstm(p_n_symbols, p_embedding_weights, p_X_train, p_y_train, p_X_test, p_y_test, X_test_l):

    print('创建模型......')

    model = Sequential()

    model.add(Embedding(output_dim=vocab_dim,  # 输出向量维度

                        input_dim=p_n_symbols,  # 输入向量维度

                        mask_zero=True,  # 使我们填补的0值在后续训练中不产生影响(屏蔽0值)

                        weights=[p_embedding_weights],  # 对数据加权

                        input_length=max_len))  # 每个特征的长度

    # 1D 卷积层,对词嵌入层输出做卷积操作

    model.add(Convolution1D(filters=nb_filter,

                            kernel_size=filter_length,

                            activation='relu'))

    # 池化层

    model.add(MaxPooling1D(pool_size=pool_size))

    model.add(LSTM(units=128,

                  activation='sigmoid',

                  recurrent_activation='hard_sigmoid'))

    model.add(Dropout(0.5))  # 每次迭代丢弃50神经元 防止过拟合

    model.add(Dense(units=512,

                    activation='relu'))

    model.add(Dropout(0.5))

    model.add(Dense(units=6,  # 输出层1个神经元 1代表正面 0代表负面

                    activation='softmax'))

    model.summary()

    print('编译模型......')

    model.compile(loss='categorical_crossentropy',

                  optimizer='rmsprop',

                  metrics=['accuracy'])

    print("训练......")

    train_history = model.fit(p_X_train, p_y_train, batch_size=batch_size, epochs=n_epoch,

                              validation_data=(p_X_test, p_y_test))

    print("评估......")

    score, acc = model.evaluate(p_X_test, p_y_test, batch_size=batch_size)

    label = model.predict(p_X_test)

    print('Test score:', score)

    print('Test accuracy:', acc)

    logging.info('Test score: {}'.format(score))

    logging.info('Test accuracy: {}'.format(acc))

    for (a, b, c) in zip(p_y_test, X_test_l, label):

        logging.info("原文为:{}".format(b))

        logging.info("预测倾向为{}".format(a))

        logging.info("真实倾向为{}".format(c))

    """保存模型"""

    model.save('./model_LSTM2.h5')

    print("模型保存成功")

    show_train_history(train_history, 'accuracy', 'val_accuracy')  # 训练集准确率与验证集准确率 折线图

    show_train_history(train_history, 'loss', 'val_loss')  # 训练集误差率与验证集误差率 折线图

8. 输出可视化训练图表

可以通过show_train_history函数打印的训练集曲线来判断模型是否过拟合。

def show_train_history(train_history, train, velidation):

    # 可视化训练过程 对比

    plt.plot(train_history.history[train])

    plt.plot(train_history.history[velidation])

    plt.title("Train History")  # 标题

    plt.xlabel('Epoch')  # x轴标题

    plt.ylabel(train)  # y轴标题

    plt.legend(['train', 'test'], loc='upper left')  # 图例 左上角

    plt.show()


借鉴项目:https://github.com/sph116/lstm_emotion(大家自行搜索)

部分结果截图(仅供参考):

有关CNN+LSTM:智能合约漏洞检测的更多相关文章

  1. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  2. Tomcat AJP 文件包含漏洞(CVE-2020-1938) - 2

    目录1.漏洞简介2、AJP13协议介绍Tomcat主要有两大功能:3.Tomcat远程文件包含漏洞分析4.漏洞复现 5、漏洞分析6.RCE实现的原理1.漏洞简介2020年2月20日,公开CNVD的漏洞公告中发现ApacheTomcat文件包含漏洞(CVE-2020-1938)。ApacheTomcat是Apache开源组织开发的用于处理HTTP服务的项目。ApacheTomcat服务器中被发现存在文件包含漏洞,攻击者可利用该漏洞读取或包含Tomcat上所有webapp目录下的任意文件。该漏洞是一个单独的文件包含漏洞,依赖于Tomcat的AJP(定向包协议)。AJP自身存在一定缺陷,导致存在可控

  3. TimeSformer:抛弃CNN的Transformer视频理解框架 - 2

    Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图

  4. ruby - 检测由 RSpec、Ruby 运行的代码 - 2

    我想知道我的代码是否在rspec下运行。这可能吗?原因是我正在加载一些错误记录器,这些记录器在测试期间会被故意错误(expect{x}.toraise_error)弄得乱七八糟。我查看了我的ENV变量,没有(明显的)测试环境变量的迹象。 最佳答案 在spec_helper.rb的开头添加:ENV['RACK_ENV']='test'现在您可以在代码中检查RACK_ENV是否经过测试。 关于ruby-检测由RSpec、Ruby运行的代码,我们在StackOverflow上找到一个类似的问题

  5. ruby - 使用 Ruby Daemons gem 检测停止 - 2

    我正在使用rubydaemongem。想知道如何向停止操作添加一些额外的步骤?希望我能检测到停止被调用,并向其添加一些额外的代码。任何人都知道我如何才能做到这一点? 最佳答案 查看守护程序gem代码,它似乎没有用于此目的的明显扩展点。但是,我想知道(在守护进程中)您是否可以捕获守护进程在发生“停止”时发送的KILL/TERM信号...?trap("TERM")do#executeyourextracodehereend或者你可以安装一个at_exit钩子(Hook):-at_exitdo#executeyourextracodehe

  6. ruby - Ruby 脚本如何检测到它正在 irb 中运行? - 2

    我有一个定义类的Ruby脚本。我希望脚本执行语句BoolParser.generate:file_base=>'bool_parser'仅当脚本作为可执行文件被调用时,而不是当它被irbrequire(或通过-r在命令行上传递)时。我可以用什么来包装上面的语句,以防止它在我的Ruby文件加载时执行? 最佳答案 条件$0==__FILE__...!/usr/bin/ruby1.8classBoolParserdefself.generate(args)p['BoolParser.generate',args]endendif$0==_

  7. Ruby 无法检测字符串中的换行符 - 2

    我有以下字符串,我想检测那里的换行符。但是Ruby的字符串方法include?检测不到它。我正在运行Ruby1.9.2p290。我哪里出错了?"/'ædres/\nYour".include?('\n')=>false 最佳答案 \n需要在双引号内,否则无法转义。>>"\n".include?'\n'=>false>>"\n".include?"\n"=>true 关于Ruby无法检测字符串中的换行符,我们在StackOverflow上找到一个类似的问题: h

  8. 深度学习12. CNN经典网络 VGG16 - 2

    深度学习12.CNN经典网络VGG16一、简介1.VGG来源2.VGG分类3.不同模型的参数数量4.3x3卷积核的好处5.关于学习率调度6.批归一化二、VGG16层分析1.层划分2.参数展开过程图解3.参数传递示例4.VGG16各层参数数量三、代码分析1.VGG16模型定义2.训练3.测试一、简介1.VGG来源VGG(VisualGeometryGroup)是一个视觉几何组在2014年提出的深度卷积神经网络架构。VGG在2014年ImageNet图像分类竞赛亚军,定位竞赛冠军;VGG网络采用连续的小卷积核(3x3)和池化层构建深度神经网络,网络深度可以达到16层或19层,其中VGG16和VGG

  9. 玩以太坊链上项目的必备技能(初识智能合约语言-Solidity之旅一) - 2

    前面一篇关于智能合约翻译文讲到了,是一种计算机程序,既然是程序,那就可以使用程序语言去编写智能合约了。而若想玩区块链上的项目,大部分区块链项目都是开源的,能看得懂智能合约代码,或找出其中的漏洞,那么,学习Solidity这门高级的智能合约语言是有必要的,当然,这都得在公链``````以太坊上,毕竟国内的联盟链有些是不兼容Solidity。Solidity是一种面向对象的高级语言,用于实现智能合约。智能合约是管理以太坊状态下的账户行为的程序。Solidity是运行在以太坊(Ethereum)虚拟机(EVM)上,其语法受到了c++、python、javascript影响。Solidity是静态类型

  10. 【自动驾驶环境感知项目】——基于Paddle3D的点云障碍物检测 - 2

    文章目录1.自动驾驶实战:基于Paddle3D的点云障碍物检测1.1环境信息1.2准备点云数据1.3安装Paddle3D1.4模型训练1.5模型评估1.6模型导出1.7模型部署效果附录show_lidar_pred_on_image.py1.自动驾驶实战:基于Paddle3D的点云障碍物检测项目地址——自动驾驶实战:基于Paddle3D的点云障碍物检测课程地址——自动驾驶感知系统揭秘1.1环境信息硬件信息CPU:2核AI加速卡:v100总显存:16GB总内存:16GB总硬盘:100GB环境配置Python:3.7.4框架信息框架版本:PaddlePaddle2.4.0(项目默认框架版本为2.3

随机推荐