CLR和JIT的理解、.NET反匯編學習


CLR:通用語言運行時(Common Language Runtime)的簡稱,CLR是.NET框架的核心內容之一,可以把它看為一套標准資源,可以唄任何.NET程序使用。它包括:面向對象的編程模型、安全模型、類型系統(CTS)、所有.NET基類、程序執行及代碼管理等。

我們可以這樣理解,CLR是托管程序運行的環境,就像Windows是普通的PE程序的運行環境一樣。
在Windows中,整個CLR系統的實現基本其實就是幾個關鍵的DLL,比如mscorwks.dll、mscorjit.dll,它們共同的特點就是前綴均為mscor。

在win32中,可執行文件在開始運行時,有操作系統載入到內存中,然后運行文件中的.text代碼,結束時有操作系統負責卸載。而在.NET下,這個過程卻不大一樣。用PE結構查看工具(這里使用PEiD)載入一個實例文件,觀察導入表,可以發現整個表只引入了一個mscoree.dll中的一個方法:_CorExeMain。而這個方法,真是該可執行文件在win32意義上的入口點。

和win32程序一樣,.NET可執行程序在運行初始,首先有Windows將PE載入內存,然后跳至_CorExeMain中執行。分水嶺就在這,當代碼跳至_CorExeMain中之后,程序運行進入了.NET的初始化階段,經過一番准備工作,.NET框架便正式接管程序的運行了。

 

*********************************************************************

 

JIT:即時編譯(Just In-Time compile),這是.NET運行可執行程序的基本方式,也就是在需要運行的時候,才將對應的IL代碼編譯為本機指令。傳入JIT的是IL代碼,輸出的是本機代碼,所以部分加密軟件通過掛鈎JIT來進行IL加密,同時又保證程序正常運行。同解釋執行的代碼相比,JIT的執行效率要高很多。

說到這,我們先來了解下IL代碼是從哪一個步驟得到的。

MSIL是將.NET代碼轉化為機器語言的一個中間過程。它是一種介於高級語言和基於Intel的匯編語言的偽匯編語言。當用戶編譯一個.NET程序時,編譯器將源代碼翻譯成Microsoft 中間語言 (MSIL),它是一組可以有效地轉換為本機代碼且獨立於CPU的指令。當執行這些指令時,實時(JIT)編譯器將它們轉化為CPU特定的代碼。

也就是說,MSIL是一個中間語言,是由編譯器編譯而來的,屬於第一個步驟(編譯)的產物。

而當我們需要執行時,再將MSIL通過JIT即時編譯成所需的機器指令來執行。

 

下面我們來看看MSIL的樣子:

我們先用vs2012編寫一個簡單的控制台程序,hello world。

然后打開ildasm,具體步驟是這樣的

輸入命令后出現

我們將編譯好的exe程序拖拽進ildasm中。

 

我們將程序進行轉儲,也就是傳說中的dump

選擇一些選項,然后保存

我們用記事本將保存的il文件打開,文件內容如下:

View Code
//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.0.30319.17929




// 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 '觀察導入表'
{
  .custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01 00 1A 2E 4E 45 54 46 72 61 6D 65 77 6F 72 6B   // ....NETFramework
                                                                                                        2C 56 65 72 73 69 6F 6E 3D 76 34 2E 35 01 00 54   // ,Version=v4.5..T
                                                                                                        0E 14 46 72 61 6D 65 77 6F 72 6B 44 69 73 70 6C   // ..FrameworkDispl
                                                                                                        61 79 4E 61 6D 65 12 2E 4E 45 54 20 46 72 61 6D   // ayName..NET Fram
                                                                                                        65 77 6F 72 6B 20 34 2E 35 )                      // ework 4.5
  .custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 0F E8 A7 82 E5 AF 9F E5 AF BC E5 85 A5 E8 
                                                                                              A1 A8 00 00 ) 
  .custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = ( 01 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00 0F E8 A7 82 E5 AF 9F E5 AF BC E5 85 A5 E8 
                                                                                                A1 A8 00 00 ) 
  .custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = ( 01 00 12 43 6F 70 79 72 69 67 68 74 20 C2 A9 20   // ...Copyright .. 
                                                                                                  20 32 30 31 32 00 00 )                            //  2012..
  .custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = ( 01 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = ( 01 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 66 36 62 34 31 32 31 63 2D 64 37 63 37   // ..$f6b4121c-d7c7
                                                                                                  2D 34 30 33 35 2D 62 36 34 34 2D 35 30 36 34 38   // -4035-b644-50648
                                                                                                  63 62 34 33 30 34 63 00 00 )                      // cb4304c..
  .custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 31 2E 30 2E 30 2E 30 00 00 )             // ...1.0.0.0..

  // --- 下列自定義特性會自動添加,不要取消注釋 -------
  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02 00 00 00 00 00 ) 

  .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.
  .hash algorithm 0x00008004
  .ver 1:0:0:0
}
.module '觀察導入表.exe'
// MVID: {287A4077-C19B-4F87-B42E-88C0B8CE6A6E}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00020003    //  ILONLY 32BITPREFERRED
// Image base: 0x01720000


