一个用于训练静态PE恶意软件机器学习模型的开放数据集

来源:https://arxiv.org/abs/1804.04637

https://academic.microsoft.com/search?iq=And(Ty%3d%270%27%2cRId%3d2798159728)&filters=&from=0&sort=0&q=papers%20citing%20ember%20an%20open%20dataset%20for%20training%20static%20pe%20malware%20machine%20learning%20models

来源:EMBER: An Open Dataset for Training Static PE Malware Machine Learning Models


摘要:

本文描述了EMBER:一个用于训练机器学习模型静态检测恶意Windows可移植可执行文件的标记基准数据集。该数据集包含了从1.1M个二进制个体抽取的特征:900K训练样本(300K恶意,300K良性,300K未标记)和200K测试样本(100K恶意,100K良性)。为了配合数据集,我们还发布了用于从其他二进制文件中提取特性的开放源代码,以便可以将其他样例特性附加到数据集。这个数据集填补了信息安全机器学习社区的空白:一个良性/恶意的数据集,足够大、开放和通用,足以涵盖几个有趣的用例。我们列举了在构造数据集时考虑的几个用例。此外,我们还演示了一个用例,在这个用例中,我们将使用LightGBM训练的带有默认设置的基线梯度增强决策树模型与MalConv(最近发布的用于恶意软件检测的端到端(无特征)深度学习模型)进行了比较。结果表明,即使没有超参数优化,基线EMBER模型的性能也优于MalConv。作者希望EMBER提供的数据集、代码和基线模型能够像基准数据集具有先进的计算机视觉研究一样,为恶意软件检测的机器学习研究注入活力。

1介绍

机器学习可以是一个有吸引力的工具,无论是主要的检测能力或补充检测启发式。监督学习模型自动利用训练数据中文件属性之间的复杂关系,区分恶意样本和良性样本。此外,适当正则化的机器学习模型可以推广到新的样本,这些样本的特征和标签与训练数据的分布类似。然而,在开放的研究社区中,使用机器学习的恶意软件检测并没有像其他应用程序那样受到如此多的关注,因为在这些应用程序中存在丰富的基准数据集。这些包括手写数字分类(如MNIST[17])、图像标记(如CIFAR[16]或ImageNet[10])、流量标志检测[13]、语音识别(如TIMIT[32])、情绪分析(如Sentiment140[12]),以及大量其他适合训练模型模拟人类感知和认知任务的数据集。发布用于恶意软件检测的基准数据集的挑战很多,可能包括以下内容。

•法律限制。恶意二进制文件通过VirusShare[24]和VX Heaven[2]这样的站点被慷慨地共享,但是良性二进制文件通常受到版权法的保护,版权法禁止共享。良性和恶意二进制文件都可以通过付费服务(如VirusTotal[1])批量获得,供内部使用,但禁止随后共享。

•标签的挑战。与图像、文本和语音不同的是,即使是受过良好训练的人,判断二进制文件是恶意的还是良性的也是一个耗时的过程。标签的工作可以通过反毒软件扫描器自动化,这些扫描器将人类的许多专业知识编入知识库,但结果可能是专有的或受到保护的。像VirusTotal这样的重新发布服务特别地限制了反病毒软件标签[1]的公开共享。

•安全责任和预防措施。向不习惯采取适当预防措施(如沙箱托管)的一般非infosec受众推广包含恶意二进制文件的大型数据集可能存在风险。

我们通过发布研究(EMBER)数据集的Endgame恶意软件基准(BEnchmark for Research, EMBER)数据集1来解决这些问题,该数据集是从大量Windows可移植可执行程序(PE)中提取的恶意和良性的东西。这允许恶意和良性实体的自由传播,而无需担心法律或安全问题。样例连同原始文件的sha256散列一起发布,并使用一个标签表示该文件是被认为是恶意的还是良性的。特征的预先选择自然限制了研究人员比较特征集的灵活性。这在某种程度上得到了改进,因为我们发布了开放源代码来计算用于特性比较研究的PE特性。缺乏原始二进制文件也妨碍了使用无特征的深度学习恶意软件检测器(如[22])进行实验。但是,我们希望通过发布sha256哈希,特征提取源代码,以及从特征子集计算出的高性能基线分类器,这个数据集和模型代码库仍然能够成为机器学习恶意软件检测研究的相关基线,并且可以与无特征的深度学习研究进行比较。我们在第4节中演示了这种比较。

我们从第2节开始介绍PE文件格式的相关背景,以及静态恶意软件分类的相关数据集和方法的总结。在第3节中,我们将描述数据集及其格式的方法。我们在第4节中演示了在此数据集上训练的基线模型的有效性。源代码和数据可以在https://github.com/endgameinc/ember找到。

2背景

我们在2.1节中总结了可移植可执行文件格式(PE)中的重要上下文。在第2.2节中,我们回顾了使用机器学习对恶意软件进行分类的特征提取的相关工作。最后,我们在2.3节中总结了其他相关的静态恶意软件数据集。

2.1 PE文件格式

PE文件格式描述了Microsoft Windows操作系统的主要可执行格式,包括可执行文件、动态链接库(dll)和FON字体。该格式目前支持英特尔、AMD和ARM指令集架构的变体。

文件格式由许多标准头文件(PE-32格式见图1)组成,后面是一个或多个节[20]。头文件包括通用对象文件格式(COFF)文件头文件,其中包含重要信息,如文件的类型、fle (DLL、EXE、OBJ)的性质、节数、符号数等。可选的头标识链接器版本、代码的大小、初始化和未初始化数据的大小、入口点的地址,等等。可选标头中的数据目录提供指向跟随它的节的指针。这包括用于导出、导入、资源、异常、调试信息、认证信息和重定位表的表。因此,它提供了可执行[30]内容的有用摘要。最后,节表概述了PE文件中每个节的名称、偏移量和大小。

PE部分包含代码和初始化数据,Windows加载器将这些代码和初始化数据分别映射到可执行或可读/可写的内存页面,以及文件的导入、导出和资源。每个部分都包含一个头,它指定了大小和地址。导入地址表指示加载程序静态导入哪些函数。参考资料部分可能包含用户界面所需的资源:光标、字体、位图、图标、菜单等。基本PE文件通常包含.text code部分和一个或多个数据部分(.data,.rdata或.bss)。重定位表通常存储在.reloc节中,Windows加载程序使用该节从可执行文件的首选基中重新分配基地址。TLS部分包含用于存储thread-specifc局部变量的特殊线程本地存储(TLS)结构,它被用来重定向可执行文件的入口点,以首先检查调试器或其他分析工具是否正在运行[5]。从Windows加载器的角度来看,节名称是任意的,但是specifc名称已经被采用,并且非常普遍。包装程序可以创建新的部分,例如,UPX包装程序创建UPX1来存放打包的数据,并创建一个空的部分UPX0,它为运行时解包[11]保留一个地址范围。

2.2静态PE恶意软件检测

静态恶意软件检测试图在不执行样本的情况下将样本分类为恶意或良性,而动态恶意软件检测则根据恶意软件的运行时行为(包括需要分析的系统调用的时间依赖序列)来检测恶意软件[4,9,18]。虽然静态检测在一般的[7]中是不可判定的,但它是安全套件中一个重要的保护层,因为当成功时,它允许在执行之前检测恶意事件。

基于机器学习的静态PE恶意软件检测器至少从2001年[27]就开始使用了,主要由于结构化文件格式和向后兼容性的要求,在后续的工作中,许多概念仍然惊人地相似[9,15,23,26,29]。Schultz等人通过McAfee病毒扫描仪收集数据并生成标签。PE文件由包含导入函数、字符串和字节序列的特性表示。在保留集上对各种机器学习模型进行训练和验证,模型包括RIPPER[8]的规则、朴素贝叶斯和集成分类器。Kolter等人[15]通过包含字节级n -gram扩展了这种方法,并采用了来自自然语言处理的技术,包括字符串的tf-idf加权。Shafq等人提出仅使用PE头中的7个特性(在2.3节中描述),其动机是研究中的大多数恶意软件样本通常都显示了这些元素。Saxe和Berlin利用新颖的二维字节熵直方图,将其输入多层神经网络对[26]进行分类。

最近端到端深度学习的进展极大地改善了这一技术,特别是在对象分类、机器翻译和语音识别方面。在这些方法中,原始图像、文本或语音波形被用作机器学习模型的输入,从而推断出当前任务最有用的特征表示。然而,尽管手工制作的特性在其他领域取得了成功,但在已发表的文献中,它们显然仍然代表了恶意软件检测的最新技术水平。在接下来的几个月或几年里,这种技术的状态可能会转变为端到端深度学习,但由于PE文件的结构化格式,解析PE文件所产生的手工特性可能会继续与之相关。在[22]中讨论了一个最近的端到端深度学习恶意软件分类的例子,我们重新实现了这个例子,并与第4节中的基线模型进行了比较。

