Implementing genetic algorithms in virusses by BlueOwl/Rrlf 5# 翻译 by nEINEI/vxjump.net [0x1]. 简介 [0x2]. 达尔文的进化理论 [0x3]. so ,inshort [0x4]. 二进制世界中的物种 [0x5]. 二进制与生物的结合 [0x6]. 遗传算法 [0x7]. 选择合适的基因 [0x8]. 变形技术 [0x9]. 代码示例 [0xa]. 结束语 [0x1]. 简介 我本人十分着迷于进化理论,并且坚信这就是生物进化的真相。我花了很多时间去 思考和编写代码并酝酿着如何把这些理论实施到计算机病毒的编写当中。当然,这和前 面说的那些理论是完全不相同的东西。 通常病毒是不能改变自身代码的(译注:指静态文件的情况),所以要通过加密的办法, 或者通过多层加密来彻底改变自身(这很难做到)。随着进一步的尝试,彻底改变代码布局 的方式有配置层数/代码混淆/寄存器混淆等等方式,这里我将试图证明进化理论比那样的 变形方式更好。 注意!这个理论我主要是阐述的是如何应用遗传算法在文件感染类病毒的编写中, 当然这也适合任何一种传播计划包括蠕虫,只要你能发挥创意就可以。 [0x2]. 达尔文的进化理论 ok,长话短说,达尔文的进化理论是什么?让我们假设有一个物种,就说狗吧,并假设 它们在丛林中生活,周围没有人类。你可能知道这里会很有很多的狗,小的,瘦的,大的, 长的,短的等等吧。因此所有这些不同的生物都被混合在丛林中了。 一些狗狗一定会死亡的,因为他们找不到吃的,或者被逮捕到,亦或是被狮子吃掉, 还有可能掉下河去被淹死,凡此种种吧,但正如你能想象的一样,成千上万的狗中仍然 会有少数幸运的狗狗活着。因为他们完全适应了丛林中的生活。剩下的这些狗进行交配 产生下一代。其中一些新产生的狗会更好的适应环境,有的则会更差。因此新产生的还会 死掉,但不会很多,因为它们已经从它们的父母那里继承了要生存的基因。 达尔文的进化论就是关于这方面的一切,最强烈的生存,而这些后代要么更好要么 更坏,直到最终创建出“完美”的物种。 [0x3]. so ,inshort ok,读了上面的东西会发现有x个核心因素: 1 每个人都有一个特定的DNA这取决于它是什么,高矮胖瘦,毛长,毛短... 2 生存环境将会杀掉个体的某些特征,例如一些狗的腿要长并且跑的很快,这样才能 不会被狮子吃掉,相反那些短腿的将被杀害和吃掉。 3 狗狗这一物种能生存下来,是能产生积极的特征被下一代继承,因此它们有很多 相同的变化特征,但也有少数不同的特征,这些变化将取决于个体是否会更好或更差的 生存,相比于其父母。 [0x4]. 二进制世界中的物种 这个理论说的是,让我们聊聊现在计算机病毒和进化理论的关系吧。什么是带有遗传 技术的病毒呢? 在病毒的世界里,当然,是没有“自然”的天敌的。没有狮子,河流... 。敌人只有一个, antivirus,当antivirus发现一个病毒,将提示移除,或者清除。病毒的检测有两种方法, 1 基于病毒的特异性 2非特异性病毒(启发式) 第一种方法的意思是很宽松的一个方式,某个感染病毒的文件被发送到病毒分析员 那里,部分或者全部被分析并且产生一个检测的例程。升级给使用antivirus的人们,这样 他们就可以免疫种病毒了。 第二种方法检测病毒的方法是检测病毒家族的可能特征或者可疑行为。什么样的行为是 可疑的,什么样的行为不是可疑的,这并不是软件作者所能决定的。有些病毒不能被检测, 因为它们不符合启发式的描述规则,程序设计者不能无限制的增加描述规则,因为越是加入 就越有机会把这变成了一个non-virus的描述集合了。 [0x5]. 二进制与生物的结合 首先我们讨论一下启发式检测,有了这种检测方式,病毒就可以知道他们做了什么事情 了。antivirus能检测一个文件被病毒感染后的情况,但正如我前面所说的,一些病毒是不 能被检测出来的,因为每一个病毒都有自己的变化方式。 我们用长腿/短腿的狗来做个类比,这是个非常好的比较,如果狗的腿短将会死掉,长 的将得到生存,如果一个病毒被一种检测方法检测到,那么它使用另一个方式感染,将不会 被检测到。 什么样的方法是病毒所使用最好的方式呢?这个还是未知数,就像腿短或者腿长的狗 不知道将来是否能生存一样,病毒也同样不会知道。对于狗的这个物种来说这不是个问题, 一些狗总会死掉,但新的会替代他们的位置。但对病毒来说这是个问题,因为没有什么不同 类型的病毒。即使这种病毒是多态的,也仍然是个问题,因为多态病毒的幸存者也无法了解 如何组合起来工作。就像是长腿的父辈,生了一个长腿和短腿的后代一样。 在这里,我们有了遗传学和DNA病毒的想法。如果病毒能够记得自己的感染方式,并且 通过轻微的修改把他传递给它的下一代。这样的方法实现了也就像狗狗的进化一样了。 这同样适用于特征检测,比如反病毒分析员发现某种病毒的感染方式,把检测方案添加 到了病毒库中,这样所有使用这种感染方法的病毒都会被检测出来。当病毒使用另外的DNA时, 它将不会被删除,它将替换之前那个病毒样本。这样的病毒演变是完全的,只要不是所有的 病毒样本都被添加到病毒库中,一些病毒就可以绕过检测,继续生存和繁殖。 [0x6]. 遗传算法 处理一些很难理解的事情上(代码设计..),遗传算法可以看做是一个合理简单的方案。 结构如下,在我看来这是最好的遗传引擎方式了(后面我会解释) 对每一个被感染的文件来说: 1 保留病毒DNA 2 变异的病毒DNA 3 被感染的文件 4 恢复病毒的DNA 首先我们来谈谈文件的感染,在每一个可能的遗传感染步骤中,是这样考虑的: if (stepxgene==0) { do first way } else { do second way } 为了使这个过程变的更高效,所有步骤的可能性,其数量最好是固定的。比如所有 的步骤都只有4种可能性。这将有助于我们如何确定存储DNA。如果你考虑多个DNA步骤,我 希望你能用2^ ~ ... 这样一个范围。所以你能使用最大的比特位是有限制的。 保存/变异/恢复,这些可能很难理解为什么要这样做。最终的原因是,这种方式感染的文件 将根据病毒的DNA遗传给它的下一代。这样的方式才会使得它的后代知道它是由什么组成的。 如果病毒仅copy一个变异的DNA在感染进化中是会留下一点点的。例如,一个病毒有DNA A组件, 并使用A方式去感染文件,但给它copy一个DNA B组件。另外一个问题是在所有被感染的文件中 通常是一个病毒用完全相同的方式去感染文件,而实际上你不能看到,所有的小狗都长得一个 模样。 [0x7]. 选择合适的基因 是什么原因造成的遗传?这是另外一个话题,但这确实值得讨论的。真正的问题是,什 么东西是有用的遗传因素。人类头发的颜色是和遗传相关的,但指纹确实不同的,甚至双胞 胎也不一样。显示,指纹在人类的进化过程中是不重要的,你可以添加任何你想要的基因进 去,但是问题出现了,你将碰到下面的情况: if(gene==0){ ... if (anothergene==0){ ... } else { ... } ... } else { ... if (yetanothergene==0){ ... } else { ... } ... } 当然,这是有可能的,但是当你更加密切的关注它时,你会注意到基因的重要性下降了。 if (...){ if (...){ if (...){ ... } ..}..} 如果第一个if里面的“基因”进行突变,所有内部的”基因“将不能被执行。当一个内部 基因改变时要做出更大的适应调整。所以为了”公平“,你不得不做出调整给更小更重要的基因。 这是个问题,你还可以忍受,但我会建议你尽量避免这样做,保持这种格式吧: if (...) { ... } ... if (...) { ... } ... if (...) { ... } ... ... 此外,别在得意忘形的时候创造基因,我的意思是别创造一个自我毁灭的基因:) 并且 确保所有的选择都是兼容的。最有效的测试办法是设置所有基因的第一次值为0,而不是单 独测试到底有多少个不同的情况,有因为你不能测试所有的组合。 [0x8]. 变形技术 变形是进化的本质,没有它,当然,一切都将保持不变。因此引擎在某个时候会做出 改变,然后还有另一个事情要考虑,保持多久后才要有所改变呢?如果改变的太快,病毒 可能完全不同了,很快就失去了演变的作用。但如果改变的太慢,导致变化不足而被检测 到或者不能找到新的方法。无论如何,这都是值得讨论的。 此外,可能突变的数量也不能是静态的不变的。因此,要保持”自然“的方式,每一个 基因都应该有一个独立的一定概率的改变。我的算法是(ASM) call rand ; eax = random xchg eax, edx ; (each bit has a chance of 1 in 2 to be 1) call rand ; eax = random and edx, eax ; chance 1 in 4 call rand and edx, eax ; chance 1 in 8 call rand and edx, eax ; chance 1 in 16 call rand and edx, eax ; chance 1 in 32 因此,在这个例子中的最后,edx的任何一个bit,都有1/32可能为1,而所有其它的位 是0,考虑一个DWORD包含32bit的情况,在这一个过程结束后,每次平均第1bit都有为1的可能。 然而,0,2,3,4...32bits也有这个可能性,但32bit都为1需要48bit的数字。所以我们产生 一个太大的突变则几乎不可能发生。 所以在得到这个值后,我们只是用它和dna进行xor运算(事实上它仅是由dword得来的) 给它一个少数或者根本没有突变。 xor [dna],edx [0x9]. 代码示例 到底怎样实现一个简单的多态引擎呢,其实不是这么简单的事情,可能很难理解,因为 我最关心的是优化的事情,它有2个部分包括遗传算法,一个DNA变量(called DNA),一个 寄存器容器,在引擎运行后这些首先被保存,原来的代码将被修改。然后根据这些产生一个 解密器。 解密器通过以下方式产生:解密器有4个可能的组成部分(看代码中的) 因此,DNA每次2bit(可以是0,1,2,3)读取并选择校验正确的基因选项。如果你看看这个, 也许会学到一些新的技术,但不要试图去了解更多:)(别责怪我的编码风格:)) [0xa]. 结束语 首先,我希望你喜欢读我的文章。由于我非常感兴趣,在这件事情,我喜欢写上这句话。 我已经阅读其他人的想法及写下的关于这个主题相关内容,我喜欢它。我也希望这将为你的编 码带来新的东西,甚至完全不同思路。当然,这未必是个好主意。