危险漫步博客
新鲜的“黑客思维”就是从全新的角度看待黑客技术,从更高的层面去思考;专注于黑客精神及技术交流分享的独立博客。
文章2308 浏览22661024

Net生肉研究报告

 我们在《论.Net熟肉的正确打开方式》已经探讨了.Net熟肉,也就是没有经过任何保护,直接就把编译后的MSIL(.Net中间语言,也可理解为.NetFrameWork虚拟机的字节码)放出来的.Net程序的逆向方法。相信很容易感觉到,在现在.Net逆向工具如此成熟的环境下,直接放出.Net熟肉无异大声宣布我准备任人鱼肉。这已经不是一两处关键代码被偷窥的问题,而是相等于整套程序代码拱手送人,重新编译发布也是分分钟的事情。如果有靠写.Net编写小玩意卖钱的同学,看到这里相信已经深吸了一口冷气。不过矛盾矛盾,有矛自然有盾,.Net的逆向安全虽然不温不火,但整个生态环境实际已经相当成熟。逆向的工具前面已经说了,保护工具,也即所谓的加壳工具,也已经经行过几轮的迭代。保护的思路,概括来看大抵有两种,一种是延续传统对PE文件的保护方式,业界称为整体保护方案;一种是专门针对.Net熟肉一被拖进逆向工具,就把底裤都亮出来的尿性,采取了加入垃圾以及各种打乱的混淆保护的策略,有意思的是,大概连微软都知道.Net的统一编译成MSIL特性简直是为逆向而生,在VisualStudio中也专门提供了名为dotfuscator的混淆工具。保护的方法不多就两种,但具体的实现仍然百家争鸣。从本篇开始我们将作一个系列来逐一研究。不过要说明的是,两种保护技术并不相斥,很多保护方案都是融合了两种保护思路,以求互为犄角。

这一篇首先看看整体保护方案。我们知道.Net程序虽然需要首先安装.NetFrameWork才能运行,但它也是exe结尾,实际上也同样采用和普通exe文件相同的PE文件结构,当然,会有一些拓展,后面介绍手工脱壳方法的时候再具体介绍。这里只需要知道,.Net程序也是PE结构,也包含各种头各种节,也有OEP和IAT,传统面向PE结构的保护壳,保护的也是这些东西,理论上套上就该能用了,也就是在.Net的PE结构上套一层保护壳,将内部结构加密隐藏就保护起来了,在运行的时候再解密释放出来。不过.Net毕竟有一些新的机制,因此还需要进行一些兼容性的调整,不过大致过程和普通保护壳是一样的。

口说无凭,首先看一款老牌的.Net加壳工具.NetReactor(请注意和逆向工具.NETReflector区分,两个是不同单词),这是款最早出现的专门针对.Net的保护壳之一,现在还在更新。早期的.NetReactor主要依靠整体保护的方案来进行保护,可以以此对比观察加壳前后的变化。

先编译一个.Net程序,观察其内部结构如图1所示。

图1

这是张很经典的.Net程序文件结构图,可以注意到两点:1.如上所说,它拥有传统PE结构的全部信息,也就是完整继承了传统的PE结构;2.它拥有.Net特有的数据结构,可以看到有一项名为.NETDiretory的数据项,这是.Net程序的一大特征,下面还有几个Meta开头的数据结构,以及一些Table,这些称为元数据,在后面的文章将详细介绍。.NETDiretory和元数据是查看某个EXE文件是否为有效.Net程序的重要判断依据。同时也是判断一个.Net程序是否启用整体保护方案的重要依据。请记住这句话。

《论.Net熟肉的正确打开方式》介绍了.Net逆向神器.NETReflector,现在就看看保护后的效果。用.NETReflector打开被保护的程序,提示:isnota.NETmodule,也就是.NETReflector认为它不是一个有效的.Net程序。再来看看.NetReactor保护后的文件结构如图2所示。

图2

现在变成了传统的PE结构,所有.Net程序特有的信息都被加密保护起来了。同时也由于.Net相关的文件结构均已不存在,被保护的程序不再是一个有效的.Net程序,也就不再能够使用.NETReflector逆向了。因此起到了防止逆向的效果。到这里为止,对.Net程序的整体保护和传统对PE文件的加壳保护并没有很大区别,同样是对敏感的数据结构进行加密,保护后原文件相关的二进制信息是无法直接查看的。是不是进行了整体保护,就不再能够逆向.Net程序了呢?当然不是,为了对抗传统的加壳技术,以及发展出多种脱壳工具和技术,.Net的整体保护既然也类似于加壳,当然也就会有对应的脱壳工具和技术。我们知道,传统的加壳软件,会在运行时还原或部分还原数据结构(部分信息可能仍存于加密状态以防止逆向,譬如IAT等),以保证程序同义执行,也即保持功能的一致性,能像原来那样运行。.Net的整体保护也一样,会在运行时还原原来的.Net程序。如果能有一款工具抓取此时的内存数据,不就能DUMP得原来的.Net程序了吗?真的就有这么一款专门针对.NetDump脱壳的工具,而且非常自动化,能完成从DUMP到REBUILD一条龙工作,更重要的是,操作非常简单。这款有点半仙味道的工具叫做NETUnpack,如图3所示。

图3

用法非常简单。我们以脱.NetReactor主程序为例子进行演示。虽然我们已经知道.NetReactor采用了整体保护的方案,但我们还是尝试.NETReflector打开,OK,提示错误,如图4所示。

图4

接下来运行.NetReactor,然后运行NETUnpack。NETUnpack的界面一看就知道是进行列表,右边有两个按钮,从上到下分别是Unpack,也就是脱壳,和Reflesh,也就是刷新功能。在列表中找到.NetReactor的进程(如果列表里没有,点下面也就是刷新按钮),然后点脱壳。这时会弹出一个保存框选择保存路径,这里推荐保存到一个文件夹当中,因为Dump下来的通常不止一个文件.

这次一共Dump了8个PE文件,其中第5个已经显露出图标.NetReactor的图标,我们很容易就猜到这才是想要的主程序脱壳文件。把它放回原程序目录,OK正常运行,说明它确实是主程序脱壳后的文件里。把它拖进.NETReflector,现在一切正常。.NetReactor的主程序都可以用这种方法脱壳,受它保护的.Net程序自然不在话下。NETUnpack是一款通用性很好的采用内存Dump技术的脱壳工具,遇到整体保护的.Net程序,不妨用它来试试。不过,这里我要提出一个看法,运行正常离逆向完成其实还有一点距离。原因?请看图6。

图6

虽然可以打开了,但各种名称都变成了“乱码”。可能已经有同学猜到,这就是所谓的混淆技术中的一种,是名称混淆。名称是无关乎运行的,但毕竟逆向分析人员是人,读逆向代码的也是人,软件工程专门就讲了代码可读的重要性,其中命名规范肯定是浓墨重彩的一章。后面我们将会继续研究如何对抗采用混淆技术保护的.Net程序。

(完)

相关推荐