使用C#的猿人或多或少都會對微軟的IL反編譯工具(ildasm.exe)有所認識。我最早接觸到這工具是公司同事使用他反編譯exe程序,進行研讀和修改。感覺他還是很強大。
IL是微軟平台上的一門中間語言,我們常寫的C#代碼在編譯器中都會自動轉換成IL,然後在由即時編譯器(JIT Compiler)轉化機器碼,最後被CPU執行。ildasm.exe反編譯工具將IL匯編成可跨平台可執行的(pe)文件。可供我們了解別人代碼和修改。有了他我們看待問題可以不用停留在編輯器層面,可深入中間層。
我們在安裝VS同時都會自動安裝ildasm工具,無需另行安裝。ildasm工具打開方法如下圖:
我們也可以直接wind+R.輸入:C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\ildasm.exe (window 7 64位 操作系統安裝目錄) 同樣可以打開ildasm。
我們也可以把ildasm工具增加到我們常用的VS中。
1.工具(Tools)-->外部工具(External Tools..)
2.添加內容填寫對應信息。命令:C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\ildasm.exe
(window 7 64位 操作系統安裝目錄) 。
已上信息填寫完成後,在“工具”選擇卡中能找到我們剛增加的外部工具名稱(IL_DASM)。增加完成後可以小試一把。
國際慣例來段"Hello World"。代碼編寫完後直接F6生成exe文件,然後工具-->IL_DASM-->確認(無需修改任何參數,默認目標文件路徑)。系統會彈出IL工具,我們雙擊Main方法。
這時可以看到Main方法在IL中編譯的代碼。感覺有點陌生不易看懂。 還有IL編譯出現的三角型,正方型都是啥!
1.圖標含義
使用IL反編譯出項目代碼
MANIFEST:是一個附加信息列表,主要包含程序集的一些屬性,如程序集名稱、版本號、哈希算法等;
Democode:項目名稱
Democodeing.Common:命名空間
Democodeing.ICar:接口
Democodeing.Program:類,主要查看存類下面的內容。
.class 類信息項代碼:
.class private auto ansi beforefieldinit DemoCoding.Program extends [mscorlib]System.Object { } // end of class DemoCoding.Program
1).class,表示Program是一個類。並且它繼承自程序集—mscorlib的System.Object類;
2)private,表示訪問權限;
3)auto,表示程序的內存加載全部由CLR來控制;
4)ansi,是為了在沒有托管代碼與托管代碼之間實現無縫轉換。這裡主要指C、C++代碼等;
5)beforefieldinit,是用來標記運行庫(CLR)可以在靜態字段方法生成後的任意時刻,來加載構造器(構造函數);
.ctor 方法代碼:
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // 代碼大小 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:表示調用構造函數.otor期間的評估堆棧(Evaluation Stack) ;
3) IL_0000:標記代碼行開頭;
4)ldarg.0:表示轉載第一個成員參數,在實例方法中指的是當前實例的引用;
5)call:call一般用於調用靜態方法,因為靜態方法是在編譯期就確定的。而這裡的構造函數.otor()也是在編譯期就制定的。而另一指令callvirt則表示調用實例方法, 它是在運行時確定的,因為如前述,當調用方法的繼承關系時,就要比較基類與派生類的同名函數的實現方法(virtual和new),以確定調用的函數所屬的Method Table;
6)ret:表示執行完畢,返回;
Main() 靜態方法代碼:
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // 代碼大小 19 (0x13) .maxstack 8 IL_0000: nop IL_0001: ldstr "Hello World" IL_0006: call void [mscorlib]System.Console::WriteLine(string) IL_000b: nop IL_000c: call string [mscorlib]System.Console::ReadLine() IL_0011: pop IL_0012: ret } // end of method Program::Main
1) hidebysig:表示當把此類作為基類,存在派生類時,此方法不被繼承,同上構造函數;
2).entrypoint:指令表示CLR加載程序時,是首先從.entrypoint開始的,即從Main方法作為程序的入口函數;
3)nop:為空該指令,主要給外部設備或者指令間隙准備時間;
4)ldstr:創建String對象變量"Hello World." ;
5)pop:取出棧頂的值。當我們不需要把值存入變量時使用;
1.打開IL工具,選擇所要修改的EXE程序。
2.文件-->轉儲。確定後選擇另存路徑,會生成二個文件:*.il 和 *.res
3.用記事本打開*.il修改裡面的內容:
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // 代碼大小 19 (0x13) .maxstack 8 IL_0000: nop IL_0001: ldstr "Hello World-[已使用il工具修改過...]" IL_0006: call void [mscorlib]System.Console::WriteLine(string) IL_000b: nop IL_000c: call string [mscorlib]System.Console::ReadLine() IL_0011: pop IL_0012: ret } // end of method Program::Main
4.把修改後的代碼編譯成EXE程序。
ilasm /exe /output=C:\CK.exe /Resource=C:\Users\Ck\Desktop\coding.res C:\Users\Ck\Desktop\coding.il
修改就這麼簡單。運行修改後的EXE程序,值已修改。