天天看點

dotNet MSIL中的一些不常見IL指令

dotNet MSIL中的一些不常見IL指令

在做HVM僞代碼覆寫率檢測時,在構造的一些dotNet程式樣本中總是缺少一些MSIL指令

,沒有覆寫所有的MSIL指令。

如C#中的裝箱和取消裝箱的IL指令,可能很多人和我最初的想法一樣,裝箱是 box指令

,取消裝箱是unbox指令,實際上這隻對了一半。

裝箱使用的box指令沒有錯誤,但是取消裝箱不是用的unbox指令,而是 unbox.any 指

令,在C#編譯的程式中就從來沒有發現過 unbox 指令。

另外還有一批沒有發現的指令有 calli , cpobj, ldobj, stobj, refanyval,

mkrefany,arglist, refanytype, initblk, cpblk

initobj指令也比較少見,不過在C#的泛型中遇到了:

如 T obj = default(T); 編譯後就會出現 initobj 指令。

這個指令就是給變量賦初值。

calli 在C#裡面沒有,在C++/CLI構造出來了,實際上它是調用函數指針的用法。

refanyval, mkrefany,arglist, refanytype 看了一篇介紹 undocumented IL 的文章

後構造出來了,具體可參考轉的文章。

其它的指令構造不出來就隻能蠻幹了,把exe用ilasm整成的 il 檔案,然後直接修改il

,再編譯測試,經過反複實驗,構造出了可以正常運作的程式。

先看裝箱和取消裝箱,

int i = 123;

object obj = i;

i = (int)obj;

對應的il代碼是:

第一句:

ldc.i4.s   123

stloc.0

第二句:

ldloc.0

box        [mscorlib]System.Int32

stloc.1

第三句:

ldloc.1

unbox.any  [mscorlib]System.Int32

首先我就是直接把

改為

unbox  [mscorlib]System.Int32

然後測試,發現這是 i 的值不等于 123了,而是一個不确定的數字。看IL文檔得知

unbox生成的隻是一個指針,也就是位址。

這時想到了另外一個指令 ldobj ,這個指令直接從位址讀取資料放到堆棧上。

如是把

ldobj  [mscorlib]System.Int32

再測試,結果正确了。看起來 unbox + ldobj 的效果和 unbox.any一樣。

stobj 指令,從名稱就能看出它和 ldobj隻對應的。将立即數存入位址中。

功能類似如c++中的 *p = value;

i = 3;

正常方式應該是

ldc.i4.s 3

stloc.s.0

改為另一種模式

ldloca.s 0 //載入 i 的位址

ldc.i4.s 3 //載入立即數

stobj [mscorlib]System.Int32 //将立即數存入位址

cpobj 指令,直接從位址複制對象類似c++中的 *p1 = *p2;

int i, j;

j = i;

正常方式是

stloc.s 0

ldloc.s 0

stloc.s 1

改為使用cpobj的模式

ldloca.s 1 //dest

ldloca.s 0 //src

cpobj [mscorlib]System.Int32 //copy

initblk 類似如C中的 memset 函數

cpblk 類似如C中的 memcpy函數

DNGuard HVM核心是通過将IL代碼替換為HVM僞指令然後送出給Jit去編譯的,是以需要

檢測所有的HVM僞指令是否都能夠被正确編譯執行。測試遇到沒有覆寫的指令隻好用蠻

幹的方法構造樣本了。

目前以及完成了 .net framework 2.0, .net framework 3.0環境下的指令覆寫檢測,

所有HVM僞指令都編譯通過了。

接下來将對 .net framework 1.1 和 .net framework 3.5的環境進行指令覆寫檢測。