2.3恶意和良性数据集

PE-Miner的目标是生产一种基于机器学习的恶意软件检测器,其真实阳性率(TPR)超过99%,而假阳性率(FPR)不到1%,其运行时可与当时基于签名的扫描器媲美。它的训练对象是操作系统上1447个良性文件(从未发布过)、来自VX Heaven[2]的10339个恶意PE和来自Malfease的5586个恶意PE。PE-Miner使用189个特性,包括引用的specifc dll的二进制指示器、各个部分的大小、COFF部分的摘要信息、资源表的摘要等等。不幸的是,许多功能没有公开披露,其中一些被认为是敏感的,受NDA[28]保护。在数据集上对几种模型类型进行了评估,发现J48决策树算法的性能最佳。值得注意的是,尽管许多论文将此工作作为第一个基于非签名的性能(包括速度和TP/FP速率)方法,但由于缺乏公共数据集,因此没有进行真正的比较研究。

紧接着,Adobe恶意软件分类器的目标是生成一个恶意软件分类器,它只包含7个特性:调试大小、图像版本、导入地址表的相对虚拟地址、导出大小、资源大小、第二section的虚拟大小以及[23]section的总数。训练了一种决策树算法,并将生成的分类器作为一个免费的工具发布。然而,有人提出,由于良性数据集主要由Windows二进制文件组成,因此生成的模型强烈偏向于非Windows vs. Windows,而不是恶意vs.良性问题[28]。事实上,在评估EMBER测试集上的预训练模型时,我们观察到非常大的假阳性率和很低的检出率(见第4节)。不幸的是,包含大约100K个恶意文件和16K个良性文件的数据集从来没有发布过用于比较研究。

相比之下,微软恶意软件分类挑战赛于2015年4月结束。该数据集包括一个500MB的大数据集,由来自9个家庭的约20K个恶意样本的反汇编和字节码组成。最大的家族由3K个样本的特征组成(Kelihos backdoor),最小的家族只有42个样本(Simda backdoor)。自比赛结束以来,有50多篇研究论文和论文引用了该数据集。这些作品的贡献摘要在[25]中列出。不幸的是,反汇编特性是IDA Pro反汇编器特有的(不易重现),而且数据集不包含任何良性的异常。像VXHeaven这样的恶意软件共享服务提供了大量的恶意二进制文件[2]。VirusTotal 可以使用关于供应商参与者[1]的检测次数的启发式算法来挖掘假定的良性文件。然而,大规模的病毒访问速率需要付费订阅。无论如何,目前还没有一套公认的用于机器学习基准测试的恶意和良性机制。

3数据描述

在构建EMBER数据集时,我们考虑了几个实际的用例和研究,包括以下内容。

•比较用于恶意软件检测的机器学习模型。

•量化模型退化和概念随时间的漂移。

•研究可解释机器学习。

•比较恶意软件分类的特性,特别是在EMBER数据集中没有表示的新特性。这需要一个可扩展的数据集。

•与无特征的端到端深度学习相比。这可能需要代码从一个新的数据集中提取特性,或者shas256哈希来构建一个原始的二进制数据集来匹配EMBER。

•研究针对机器学习恶意软件的对抗性攻击,以及随后的防御策略。

•通过无监督学习利用无标记样本进行PE文件表示或半监督学习进行分类。对这些用例的考虑导致了本节中概述的数据结构。

3.1数据布局

EMBER数据集由一组JSON行文件组成,其中每一行都包含一个JSON对象。每个对象在数据中包含以下类型:

•原始文件的sha256哈希作为唯一标识符;

•粗略的时间信息(月分辨率),用于估计文件首次出现的时间;

•标签,良性为0,恶性为1,未标记为-1;和

•8组原始特性,包括解析值和与格式无关的直方图。

下面将更详细地描述每种特性类型的细节,图2显示了一个示例。



为了方便起见,我们的数据集由人类可读的原始特性组成。我们提供了从原始特性生成模型构建所需的数值特性向量的代码。这使得研究人员能够将原始特性与向量化策略解耦。在我们的代码中,我们提供了一个默认方法,该方法生成一个用于训练基线模型的特征矩阵,并且应该适用于大多数用例。然而,原始特性的可用性可能允许研究可解释的机器学习,或像[29]中那样的特性重要性。我们还将未标记的样本包含在训练集中,以鼓励对半监督学习方法的研究(参见图3),在已发表的文献中,这似乎是一个相对未被探索的恶意软件分类领域。另一个需要考虑的问题是,我们临时分割训练/测试集(请参见图4),以模拟恶意软件和良性软件的世代依赖关系。粗略的时间戳为一年的恶意和良性文件也可以允许简单的纵向研究。包含原始文件的sha256散列允许研究人员将特性链接到原始二进制文件,包括可以通过VirusShare或VirusTotal等文件共享站点获得的其他元数据[1,24]。为了方便起见,我们确保EMBER中标记为良性的文件在VirusTotal中可用,并且在收集时,没有供应商检测到它们是恶意的。同样,我们确保EMBER中标记为恶意的在VirusTotal中可用,并且有超过40个供应商报告为恶意。因此,EMBER是一个相对“简单”的数据集。


3.2特征集描述

EMBER数据集由8组原始特性组成,包括解析特性和与格式无关的直方图和字符串计数。接下来,我们将区分原始特性(提供的数据集)和来自数据集的模型特性(或向量化特性)。模型特征表示用于训练模型的固定大小的特征矩阵,表示原始特征的数值摘要,其中使用特征哈希技巧[31]捕获字符串、导入名称、导出名称等。在发布的数据集中没有显式地提供特征矩阵,但是提供了代码来将原始特性转换为模型特性,从而训练基线模型。为了方便,我们使用了scikit-learn[19]提供的实现。在适当的地方,在下面的特性描述中,我们注意到用于特性哈希技巧的bin的数量。

3.2.1解析功能。数据集包含五组特征,这些特征是在解析PE文件之后提取的。我们利用这个库来检测可执行格式[21]作为一个方便的PE解析器。LIEF名称用于表示符号对象的字符串,如特征和属性。对于这些字符串的一些示例,请参考图2。下面将更详细地描述每种已解析的特性类型。

一般文件信息。通用文件信息组中的一组特性包括文件大小和从PE头获得的基本信息:文件的虚拟大小、导入和导出函数的数量、文件是否具有调试部分、线程本地存储、资源、重新定位或签名,以及符号的数量。

头信息。从COFF报头中,我们报告报头中的时间戳、目标机器(字符串)和图像特征列表(字符串列表)。从可选的头文件中,我们提供了目标子系统(字符串)、DLL特征(字符串列表)、文件魔法作为字符串(例如“PE32”)、主映像版本和副映像版本、链接器版本、系统版本和子系统版本,以及代码、头文件和提交大小。在训练一个模型之前,使用特征哈希技巧总结模型特征、字符串描述符(如DLL特征、目标机器、子系统等),每个带噪声的指标向量分配10个bin。

导入函数。我们解析导入地址表并按库报告导入的函数。为了为基线模型创建模型特性,我们只需要收集一组惟一的库,并使用散列技巧来绘制这个集合(256个bin)。类似地,我们使用散列技巧(1024个bin)捕捉单个函数,方法是将每个函数表示为一个字符串,如library:FunctionName对(例如,kernel32.dll:CreateFileMappingA)。

导出函数。原始特征包括导出的函数列表。使用128个bin的哈希技巧将这些字符串总结为模型特性。

section信息。提供了每个section的属性,包括名称、大小、熵、虚拟大小和表示节特征的字符串列表。入口点按名称指定。为了转换为模型特征,我们使用哈希技巧(节名、值)对创建包含节大小、节熵和虚拟大小(每个50个bin)的向量。我们还使用散列技巧来捕获入口点的特征(字符串列表)。

3.2.2与格式无关的特性。EMBER数据集还包含三组与格式无关的特性,因为它们不需要解析PE文件来进行提取:原始字节直方图、基于以前在[26]中发布的工作的字节熵直方图和字符串提取。

字节直方图。字节直方图包含256个整数值,表示文件中每个字节值的计数。在生成模型特性时,这个字节直方图被规范化为一个分布,因为文件大小在一般文件信息中表示为一个特征。

Byte-entropy直方图。字节熵直方图近似于熵H和字节值X的联合分布p(H, X)。这是通过计算一个固定长度窗口的标量熵H并将其与窗口内发生的每个字节配对来完成的,如[26]所述。当窗口在输入字节之间滑动时,将重复此操作。在我们的实现中,我们使用的窗口大小为2048,步骤大小为1024字节,使用16×16个bin对熵和字节值进行量化。在训练前,我们将这些计数归一化,使之统一。

字符串信息。数据集包含关于可打印字符串的简单统计信息(包括范围为0x20到0x7f的字符),这些字符串至少有5个可打印字符长。特别地,报告了字符串的数量、它们的平均长度、这些字符串中可打印字符的直方图以及所有可打印字符串的字符熵。可打印字符分布提供了与上面的字节直方图信息不同的信息,因为它仅派生自包含至少五个连续可打印字符的字符串。此外,字符串功能组包含字符串的数量,从C: \(不分大小写)可能表明一个路径,出现的次数http://或https://(不分大小写)可能表明一个URL,出现的次数HKEY_可能表明一个注册表键,和出现的次数短字符串MZ可能提供弱Windows PE dropper或捆绑可执行文件的证据。通过提供字符串的简单统计摘要,而不是原始字符串的列表,我们减轻了一些良性事件可能存在的隐私问题。

4实验

EMBER包含的代码演示了如何使用训练集中的原始特性(仅标记为sample)来构建监督学习模型,我们将其作为基线模型提供。模型构建过程包括向量化原始特性(将每个对象转换为一个维数为2351的向量),在必要时使用特征哈希技巧,如前所述。在2015年的MacBook Pro i7上,将原始功能矢量化为模型功能需要20个小时。从矢量化特征出发,我们使用默认参数LightGBM(100棵树,每棵树31片叶子)训练梯度增强决策树(GBDT)模型,得到小于10K的可调参数[14]。模型训练花了3个小时。通过适当的超参数优化,基线模型的性能可能会得到很大的提高,但我们对这方面的工作不太感兴趣。

结果模型的ROC曲线如图5所示,恶意和良性样本在测试集中的得分分布如图6所示。ROC AUC超过0.99911。模型得分的阈值为0.871,检出率超过92.99%,FP率小于0.1%。在FP小于1%的情况下,模型的检出率超过98.2%。

正如在第2节中讨论的,有人提出,由于Adobe恶意软件分类器所针对的数据集,它偏向于非Windows与Windows分类器,而不是真正的恶意与良性问题[28]。我们在我们的测试集中评估了预训练的J48模型,发现它显示出惊人的53%的假阳性率和8%的假阴性率。这似乎证实了之前关于数据集偏见的说法。然而,这种糟糕的性能是由于陈旧的训练数据还是数据集偏见,或者两者都是超出了本文的范围。但显然,这是一个不合适的基线模型。

作为对比研究,我们对MalConv[22]进行了数据集底层原始二进制文件的训练。我们使用了作者规定并验证过的模型架构和训练设置,但是由于GPU内存的限制,我们训练的批处理大小由256改为100。我们使用跨两个Titan X (Pascal) gpu的数据并行性进行训练。每一个阶段需要25个小时,我们训练了10个阶段(10天)。得到的模型有大约1M的参数。应用于EMBER测试集对应的原始二进制文件,Malconv ROC AUC为0.99821,对应于小于0.1%的假阳性率为92.2%的检出率,小于1%的假阳性率为97.3%的检出率。这比使用没有超参数调优的LightGBM性能略低。显然,尽管模型的大小和计算量增加了,但是无特征的深度学习模型还没有超过通过解析特性利用领域知识的模型的性能。

5讨论

据我们所知,EMBER数据集代表了第一个用于机器学习恶意软件检测的大型公共数据集(其中必须包括一些良性的东西)。作者希望该数据集能够促进机器学习恶意软件检测的创新。我们在第3节中考虑了许多研究用例,包括比较模型性能、对抗性机器学习的攻防、用于恶意软件检测的半监督学习,以及更多的研究领域。

使用该数据集,我们还发布了一个简单的非优化基准LightGBM模型。快速提高模型性能的简单方法包括通过特征选择来消除噪声特征和通过网格搜索进行超参数优化。尽管如此,我们证明了基于这些特性的开箱即用LightGBM模型在端到端深度学习中优于最近发表的用于恶意软件检测[22]的工作。因此,除了基准数据集,我们希望EMBER能够提供一种简单的方法来对新架构的模型性能进行基准测试,包括端到端深度学习。数据集和源代码可从https://github.com/endgameinc/ember获得。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,784评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,745评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,702评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,229评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,245评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,376评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,798评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,471评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,655评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,485评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,535评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,235评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,793评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,863评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,096评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,654评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,233评论 2 341

推荐阅读更多精彩内容