前一章(点击可以看前一章内容),我们讲解了Interop的三大问题,本章将引入利器,对这三个问题进行初探,并加以解决
善功必先利器
工具一 SpyStudio
这是我最近发现的一个特别牛逼的软件,主要用来HOOK程序,实时分析程序调用了那些api,读取了那些文件,用到了那些COM组件,读取了那些注册表。特别适合进行软件绿化,因为它能直接导出vmware thinapp,简直是神一样的存在,可惜不能在Win10下正常使用。但是绿化后的程序可以在各种系统下运行。
工具二 ILMergeGUI_Portable和ILMerge
用于将多个NET的DLL组件合并到一起,本来是一个命令行工具,后来我找到一个GUI的小程序,可以托拉拽了,特别强大和方便。
工具三 DotNETHelper
这也是一个杀手级别的利器,主要用来将NET反编译成IL文件,然后修改IL后,再次编译成DLL。我主要用它解决引用错误问题。因为Interop文件不能很完美反编译成C#语言,所以很多工作我都是在IL级别操作的。
工具四 TotalCmd
因为后期主要是对各种文件的操作,所以最好准备一个TC工具,可以非常方便的管理文件。对于这个软件可以说也是神级别的了,我就不多说了。自己百度吧。
工具五 Mono.Cecil
准确的说,这不是一个工具了,而是一个NET的类库,由Mono提供,可以修改Net程序的DLL文件,功能比DotHelper还要强大。因为需要对Interop文件进行批量的处理,而IL操作实在是太麻烦了,所以直接用这个类库,通过编程的方式,把我想修改的内容写成代码,然后执行,全部搞定!!
工具使用
以上的5个工具,除了SpyStudio暂时用不到,其他的工具,是下面将会用到的主要工具,所以希望大家提前去百度学习一下如何使用,这里不展开。毕竟也不是非常复杂,过程中我会尽量截图,让大家看的清除一些。
Interop文件引用修复初探
反编译观察
有了工具,我们就可以分析Interop文件了,首先拿出DotNetHelper,把Interop.U8Login.dll反编译后,看一下IL文件的开始部分信息。
文件的内容很多,但是我们主要关注开头部分,因为开头部分是引用部分,相当于我们开发C#时,引用程序集那个部分的功能,具体的格式如下:
// Metadata version: v2.0.50727
.assembly extern mscorlib{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .zV.4..
.ver 2:0:0:0}
.assembly extern ADODB{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
.ver 7:0:3300:0
}
我们这里发现Interop.U8Login.dll 引用了两个组件,一个是2.0的mscorlib,也就是framewor 2.0的基本环境。一个是ADODB,版本7.0。并且我们发现ADDOB有两个特点。
1、ADODB的这个引用带有强命名,.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )
2、ADODB这个引用前面没有Interop单词,.assembly extern ADODB,这个特征很重要,有时候我们在处理Interop.VBA.dll的时候你就会发现,有的引用居然是VBA.dll,有的是Interop.VBA.dll
分析正确文件的特点
我们再看一下,正确引用了Interop.U8Login.dll的其他Interop文件,比如下面就是我自己编译的Interop.USERPCO.dll,该类库引用了U8Login组件,这个类库也是非常重要的一个类,主要完成库存单据的保存功能。是API里面最核心的调用类。
// Metadata version: v2.0.50727
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .zV.4..
.ver 2:0:0:0
}
//这里的引用,publickey和U8login的ADODB引用是完全一样的
.assembly extern ADODB
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
.ver 7:0:3300:0
}
.assembly extern Interop.VBA
{
.ver 6:0:0:0
}
//这里的引用,没有publickey
.assembly extern Interop.USCOMMON
{
.ver 2:1:0:0
}
//注意这里的引用,有publickey
.assembly extern Interop.U8Login
{
.publickeytoken = (79 A4 E7 AD 54 EE AB CA ) // y...T...
.ver 1:14:0:0
}
.assembly extern Interop.MSXML2
{
.ver 3:0:0:0
}
注意U8Login的强命名还有版本号 ,.publickeytoken = (79 A4 E7 AD 54 EE AB CA ) .ver 1:14:0:0
注意ADODB的强命名和版本号,这两个值是(.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) .ver 7:0:3300:0 ),且和U8Login使用的ADODB完全一样,这样的文件,就是正确的,因为如果U8Login有返回值是ADODB中的类,那么这个Interop文件可以正常操作,不会出现类型转换失败的问题,因为他们引用的是同一个ADODB文件。
错误文件的特征
再看一个我们自己生成的Interop后最容易遇到的问题,往往我们自己生成Interop 文件以后,很有可能是这样的
//前面的我就忽略不贴出来了,直接看关键的U8Login的引用
.assembly extern Interop.U8Login
{
.ver 1:29:0:0
}
正确的应该如下
.assembly extern Interop.U8Login
{
.publickeytoken = (79 A4 E7 AD 54 EE AB CA ) // y...T...
.ver 1:14:0:0
}
这里之所以不一致,就是前文说的拖家带口问题导致的,其实你仔细看,就会发现在你生成的Interop文件对应的目录里面,居然还有一个Interop.U8Login.dll,而这个文件就是版本1.29那个文件。而NET程序是绝对不能引用两个同名文件的。所以必须将公用引用文件保持一致。
到此我们发现了正确文件的基本特征:
1、公用文件,比如ADODB,他们引用的名称,版本号,强命名都是完全一样的
2、彼此关联的文件,比如某DLL引用了Interop.U8Login.dll,必须保证某DLL中U8login的版本和强命名还有名称和原版的Interop.U8Login一致。
Interop引用错误的问题修改
毛爷爷教导我们,知错不改,不是好同志!既然我们知道了错误的根本原因,那么下面就开始做一名真正的好同志。
修改方法1 反编译法
之前说过,Interop.U8Login.dll不是能完美反编译成C#的,但是如果你愿意手工干预,通过后期的修改,这个项目可以完美的变成一个标准C#类库项目,然后通过修改引用,再次编译就好了。可惜,我不认为有人会这么干,因为Interop文件实在太多了,修改工作量巨大,错曾经尝试过几次,最后都放弃了。
修改方法2 命令行参数法
正统的解决方案微软其实是给出来的,就是通过在使用Tlbimp.exe这个命令行的时候,使用/reference 参数
Tlbimp.exe C:U8SoftUfcomsqlU8Login.dll /reference:"C:U8SoftInteropMSXML2.dll"
Tlbimp.exe C:U8SoftUfcomsqlUSERPCO.dll /reference:"C:U8SoftInteropInterop.U8Login.dll" /reference:"C:U8SoftInteropMSXML2.dll"
上面的代码,展示了如何使用多个已有类库文件,解决引用错误。这个方法真的非常不错,我以前也使用,后来觉得还是改IL比较有成就感,所以就不怎么用这个方法。但是我还是强力推荐该方法。
修改方法3 IL修改法
之前的整个研究过程,都是基于IL进行,所以我最早使用的就是DotNetHelper工具进行IL修改去解决这个问题的。速度也比较快,反编译,打开IL文件,找到错误点,修改,重新编译,问题解决。(这里补充一下,因为ocx控件使用AxImp工具生成AxInterop文件,但是这个命令行工具没有引用参数reference,所以只能使用IL修复法。)修改的过程如下:
//前面的我就忽略不贴出来了,直接看关键的U8Login的引用
.assembly extern Interop.U8Login
{
.ver 1:29:0:0
}
正确的应该如下
.assembly extern Interop.U8Login
{
.publickeytoken = (79 A4 E7 AD 54 EE AB CA ) // y...T...
.ver 1:14:0:0
}
本章完
下一章,开始讲解在面对繁多的U8版本和繁多的Interop时,面临的新问题