前一章(點擊可以看前一章內容),我們講解了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 ) // .z\V.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 ) // .z\V.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:\U8Soft\Ufcomsql\U8Login.dll /reference:"C:\U8Soft\Interop\MSXML2.dll"
Tlbimp.exe C:\U8Soft\Ufcomsql\USERPCO.dll /reference:"C:\U8Soft\Interop\Interop.U8Login.dll" /reference:"C:\U8Soft\Interop\MSXML2.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時,面臨的新問題