(轉).Net反編譯實戰
當你面對一個已經部署好的網站,功能,效能都非常不給力的時候,你會怎麼辦?
當你嘗試去了解這個網站業務邏輯,程式碼邏輯和資料庫邏輯時卻發現根本沒有任何資料時你會怎麼辦?
當你準備去修改這個程式卻發現根本木有原始碼而只有一堆堆的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的類的一個物件
- 呼叫自己的方法(頁面級呼叫)
- 頁面級輸出一些結果(如表格資料之類)
具體的操作是: