在项目开发过程中,估计也有人和我遇到过同样的经历:生产环境出现了重大Bug亟需解决,而偏偏就在这时仓库中的代码却不是最新的。在这种情况下,我们不能直接在当前的代码中修改这个Bug然后发布,这会导致更严重的问题,因为相当于版本回退了。即使我们眼睁睁的看着这个Bug两行代码就能搞定,在我们的代码没更新到最新版本之前,都不敢轻举妄动。但是客户的呼声让人抵挡不住,客户声称的分分钟多少多少的经济损失我们也承受不起。这时如果你是做PHP开发的,你会庆幸,因为你可以直接去生产环境修复掉这个Bug让客户先闭嘴然后再慢慢折腾你那出问题的代码管理工具;而如果你做是.Net抑或C/C++开发的,就没这么轻松了。面对服务器上拷下来的有着重大Bug的dll或exe,你很难直接去修改它里面的代码逻辑,只能利用一些逆向的技巧和工具了。

由于我这里是.Net的环境,所以我决定在这篇博客里介绍下如何利用逆向工具来修改生产上的.Net程序集。但是就在我决定写这篇博客的时候我突然发现,其实,如果你只是单纯的修改一个.Net程序集中的某个方法或功能,而且这个程序集还是出自于你自己或你所在团队之手,这实在是一件非常容易的事情,这和破解别人的程序完全不同,你不会遇到无法破解的加密算法,也不会遇到让人恶心的加壳混淆。利用搜索引擎可以搜到大量这样的教学文章,所以我改变了下主意,决定不在这篇博客中重复造轮子,而是把已有的轮子一个个的列出来总结一下。

这篇博客主要汇总一些.Net反编译相关的工具。

一、ilasm & ildasm

ilasmildasm 都是微软官方提供的.Net编译与反编译工具,可谓是.Net逆向中的瑞士军刀。这两个工具的位置分别位于.Net Framework目录和Microsoft SDK目录中:

C:\Windows\Microsoft.NET\Framework\v2.0.50727\ilasm.exe
C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\ildasm.exe

这里有一篇文章详细介绍了如何通过ilasm 和 ildasm 修改.Net程序,归结起来就下面几个步骤:

  1. 使用工具ildasm打开要逆向的.Net程序,并另存为IL文件;
    ildasm程序有命令行和图形界面两种运行模式,一般情况下双击ildasm即可启动图形界面的主程序,然后通过菜单项 File -> Dump ,选择UTF-8编码,即可导出到IL文件中。如果是以命令行模式运行的话,可以打开Visual Studio自带的开发环境命令行工具(Developer Command Prompt for VS2012),这样可以不用关心ildasm所处的目录,直接运行下面的命令:ildasm test.exe /out:test.il

如果程序含资源文件的话,除了生成一个IL文件,可能还会有其他的*.res文件等。

  1. 打开IL文件阅读IL源码并定位到需要修改的代码处,对IL代码进行修改;
    使用ilasm 和 ildasm 反编译.Net程序需要了解一点MSIL的语法,这样无论阅读还是修改IL文件都要方便的多,好在MSIL的语法并不是很复杂,花一天的时间研究下还是值得的。这里有一篇不错的MSIL教程

如果真的对MSIL不熟悉不会编写MSIL的话,其实也没有大碍,只要你会大概的看懂MSIL源码和会编写C#程序也可以。可以参考这篇文章,具体的方法是:用C#编写你需要修改的方法,然后编译成exe/dll文件,再通过ildasm反编译成IL文件,从这个IL文件中复制出需要的IL源码覆盖掉之前那个需要修改的IL文件中的相关代码,这样你就算不会MSIL,也能修改IL文件了,确实有点偷梁换柱的味道。

  1. 使用ilasm将IL文件重新编译成.Net程序。
    最后,使用ilasm程序重新编译IL文件:ilasm test.il /output:test-mod.exe,再使用PEVerify执行校验确保文件无误:PEVerify test-mod.exe。如果一切顺利的话,将test-mod.exe替换掉老的test.exe即可。

