Ildasm.exe 概要:
一.前言: 微軟的IL反編譯實用程序——Ildasm.exe,,可以對可執(zhí)行文件抽取出 IL 代碼,,并且給出命名空間以及類的視圖。在講述如何反編譯之前,,有必要從虛擬CPU的角度來看CLR,,這樣有助于先從正面了解代碼執(zhí)行過程,。 虛擬CPU: .NET 程序,,其核心皆為 CLR ,而同時CLR的功能卻與CPU非常相近,,其中CLR執(zhí)行IL代碼(或叫做,,IL指令)、操作數(shù)據(jù),,只不過操作的代碼不同:CPU操作機器語言,,而CLR操作IL代碼。 由上,,上述講解的是從IL--機器語言的過程,,而Ildasm則可以實現(xiàn)將可執(zhí)行程序(機器語言)--IL代碼,這就是Ildasm的主要功能,。 在Anytao的《你必須知道的.NET》中對IL代碼專門做了說明,,雖然暫時悟不透其"深遠意義",但我還是愿意去開始我的IL之旅的,,呵呵~,。 在此我們先看,Anytao對于掌握(或者了解) IL代碼的重要性: 1.通用的語言基礎(chǔ)是.NET運行的基礎(chǔ),,當我們對運行結(jié)果有異議的時候,,如何透過表面看本質(zhì),IL是必須的基礎(chǔ),; 2. IL也是更好理解,、認識CLR的基礎(chǔ); 3.大量的實例分析是以IL為基礎(chǔ)的,,所以了解IL,,是讀懂他人代碼的必備基礎(chǔ),同時自己也可以獲得潛移默化的提高,; 有上述3條影響,,足以讓任何一個有追求的人都鼓足勁,去開始IL之旅了(自然包括我,,呵呵~),。
二 .Ildasm.exe 的使用方法: 在應(yīng)用Ildasm.exe具體反編譯代碼之前,先附上MSDN對于用Ildasm.exe反編譯的經(jīng)典幫助示例: 以上來源:https://www.cnblogs.com/yangmingming/archive/2010/02/03/1662307.html
三,、使用ILDasm生成IL先看下示例代碼: class Program { static void Main(string[] args) { var loginResult = Login("foo", "111111"); if (loginResult) { Console.WriteLine("登錄成功"); } else { Console.WriteLine("登錄失敗,請重試"); } Console.ReadLine(); } private static bool Login(string userName, string password) { if (userName.Equals("johnny") && password.Equals("123456")) { return false; } return false; } }
顯然,,上述代碼針對
寫好代碼并編譯運行成功后,,在Visual Studio中點擊 “工具-> 命令行-> 開發(fā)者命令提示"
分析具體IL代碼: 1.MANIFEST清單: MANIFEST是一個附加信息列表,主要包含程序集的一些屬性,,如程序集名稱,、版本號、哈希算法等,; 2.ConsoleApplication1.Program類: 這才是我們介紹的主角,。 首先是Program類: 代碼為 .class private auto ansi beforefieldinit IlasmTest.Program
extends [System.Runtime]System.Object { } // end of class IlasmTest.Program
1).class,表示Program是一個類,。并且它繼承自程序集—mscorlib的System.Object類,; 2)private,表示訪問權(quán)限,; 3)auto,,表示程序的內(nèi)存加載全部由CLR來控制; 4)ansi,,是為了在沒有托管代碼與托管代碼之間實現(xiàn)無縫轉(zhuǎn)換,。這里主要指C、C++代碼等,; 5)beforefieldinit,,是用來標記運行庫(CLR)可以在靜態(tài)字段方法生成后的任意時刻,來加載構(gòu)造器(構(gòu)造函數(shù));
其次是 .otor方法,,代碼為: .method public hidebysig specialname rtspecialname
instance void .ctor() cil managed { // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret } // end of method Program::.ctor
1)cil managed:表示其中為IL代碼,,指示編譯器編譯為托管代碼; 2).maxstack:表示調(diào)用構(gòu)造函數(shù).otor期間的評估堆棧(Evaluation Stack) ; 3)IL_0000:標記代碼行開頭,; 4)ldarg.0:表示轉(zhuǎn)載第一個成員參數(shù),,在實例方法中指的是當前實例的引用; 5)call:call一般用于調(diào)用靜態(tài)方法,,因為靜態(tài)方法是在編譯期就確定的,。而這里的構(gòu)造函數(shù).otor()也是在編譯期就制定的。而另一指令callvirt則表示調(diào)用實例方法,, 它是在運行時確定的,,因為如前述,當調(diào)用方法的繼承關(guān)系時,,就要比較基類與派生類的同名函數(shù)的實現(xiàn)方法(virtual和new),,以確定調(diào)用的函數(shù)所屬的Method Table,; 6)ret:表示執(zhí)行完畢,返回,;
最后是Main()方法,,代碼為: .method private hidebysig static void Main() cil managed
{ .entrypoint // Code size 13 (0xd) .maxstack 8 IL_0000: nop IL_0001: ldstr "Hello world" IL_0006: call void [mscorlib]System.Console::WriteLine(string) IL_000b: nop IL_000c: ret } // end of method Program::Main
1) .entrypoint指令表示CLR加載程序時,是首先從.entrypoint開始的,,即從Main方法作為程序的入口函數(shù),; 2)ldstr:表示將字符串壓棧,在這里就是將"Hello World." 壓棧,; 3)hidebysig:表示當把此類作為基類,,存在派生類時,,此方法不被繼承,,同上構(gòu)造函數(shù);
至此,,我們對IL代碼的一些指令有了了解,,也縱觀了IL世界里的概況,呵呵~
常用IL指令擴展:
一:創(chuàng)建對象實例的IL指令 關(guān)于創(chuàng)建對象的在內(nèi)存分配的機制,,在《內(nèi)存探尋1之——值類型和引用類型的內(nèi)存分配機制》 里有了詳細的介紹,。而常用的創(chuàng)建對象的IL指令使我們更好理解對象的步驟。其主要有4種: 1.newobj: 用于創(chuàng)建引用類型的對象,; 2:ldstr:用于創(chuàng)建String對象變量,; 3.newarr:用于創(chuàng)建數(shù)組型對象; 4:box:在值類型轉(zhuǎn)換為引用類型的對象時,,將值類型拷貝紙托管堆上分配內(nèi)存,;
二:通過IL代碼,更好地理解屬性 我們在C++中,,在典型的類中,,都會定義用于控制有效性輸入的Set()函數(shù),以及用于不同方式顯示的Get()函數(shù),。然而在C#中,,它將Get()函數(shù)和Set()結(jié)合在一起,剛開始難免會為之混淆,。然而若通過 Ildasm.exe對程序反編譯后觀察屬性的本質(zhì),,即可看到其執(zhí)行機制,如下圖示(注:選自互聯(lián)網(wǎng)):
由我們前面的分析IL代碼的方法,,以及上圖的展示,,我們可以看到屬性被重新分為Get()函數(shù)和Set()函數(shù)。ex,,屬性Name,,被分解為get_Name()函數(shù)和set_Name(String s)函數(shù),。這樣我們對其本質(zhì)就一目了然了!至于其屬性的特殊表示形式,,只看做是Set()函數(shù)和Get()函數(shù)的完美結(jié)合體就可以了,,這也是C#語言的優(yōu)美體現(xiàn)啊,呵呵~
綜述之,,我們對反編譯工具Ildasm.exe有了一定認識,,最主要的,我們通過它反編譯的IL代碼,,對基本的IL指令有了一定的了解,,也對以后的在把IL代碼作為有力工具 使用的過程中,更向前了一步,!然而,,這些都還只是IL的基礎(chǔ),需要繼續(xù)深入,,呵呵~
附:感謝姚凱(K-night),百忙之中對本文 代碼提供的支持,,呵呵~ |
|