当你面对一个已经部署好的网站,功能,性能都非常不给力的时候,你会怎么办?
当你尝试去了解这个网站业务逻辑,代码逻辑和数据库逻辑时却发现根本没有任何资料时你会怎么办?
当你准备去修改这个程序却发现根本木有源代码而只有一堆堆的DLL和aspx的时候,你会怎么办?
当你发现这个网站配置及其复杂,只有一个线上环境而且处处是坑的时候,你会怎么办?
当你面对一个要求严格的领导,心怀一切皆有可能的思想时,准备让你对此进行优化和功能修改时,你会怎么办?
重构?罢工?辞职?
不错,是个选择!
要是那样的话,就不会有这篇文章了亲。
所以,只有硬着头皮干下去。。
言归正传,首先介绍几款神器:
1.Reflector ——.Net反编译工具
我用的是8.0的破解版,支持直接运行和以VS插件形式运行,测试表示以VS插件的形式速度比较慢,容易将VS卡死,所以不推荐。
2.Ilasm和ildasm——微软自带的编译和反编译工具
这两款工具是Framework自带的,虽然界面不是很华丽,但是功能还是很给力的。
3.Reflexil——一款Reflector插件
相当给力,可以通过界面的形式对DLL中的类,方法,属性等进行修改和注入
有了几款神器,下面就是如何对一个DLL进行开刀了。
首先,在不清楚DLL作用的情况下,可以先通过aspx页面找一些线索。
<%@ Page Language= "C#"
MasterPageFile= "Template/LogonMasterPage.Master"
AutoEventWireup= "true"
Inherits= "Logon"
Codebehind= "Logon.aspx.cs"
%>
|
如页面顶部Inherits表示的是这个页面 定义供页继承的代码隐藏类,在DLL中搜索这个类可以找到该页面的一些后台代码逻辑。
结合aspx的服务器控件的事件可以找到对应的实现。
找到了对应的C#代码,是时候对其进行大显身手了。
此时的需求可能有如下几个:
- 修改某一个变量的值(如某个SQL语句字符串)
- 修改某一个方法的具体实现逻辑(如修改某一个按钮点击后做的一些事情)
- 在原有的逻辑中,补充插入自己的新方法或程序中已有的方法。
- 其他未想到的需求。。
下面挨个解决。
1.修改变量的值。
这类问题应该是最简单的一类问题,在我最初没有发现神器插件的时候,用了这样一种相对复杂的方法去做的。
当时的需求是修改程序中的一个执行较慢的SQL语句,也就是改某个字符串的值。
首先我用Reflector查看到相应的方法代码(C#代码),也就是我要修改的那个字符串所在的方法。然后在Reflector工具的上方有个下拉菜单
该菜单可以查看对应该方法C#代码的IL代码,这就给我们这些看不太懂IL代码的童鞋们一些希望了。通过IL视图,我们能够查看到这个方法的IL代码是类似这样的:
由于微软提供的工具可以支持DLL与IL代码的相互转化,那么我们就可以通过修改原始IL代码来重新生成DLL实现修改DLL的目的!那么该如何去做呢?
首先打开ildasm工具,该工具所在的位置大致是:
C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin
打开后将DLL文件拖进去,即可查看该DLL的一些结构:
其中展开可以看到某一个方法的IL代码。
通过该工具可以将DLL转储为IL代码文件,操作是:文件->转储
接下来通过文本编辑器可以查看il文件,由于刚才我们已经通过Reflector定位到了某个方法的IL代码,通过搜索il代码,可以比较容易的找到。(后来又发现了一个更好的方法,由于Reflector工具和微软的工具是两款工具,生成的IL有一些细微的差别,更好的做法是通过ildasm查看到需要修改的方法的原始IL代码,再在文本编辑器里搜索)
接下来就是修改具体的代码了,字符串啊,想改成什么就改成什么,即使我们看不太懂IL命令。
修改后需要重新编译回DLL文件,这就需要请出我们的又一个神器ilasm了,这是一个需要用命令行运行的工具。运行方法是:
//先要找到.net具体版本下的这个目录。
cd C:\Windows\Microsoft.NET\Framework\v2.0.50727
//执行转换操作
ilasm c:\test.il /output=c:\test.dll /dll
意思是将C盘下的test.il文件输出成test.dll文件,没有错误的话就可以成功生成。
PS:有时候还需要将转储后的其他相关文件一起拷贝过来才能成功生成DLL。
2.修改某一个方法的具体实现逻辑
这个就相对有点复杂了,不同情况有不同的处理方式,需要用到一些小技巧。
- 修改方法体相对简单的方法。
这种情况只需要Reflector插件就可以搞定了,因为该插件有一个给力的功能就是能以C#视图去修改某个方法的IL代码。有图有真相:
在IL代码中右键 Replace all…可以打开一个C#代码编辑器:
该编辑器中左侧是C#代码,右侧是如果编译成功会显示的IL代码。
这个编译器有几点使用心得:
- 需要修改的方法,打开后默认变成空的了。所有如果是小改动,需要提前复制好代码。
- 代码中使用的对象除了C#基本的数据类型外,一般都需要写全限定名称。如DataTable dt就应该写成:System.Data.DataTable dt,否则不会编译通过。
- 对于引用了外部程序集中的对象,需要自己手工在#region " Imports "中自行添加using了哪个程序集。
- 基本修改后尝试点击左下角的编译按钮,如果报错的话,定位到下面的字段说明中,可以把报错的那行注释掉。
- 编译通过后,记得把这段代码保存起来,因为下次一旦再修改这段代码,就不用重新改了,省去了一些时间。
修改后点击左侧树形目录的那个程序集,右键,save as,如果不报错,OK,搞定!
2.修改方法体相对复杂的方法。
对于这种修改,上述方法很可能不容易编译通过,因为牵连的东西比较多,所以……
需要将原程序段中的方法调用,改为一个新的方法调用。(新方法如果和旧方法差异不大的话可以把旧方法进行一个“克隆”)新的方法可以是自己新建DLL中的一个方法(最好是静态方法),而且保险起见,新方法的参数类型和名称尽量和旧方法一致,便于直接修改IL。
调用自己的方法,需要先将自己的DLL拖入Reflector中关联起来。然后在IL视图里找到调用旧方法的那一段(IL表格中的那一行),右键编辑,进行修改。修改时对于调用静态方法使用call指令,具体的方法可以在不同DLL中进行选择。
如图:
之后进行保存就可以了。
如果是对原有方法进行的简单修改,可以采用“克隆”的方法进行操作。
所谓克隆,就是用工具像原有dll中注入一个新的方法。
注入方法时,输入方法名即可,确定后不会立刻看到该方法,需要将DLL保存后,重新加载才能看到。
重新加载后,看到的新方法默认是Void的,而且不带任何参数,这和我们克隆的目标方法可能不太一样,所以,还需要改一下参数和返回值类型以及其他相关属性,修改的方法是比较修改法。即在克隆方法的选项卡中依次比较每一个选项,修改成和目标方法一模一样的新方法。
修改新方法的各个属性。
再次保存。即可克隆出一个方法签名类似的新方法。
接下来就是克隆方法体了,这里还有个技巧,如果方法简单,直接通过C#视图就可以将原方法体粘贴进去,编译。
如果方法体复杂,则需要通过之前提到的微软工具进行IL代码的移植。即,复制原方法的IL代码实现,粘贴到克隆方法的方法体中。
这些操作中可能会遇到的一些注意事项:
添加方法时的参数可参考已有方法的参数界面进行选择,其中System下的对象在microlib.dll里。
il编译不通过可以增加Using,下面字段里不要添加自己的对象,否则无法生成dll(可以把属性用私有成员替代!)
使用C#视图无法调用新注入的函数时,可以先克隆一个原有函数(函数头一样的),然后再使用IL视图的Edit功能把旧方法换成克隆后的方法。最后再修改克隆后的实现。
每次增加新方法,需要更新关联的DLL
Clone方法头可以使用reflecxil工具,克隆复杂的方法体,可以使用微软IL工具,查看到具体的方法的IL代码,复制。然后用文本编辑器找到Clone的方法体,粘贴。重新编译。
此外还可以尝试修改类成员的访问权限,如改成public,注入其他成员等。
除了在DLL中下手调用新的方法,还可以直接通过aspx页面进行修改。
步骤大概是:
- 准备一个需要调用的方法(自己的DLL中)
- 在aspx页面头添加对自己dll的引用
- 实例化自己dll的类的一个对象
- 调用自己的方法(页面级调用)
- 页面级输出一些结果(如表格数据之类)
具体的操作是: