入門
IL是什么?
IL(Intermediate Language),它也稱為CIL或者M(jìn)SIL,中文就是“中間語言”。IL由ECMA組織(ECMA-335標(biāo)準(zhǔn))提供完整的定義和規(guī)范。我們可以直接把C#源碼編譯為.exe或dll文件,但是此時(shí)編譯出來的程序代碼并不是CPU能直接執(zhí)行的二進(jìn)制代碼,而是IL代碼。
IL分析工具,如何使用?
工具
- ILDasm.exe
# 尋找路徑
+ C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX x.x Tools
# 官方文檔
+ https://docs.microsoft.com/en-us/dotnet/framework/tools/ildasm-exe-il-disassembler
ILDasm.exe說明
1. 可視化分析
- 編寫常見的HelloWorld,沒有復(fù)雜的代碼。
using System;
namespace ILLearning
{
class Program
{
static void Main(string[] args)
{
string helloString = "Hello World";
Console.WriteLine(helloString);
Console.ReadLine();
}
}
}
使用csc.exe編譯,具體可以參考:C#命令行編譯器的步驟介紹
-
運(yùn)行ILDasm.exe,拖剛剛編譯的exe進(jìn)來,界面如下:
參考ILDasm_MainForm.png
從上圖可以看到IL結(jié)構(gòu):包含MANIFEST文件和ILLearning,其中MANIFEST是一個(gè)清單文件,主要包括程序集的一些屬性,例如程序集名稱、版本號(hào)、哈希算法、程序集模塊,以及對(duì)外部引用程序的引用項(xiàng)目。.Program類是我們要主要介紹的內(nèi)容。
2. 命令行操作
-
常見命令
> ildasm MyFile.exe /output:MyFile.il
IL指令
-
-
Emit實(shí)踐
using System; using System.Reflection; using System.Reflection.Emit; namespace ILLearning { class EmitTest { static void Main(string[] args) { #region Emit練習(xí) // specify a new assembly name var assemblyName = new AssemblyName("World"); // create assemblybuilder /* * AssemblyBuilderAccess枚舉值說明: * AssemblyBuilderAccess.Run; 表示程序集可被執(zhí)行,但不能被保存?! ? * AssemblyBuilderAccess.Save; 表示程序集可被保存,但不能被執(zhí)行。 * AssemblyBuilderAccess.RunAndSave; 表示程序集可被保存并能被執(zhí)行。 * AssemblyBuilderAccess.ReflectionOnly; 表示程序集只能用于反射上下文環(huán)境中,不能被執(zhí)行?!? * AssemblyBuilderAccess.RunAndCollect; 表示程序集可以被卸載并且內(nèi)存會(huì)被回收。 * */ var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave); // create module builder var moduleBuilder = assemblyBuilder.DefineDynamicModule("WorldModule", "HelloWorld.exe"); // create type builder for a class Name var typeBuilder = moduleBuilder.DefineType("HelloWorld", TypeAttributes.Public); // create method buider var methodBuilder = typeBuilder.DefineMethod("SayHello", MethodAttributes.Public | MethodAttributes.Static, null, null); // get il genereator var il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldstr, "Hello,World"); il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); il.Emit(OpCodes.Call, typeof(Console).GetMethod("ReadLine")); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ret); var helloworldClassType = typeBuilder.CreateType(); assemblyBuilder.SetEntryPoint(helloworldClassType.GetMethod("SayHello")); assemblyBuilder.Save("HelloWorld.exe"); #endregion Console.WriteLine( "Hi, a Hello Emit assembly has been generated for you."); Console.ReadLine(); } } }
-
深化
讀懂基礎(chǔ)的IL,在實(shí)際開發(fā)中應(yīng)用,具體實(shí)踐,留坑先
讀懂IL
- 讀懂加減法的IL
// Microsoft (R) .NET Framework IL Disassembler. Version 4.7.2053.0
// Copyright (c) Microsoft Corporation. All rights reserved.
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly demo // 指定程序集的名稱
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )
.hash algorithm 0x00008004 // 指定的hash算法
.ver 0:0:0:0 // 指定程序集的版本
}
.module demo.exe // 指定組成程序集的模塊名稱,在此示例中,程序集中只包含一個(gè)文件
// MVID: {61F485FC-2FB2-46D9-B2EE-29E5F44AF6CA}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI //指定程序要求的應(yīng)用程序環(huán)境。在此示例中,0x0003表示該可執(zhí)行文件從控制臺(tái)運(yùn)行
.corflags 0x00000001 // ILONLY // 當(dāng)前是元數(shù)據(jù)中的一個(gè)保留字段
// Image base: 0x05610000
// =============== CLASS MEMBERS DECLARATION ===================
/*
.class表示的Program是一個(gè)類,extends 代表Program類繼承于程序集mscorlib中的System.Object類,這就告訴我們,在C#中所有的類的父類都是Object。
private為訪問權(quán)限,表明該類是私有的。
auto:表明程序加載的時(shí)候內(nèi)存布局是有CLR決定的,而不是由程序本身控制的。
ansi:表明類的編碼為ansi編碼
beforefieldinit :表明CLR可以在第一次訪問靜態(tài)字段之前的任何時(shí)刻執(zhí)行類型構(gòu)造函數(shù)。類型構(gòu)造函數(shù)也就是構(gòu)造函數(shù),而使用beforefieldinit屬性可以提高性能。
*/
.class private auto ansi beforefieldinit ILLearning.Program
extends [mscorlib]System.Object
{
// main函數(shù)
// cil managed 表明方法體中的代碼是IL代碼,且是托管代碼,即運(yùn)行在CLR運(yùn)行庫(kù)中的代碼
// hidebysig :指令表示如果當(dāng)前類作為父類,用該指令標(biāo)記的方法將不會(huì)被子類繼承
.method private hidebysig static void Main(string[] args) cil managed
{
// .entrypoint :指令代表該函數(shù)是程序的入口函數(shù),每個(gè)托管應(yīng)用程序都有且只有一個(gè)入口函數(shù),CLR加載的時(shí)候,首先從.entrypoint函數(shù)開始執(zhí)行。
.entrypoint
// Code size 34 (0x22)
// .maxstack 表明執(zhí)行構(gòu)造函數(shù)時(shí),評(píng)估堆??扇菁{數(shù)據(jù)項(xiàng)的最大個(gè)數(shù)。評(píng)估堆棧是保存方法中所需變量的值的一個(gè)內(nèi)存區(qū)域,該區(qū)域在方法執(zhí)行結(jié)束時(shí)會(huì)被清空,或者存儲(chǔ)一個(gè)返回值
.maxstack 2
// .locals init ([0] string helloString) 表示定義string 類型的變量,變量名成為:helloString
.locals init (int64 V_0,
int32 V_1,
float32 V_2,
int64 V_3)
// IL_0000是代碼行的開頭。一般在IL_標(biāo)記之前的部分為變量的聲明和初始化操作。
// IL_0000: nop 表示不做任何操作 No Operation
IL_0000: nop
// (以ld為前綴的指令表示:入棧操作 st為前綴的指令則代表著出棧操作)
IL_0001: ldc.i4.0 // 將整數(shù)值 0 作為 int32 推送到計(jì)算堆棧上。
IL_0002: conv.i8 // 將位于計(jì)算堆棧頂部的值轉(zhuǎn)換為 int64。
IL_0003: stloc.0 // 從計(jì)算堆棧的頂部彈出當(dāng)前值并將其存儲(chǔ)到索引 0 處的局部變量列表中。
IL_0004: ldc.i4.2
IL_0005: stloc.1
IL_0006: ldc.r4 1. // 將所提供的 float32 類型的值作為 F (float) 類型推送到計(jì)算堆棧上。
IL_000b: stloc.2
IL_000c: ldloc.0 //將索引 0 處的局部變量加載到計(jì)算堆棧上。 // 拿出a的值
IL_000d: ldloc.1 // 拿出b的值
IL_000e: conv.i8 // 將b強(qiáng)制轉(zhuǎn)換成long類型
IL_000f: add // 相加
IL_0010: ldloc.2
IL_0011: conv.i8
IL_0012: add
IL_0013: stloc.3
IL_0014: ldloc.3
// call :指令表示調(diào)用靜態(tài)函數(shù), 這里調(diào)用的是Console類中的WriteLine函數(shù),把第0個(gè)局部變量輸出到控制臺(tái)中
IL_0015: call void [mscorlib]System.Console::WriteLine(int64)
IL_001a: nop
IL_001b: call string [mscorlib]System.Console::ReadLine()
IL_0020: pop
IL_0021: ret // 返回
} // end of method Program::Main
// 默認(rèn)的構(gòu)造函數(shù),其中.ctor 表示構(gòu)造函數(shù)
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method Program::.ctor
} // end of class ILLearning.Program
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file C:\Users\87953\Desktop\Demos\demo.res
- 帶有if分支的IL分析
// Microsoft (R) .NET Framework IL Disassembler. Version 4.7.2053.0
// Copyright (c) Microsoft Corporation. All rights reserved.
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly demo
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module demo.exe
// MVID: {35CECF14-04D6-4E7E-AE4B-94F2DFB943BD}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x06EB0000
// =============== CLASS MEMBERS DECLARATION ===================
.class private auto ansi beforefieldinit ILLearning.Program
extends [mscorlib]System.Object
{
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 50 (0x32)
.maxstack 2
.locals init (int64 V_0,
string V_1,
bool V_2)
IL_0000: nop
IL_0001: ldc.i4.3 // 將所提供的 int32 類型的值作為 int32 推送到計(jì)算堆棧上。
IL_0002: conv.i8 // 轉(zhuǎn)換成long
IL_0003: stloc.0 // 出棧,賦值到a中
IL_0004: ldstr "hello,kitty" // 字符串入棧
IL_0009: stloc.1 // 出棧,賦值給b
IL_000a: ldloc.0 // 將索引 0 處的局部變量加載到計(jì)算堆棧上。
IL_000b: ldc.i4.5 // 將所提供的 int32 類型的值作為 int32 推送到計(jì)算堆棧上。
IL_000c: conv.i8
IL_000d: cgt
IL_000f: stloc.2
IL_0010: ldloc.2
/*
* Brfalse 如果 value 為 false、空引用(Visual Basic 中的 Nothing)或零,則將控制轉(zhuǎn)移到目標(biāo)指令。
* Brfalse.S 如果 value 為 false、空引用或零,則將控制轉(zhuǎn)移到目標(biāo)指令。
* Brtrue 如果 value 為 true、非空或非零,則將控制轉(zhuǎn)移到目標(biāo)指令。
* Brtrue.S 如果 value 為 true、非空或非零,則將控制轉(zhuǎn)移到目標(biāo)指令(短格式)。
*/
IL_0011: brfalse.s IL_0022
IL_0013: nop
IL_0014: ldstr "hello world"
IL_0019: call void [mscorlib]System.Console::WriteLine(string)
IL_001e: nop
IL_001f: nop
/*
* Br 無條件地將控制轉(zhuǎn)移到目標(biāo)指令。
* Br.S 無條件地將控制轉(zhuǎn)移到目標(biāo)指令(短格式)。
*/
IL_0020: br.s IL_002b
IL_0022: nop
IL_0023: ldloc.1
IL_0024: call void [mscorlib]System.Console::WriteLine(string)
IL_0029: nop
IL_002a: nop
IL_002b: call string [mscorlib]System.Console::ReadLine()
IL_0030: pop
IL_0031: ret
} // end of method Program::Main
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method Program::.ctor
} // end of class ILLearning.Program
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file C:\Users\87953\Desktop\Demos\demo2.res
- const會(huì)給CLR變成static
// Microsoft (R) .NET Framework IL Disassembler. Version 4.7.2053.0
// Copyright (c) Microsoft Corporation. All rights reserved.
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly demo
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module demo.exe
// MVID: {94F20870-93B0-42E9-8F35-6716A4FE3711}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x00C30000
// =============== CLASS MEMBERS DECLARATION ===================
.class private auto ansi beforefieldinit ILLearning.Program
extends [mscorlib]System.Object
{
.class auto ansi nested assembly beforefieldinit model
extends [mscorlib]System.Object
{
// Const 會(huì)給轉(zhuǎn)換成static
.field public static literal int32 NUM = int32(0x00000003)
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method model::.ctor
} // end of class model
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 15 (0xf)
.maxstack 8
IL_0000: nop
IL_0001: ldc.i4.3
IL_0002: call void [mscorlib]System.Console::WriteLine(int32)
IL_0007: nop
IL_0008: call string [mscorlib]System.Console::ReadLine()
IL_000d: pop
IL_000e: ret
} // end of method Program::Main
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method Program::.ctor
} // end of class ILLearning.Program
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file C:\Users\87953\Desktop\Demos\demo3.res
- 裝箱和拆箱的IL
// Microsoft (R) .NET Framework IL Disassembler. Version 4.7.2053.0
// Copyright (c) Microsoft Corporation. All rights reserved.
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly program
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module program.exe
// MVID: {D837361F-CAC0-4972-821B-185D239C749A}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x00C40000
// =============== CLASS MEMBERS DECLARATION ===================
.class private auto ansi beforefieldinit ILLearning.Program
extends [mscorlib]System.Object
{
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 31 (0x1f)
.maxstack 1
.locals init (int32 V_0,
object V_1,
int32 V_2)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: box [mscorlib]System.Int32 // 裝箱
IL_0009: stloc.1
IL_000a: ldloc.1
IL_000b: unbox.any [mscorlib]System.Int32 // 拆箱
IL_0010: stloc.2
IL_0011: ldloc.2
IL_0012: call void [mscorlib]System.Console::WriteLine(int32)
IL_0017: nop
IL_0018: call string [mscorlib]System.Console::ReadLine()
IL_001d: pop
IL_001e: ret
} // end of method Program::Main
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method Program::.ctor
} // end of class ILLearning.Program
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file demo4.res