默认情况下,ilasm将生成exe文件,如果需要生成dll文件,可以使用下面的命令:ilasm test.il /dll /output:test-mod.dll,如果需要集成资源,则需要指定/resource参数:ilasm test.il /resource:test.res /output:test-mod.exe

二、.Net Reflector & Reflexil

虽说ilasm 和 ildasm是.Net逆向中的瑞士军刀,但是一提起.Net逆向,其实很多人第一反应都是Reflector这款神器,而对微软提供的这两个官方工具知之甚少。这一方面是由于Reflector良好的用户体验和强大的插件功能,另一方面要归功于Reflector堪称完美的智能反编译能力,使用它不仅能看到反编译后的IL源码甚至能直接反编译出C#源码,而且和编写时的代码几无二致,如果需要还可以直接另存为工程文件用Visual Studio打开。
Reflector是RedGate开发的.Net逆向工具,单纯的Reflector程序只有反编译功能,可以查看IL或C#源码,以及导出源码。并不能修改.Net程序。幸好我们有sailro编写的Reflexil插件,Reflexil基于Mono.Cecil,是一个强大的程序集编辑器。Reflector + Reflexil 可谓是强强联合,和 ilasm + ildasm 这个组合比起来简直是大巫见小巫。

如果是第一次加载Reflexil插件,打开Reflector,在 Tools -> Add-Ins -> Add -> 选择Reflexil.dll,以后就可以直接在Reflector的Tools菜单中打开了。用Reflector打开test.exe,选择某个函数可以发现IL代码显示在下方的Reflexil窗口中,可以点击右键Edit,Delete,Create等操作。还可以修改类或方法的访问权限等,比如将private改成public。
另外,在编辑IL的操作中还有一个Replace all with code选项,通过这个可以直接用C#代码来对程序进行修改,无需你熟悉MSIL语法,类似于上一节介绍的“偷梁换柱”的方法,只不过集成在Reflexil中让我们的操作更方便了。如下图所示:

reflexil.png

Reflexil的作者在codeproject上写了一长篇Reflexil的各种实用技巧,可以去这里看看。Reflexil唯一的缺憾是并没有和Reflector无缝结合,使用Reflexil修改完IL源码或类的属性后,上面Reflector中显示的IL或C#源码并没有立即更新,必须保存修改后使用Reflector重新打开才能看到所做的修改。这多少有点让人感觉不爽,但比起 ilasm + ildasm 这种纯手工逆向工具来讲已经好太多了。

还有一点要说明的是:.Net Reflector很早就转向收费软件了,而且价格不菲,普通版95刀每用户,专业版甚至要199刀。对于我们大多数开发人员来说逆向并不是我们的日常工作,可能只是偶尔好奇而为之,这样为了偶尔的好奇而需要支付这么多的money实在是让人有点舍不得。于是一部分人走上了破解和盗版的路,而另一部分人走上了开源的路。这也是下一节将要介绍的ILSpy工具的由来。

三、ILSpy

ILSpy 是为了完全替代收费的Reflector而生,它是由 iCSharpCode 团队出品,这个团队开发了著名的 SharpDevelop 。ILSpy 完全开源,目前还处于开发阶段,很多功能还不够完善,但是具有强大的反编译功能对于我们来说已经足够了。对于ILSpy的使用和上面的Reflector完全类似,此处不再赘述。

在我写这篇博客的时候,ILSpy最新的发布版本为3/9/2015 Version 2.3,还没有和Reflexil具有类似功能的代码修改插件。但是在ILSpy的Further Down the Road可以看到,这样的功能也已经在计划之中了。

ilspy-down-road.png

虽然官方的发布版本还没有提供Reflexil的功能,但是Reflexil的作者sailro很早就在项目描述中介绍了对ILSpy的支持:

Reflexil is an assembly editor and runs as a plug-in for Red Gate's Reflector, ILSpy and Telerik's JustDecompile. Reflexil is using Mono.Cecil, written by Jb Evain and is able to manipulate IL code and save the modified assemblies to disk. Reflexil also supports C#/VB.NET code injection.

得益于ILSpyReflexil都是开源的,我们从GitHub上把最新的代码Clone下来并进行编译,Reflexil\Plugins\Reflexil.ILSpy这个目录下是Reflexil插件的源码,我们将编译后的所有dll文件拷贝到ILSpy的bin目录,运行ILSpy就能在View选项中看到Reflexil了,如下图:

ilspy-view.png

关于ILSpy和Reflexil的操作和上面介绍的Reflector几乎一样,不过有一点很让人振奋,ILSpy提供了更新对象模型的功能,这样Reflexil插件就可以在修改完代码后直接更新ILSpy的代码了,而不用像Reflector那样需要重新加载才能看到所做的修改。如下图所示,点击“Update ILSpy object model”,上面ILSpy的代码会立即更新:

ilspy-reflexil.png

四、Just Decompile

相信不少人都听过 Telerik 公司,该公司非常关注于.Net平台下的控件研发,并且发布了很多著名的开发工具,例如:Fiddler 和 JustDecompile。JustDecompile 正是 Telerik 的一款.Net反编译工具,和ILSpy不同的是,它并不是完全开源的,但是它有着商业化的技术支持,这一点非常难得。不仅如此,Telerik 也开源了JustDecompile的引擎部分:JustDecompile Engine,这也是非常不错的。
JustDecompile在使用上和其他的反编译工具差不多,而且它也具有插件系统,官方目前提供了三个插件,如下:

jd-plugins.png

其中Assembly Editor正是Reflexil。从菜单Plugins中调出Reflexil,enjoy it!

jd-reflexil.png

五、dotPeek

JetBrains是捷克的一家软件开发公司,出品了大量著名的开发工具,包括:IntelliJ IDEA、PHPStorm、ReSharper、TeamCity、YouTrack等等,每一款产品都如雷贯耳。dotPeek 是 JetBrains 开发的一款.Net反编译工具,是.Net工具套件中的一个,其他的还有dotTrace、dotCover 和 dotMemory。相比于前面几款工具来说,dotPeek算比较小众的一款。个人感觉它最大的特色就是Visual Studio风格,这对于那些长期在Visual Studio下进行开发的人来说应该更亲切一点。

dotPeek.png

不过dotPeek目前好像还没有类似于Reflexil这样的编辑插件,本身也并没有编辑功能。如果我们需要修改程序集的话,可以另存为工程文件,使用Visual Studio打开直接修改源码重新编译。

六、更多选择

实际上,利用上面介绍的这些工具已经完全能够满足你的需求了。但是我们总是有更多选择(等有时间的时候再玩这些吧):

另外,本文中的一些工具可以在此下载

TODO:Mono.Cecil

这篇博客的主要目的本来只是在无源码的情况下修改.Net程序集,但到这里已经完全演变成了.Net反编译工具的罗列清单。Never mind,关于.Net程序集的修改,上面最耀眼的非Reflexil莫属。而Reflexil依赖于Jb Evain所写的Mono.Cecil,Cecil 是一个对于Mono项目具有战略意义的函数库。它为很多项目(包括:Mono Debugger、Gendarme 和 MoMA 等)提供了内部处理的能力,而且 Cecil 也能操作编译好的CIL,并把修改后的程序集保存到磁盘里。

作为一个.Net程序员,修改.Net程序集最终极的方法莫过于自己动手写出修改程序集的代码,利用Mono.Cecil可以轻松实现这个目的。暂且给自己挖个坑,以后填上吧。

参考

  1. 操作步骤:用ildasm/ilasm修改IL代码 - dudu - 博客园
  2. Ilasm.exe(IL 汇编程序)
  3. Ildasm.exe(IL 反汇编程序)
  4. MSIL Tutorial
  5. 通过学习反编译和修改IL,阅读高人的代码,提高自身的水平。 - 辰 - 博客园
  6. 初识Ildasm.exe——IL反编译的实用工具 - Youngman - 博客园
  7. Reflector 已经out了,试试ILSpy - James Li - 博客园
  8. c#:Reflector+Reflexil 修改编译后的dll/exe文件 - 菩提树下的杨过 - 博客园
  9. 几款 .Net Reflector 的替代品 - 张志敏 - 博客园
  10. Assembly Manipulation and C# / VB.NET Code Injection - CodeProject
扫描二维码,在手机上阅读!