// =============== CLASS MEMBERS DECLARATION ===================

.class private auto ansi beforefieldinit '觀察導入表'.Program
       extends [mscorlib]System.Object
{
  .method private hidebysig static void  Main(string[] args) cil managed
  {
    .entrypoint
    // 代碼大小       17 (0x11)
    .maxstack  8
    .language '{3F5162F8-07C6-11D3-9053-00C04FA302A1}', '{994B45C4-E6E9-11D2-903F-00C04FA302A1}', '{5A869D0B-6611-11D3-BD2A-0000F80849BD}'
    .line 13,13 : 13,47 'd:\\Pro\\CLR和JIT的理解\\觀察導入表\\Program.cs'
    IL_0000:  ldstr      "hello world!"
    IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)
    .line 14,14 : 13,31 ''
    IL_000a:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
    IL_000f:  pop
    .line 15,15 : 9,10 ''
    IL_0010:  ret
  } // end of method Program::Main

  .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

} // end of class '觀察導入表'.Program


// =============================================================

// *********** 反匯編完成 ***********************
// 警告: 創建了 Win32 資源文件 D:\Pro\CLR和JIT的理解\反編譯.res

MSIL:微軟中間語言(Microsoft Intermediate Language),也被稱作MSIL匯編。別看.NET框架很智能,其實它只認IL。無亂程序采用什么高級語言編寫,都將被編譯器編譯為IL並保存在PE文件中。雖被稱作匯編,但相比win32匯編語言,IL可謂是名副其實的高級語言:它支持面向對象,通常不直接操作內存地址,以堆棧機的方式運行。由於運行完全受.NET監控,因此IL屬於托管(Managed)代碼,與之對應的是本機代碼,被稱為非托管代碼。

 

元數據:描述.NET程序運行說必需的一切信息的數據,包括版本、類型的各個成員(方法、字段、屬性、事件)等。一個文件要稱為有效的.NET可執行程序,必須包含正確的元數據定義。

我們來看看對應的hello world對應的元數據

// =============== CLASS MEMBERS DECLARATION ===================

.class private auto ansi beforefieldinit '觀察導入表'.Program
       extends [mscorlib]System.Object
{
  .method private hidebysig static void  Main(string[] args) cil managed
  {
    .entrypoint
    // 代碼大小       17 (0x11)
    .maxstack  8
    .language '{3F5162F8-07C6-11D3-9053-00C04FA302A1}', '{994B45C4-E6E9-11D2-903F-00C04FA302A1}', '{5A869D0B-6611-11D3-BD2A-0000F80849BD}'
    .line 13,13 : 13,47 'd:\\Pro\\CLR和JIT的理解\\觀察導入表\\Program.cs'
    IL_0000:  ldstr      "hello world!"
    IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)
    .line 14,14 : 13,31 ''
    IL_000a:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
    IL_000f:  pop
    .line 15,15 : 9,10 ''
    IL_0010:  ret
  } // end of method Program::Main

  .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

} // end of class '觀察導入表'.Program


// =============================================================

上面的代碼中,首先通過.class關鍵字定義了Program類,於是編譯器會在PE文件中保存Program類的元數據。接着,定義了Program類的兩個方法.ctor和Main,元數據中也會體現這種隸屬關系。

public hidebysig static void 限定了Main方法中的執行方式為公共、靜態、無返回值(hidebysig暫時不討論),這些限定也將被保存在元數據中。

Main方法中調用了System.Console的靜態方法WirteLine用於輸出字符串,元數據中必須體現這種調用。

 

以上內容來自:《微軟.NET程序的加密與解密》,學習這些內容只是為了能更好的理解所學的C#內容,暫時不涉及逆向的問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM