天天看點

.Net反編譯實戰

當你面對一個已經部署好的網站,功能,性能都非常不給力的時候,你會怎麼辦?

當你嘗試去了解這個網站業務邏輯,代碼邏輯和資料庫邏輯時卻發現根本沒有任何資料時你會怎麼辦?

當你準備去修改這個程式卻發現根本木有源代碼而隻有一堆堆的DLL和aspx的時候,你會怎麼辦?

當你發現這個網站配置及其複雜,隻有一個線上環境而且處處是坑的時候,你會怎麼辦?

當你面對一個要求嚴格的上司,心懷一切皆有可能的思想時,準備讓你對此進行優化和功能修改時,你會怎麼辦?

重構?罷工?辭職?

不錯,是個選擇!

要是那樣的話,就不會有這篇文章了親。

是以,隻有硬着頭皮幹下去。。

言歸正傳,首先介紹幾款神器:

1.Reflector ——.Net反編譯工具

  我用的是8.0的破解版,支援直接運作和以VS插件形式運作,測試表示以VS插件的形式速度比較慢,容易将VS卡死,是以不推薦。

2.Ilasm和ildasm——微軟自帶的編譯和反編譯工具

  這兩款工具是Framework自帶的,雖然界面不是很華麗,但是功能還是很給力的。

3.Reflexil——一款Reflector插件

  相當給力,可以通過界面的形式對DLL中的類,方法,屬性等進行修改和注入

有了幾款神器,下面就是如何對一個DLL進行開刀了。

首先,在不清楚DLL作用的情況下,可以先通過aspx頁面找一些線索。

 如頁面頂部Inherits表示的是這個頁面 定義供頁繼承的代碼隐藏類,在DLL中搜尋這個類可以找到該頁面的一些背景代碼邏輯。

 結合aspx的伺服器控件的事件可以找到對應的實作。

找到了對應的C#代碼,是時候對其進行大顯身手了。

此時的需求可能有如下幾個:

修改某一個變量的值(如某個SQL語句字元串)

修改某一個方法的具體實作邏輯(如修改某一個按鈕點選後做的一些事情)

在原有的邏輯中,補充插入自己的新方法或程式中已有的方法。

其他未想到的需求。。

下面挨個解決。

1.修改變量的值。

這類問題應該是最簡單的一類問題,在我最初沒有發現神器插件的時候,用了這樣一種相對複雜的方法去做的。

當時的需求是修改程式中的一個執行較慢的SQL語句,也就是改某個字元串的值。

首先我用Reflector檢視到相應的方法代碼(C#代碼),也就是我要修改的那個字元串所在的方法。然後在Reflector工具的上方有個下拉菜單

.Net反編譯實戰

該菜單可以檢視對應該方法C#代碼的IL代碼,這就給我們這些看不太懂IL代碼的童鞋們一些希望了。通過IL視圖,我們能夠檢視到這個方法的IL代碼是類似這樣的:

.Net反編譯實戰

由于微軟提供的工具可以支援DLL與IL代碼的互相轉化,那麼我們就可以通過修改原始IL代碼來重新生成DLL實作修改DLL的目的!那麼該如何去做呢?

首先打開ildasm工具,該工具所在的位置大緻是:

C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin

.Net反編譯實戰

打開後将DLL檔案拖進去,即可檢視該DLL的一些結構:

.Net反編譯實戰

 其中展開可以看到某一個方法的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代碼。有圖有真相:

.Net反編譯實戰

在IL代碼中右鍵 Replace all…可以打開一個C#代碼編輯器:

.Net反編譯實戰

該編輯器中左側是C#代碼,右側是如果編譯成功會顯示的IL代碼。

這個編譯器有幾點使用心得:

需要修改的方法,打開後預設變成空的了。所有如果是小改動,需要提前複制好代碼。

代碼中使用的對象除了C#基本的資料類型外,一般都需要寫全限定名稱。如DataTable dt就應該寫成:System.Data.DataTable dt,否則不會編譯通過。

對于引用了外部程式集中的對象,需要自己手工在#region " Imports "中自行添加using了哪個程式集。

基本修改後嘗試點選左下角的編譯按鈕,如果報錯的話,定位到下面的字段說明中,可以把報錯的那行注釋掉。

編譯通過後,記得把這段代碼儲存起來,因為下次一旦再修改這段代碼,就不用重新改了,省去了一些時間。

修改後點選左側樹形目錄的那個程式集,右鍵,save as,如果不報錯,OK,搞定!

  2.修改方法體相對複雜的方法。

對于這種修改,上述方法很可能不容易編譯通過,因為牽連的東西比較多,是以……

需要将原程式段中的方法調用,改為一個新的方法調用。(新方法如果和舊方法差異不大的話可以把舊方法進行一個“克隆”)新的方法可以是自己建立DLL中的一個方法(最好是靜态方法),而且保險起見,新方法的參數類型和名稱盡量和舊方法一緻,便于直接修改IL。

調用自己的方法,需要先将自己的DLL拖入Reflector中關聯起來。然後在IL視圖裡找到調用舊方法的那一段(IL表格中的那一行),右鍵編輯,進行修改。修改時對于調用靜态方法使用call指令,具體的方法可以在不同DLL中進行選擇。

如圖:

.Net反編譯實戰

之後進行儲存就可以了。

如果是對原有方法進行的簡單修改,可以采用“克隆”的方法進行操作。

所謂克隆,就是用工具像原有dll中注入一個新的方法。

.Net反編譯實戰

注入方法時,輸入方法名即可,确定後不會立刻看到該方法,需要将DLL儲存後,重新加載才能看到。

重新加載後,看到的新方法預設是Void的,而且不帶任何參數,這和我們克隆的目标方法可能不太一樣,是以,還需要改一下參數和傳回值類型以及其他相關屬性,修改的方法是比較修改法。即在克隆方法的頁籤中依次比較每一個選項,修改成和目标方法一模一樣的新方法。

.Net反編譯實戰

修改新方法的各個屬性。

再次儲存。即可克隆出一個方法簽名類似的新方法。

接下來就是克隆方法體了,這裡還有個技巧,如果方法簡單,直接通過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的類的一個對象

調用自己的方法(頁面級調用)

頁面級輸出一些結果(如表格資料之類)

 具體的操作是:

.Net反編譯實戰