本文主要介紹常用的IL指令,主要分一下幾個(gè)類型來進(jìn)行介紹。
常用IL指令文檔 鏈接: https://pan.baidu.com/s/1dp507PpZfhofud9LDAp8lQ 密碼: arhh
官方介紹地址:https://msdn.microsoft.com/zh-cn/library/system.reflection.emit.opcodes(v=vs.110).aspx
接下來我們分類進(jìn)行介紹。
0x1.IL是什么
U3D游戲的腳本開發(fā)語言為C#,dll腳本反編譯后的語言即為IL,也被稱為微軟中間語言MSIL。
0x2.常用指令
我將IL分析中常用的指令分為了五種,分別是用于加載的ld開頭指令、用于存儲(chǔ)的st開頭指令、用于跳轉(zhuǎn)的b開頭指令、用于調(diào)用的call開頭指令、運(yùn)算指令。
2.1 用于加載的ld開頭指令
ld是load的意思,是將操作數(shù)推送/加載到堆棧中,等待下一個(gè)語句調(diào)用或者存儲(chǔ)。下面介紹幾種常見的指令:
2.1.1 ldc指令
ldc.i4 → 將所提供的int32類型的值推送到堆棧上,簡言之,就是在內(nèi)存中加載一個(gè)整數(shù)。
例如:ldc.i4 0x10 意思就是將十六進(jìn)制數(shù)0x10加載到內(nèi)存中,也有l(wèi)dc.i4.0~ldc.i4.8代表整數(shù)1到8加載到內(nèi)存中。
2.1.2 ldstr指令
ldstr → 將字符串對(duì)象推送到堆棧中,簡言之,就是在內(nèi)存中加載一個(gè)字符串對(duì)象。
例如:ldstr “hello world” 意思就是將字符串“hello world”加載到內(nèi)存中。
2.1.2 ldfld指令
ldfld → 查找對(duì)象中其引用的當(dāng)前位于計(jì)算堆棧的字段的值。
例如:ldfld string name 意思就是將字符串變量name中的值查找出來待用。
2.2 用于存儲(chǔ)的st開頭指令
st是store的意思,是將操作數(shù)從堆棧中彈出,相當(dāng)于將其賦值給某些變量的意思。
stfld → 用新值替換在對(duì)象引用或指針的字段中存儲(chǔ)的值。
例如:stfld string name 意思就是將堆棧中的字符串對(duì)象賦值給字符串變量name。
2.3 用于跳轉(zhuǎn)的b開頭指令
b是branch的意思,可以理解為分支或者跳轉(zhuǎn)。
2.3.1 beq指令
beq → 如果兩個(gè)值相等,則將控制轉(zhuǎn)移到目標(biāo)指令。這個(gè)與smali中的是類似的。
例如:beq IL_0020 意思就是如果前面提供的兩個(gè)值相等,就跳轉(zhuǎn)到IL_0020這一行執(zhí)行。
2.3.2 br指令
br → 無條件的將控制轉(zhuǎn)移到目標(biāo)指令。
例如:br IL_0020 意思就是不進(jìn)行任何判斷直接跳轉(zhuǎn)到IL_0020這一行執(zhí)行。
2.4 用于調(diào)用的call開頭指令
call是調(diào)用的意思,常見的兩種,帶返回值的和不帶返回值的。
2.4.1 call指令
call → 調(diào)用由傳遞的方法說明符指示的方法。
2.4.2 callvirt指令
callvirt → 對(duì)對(duì)象調(diào)用后期綁定方法,并且將返回值推送到計(jì)算堆棧上。
兩者有區(qū)別但是我們現(xiàn)在并不必深究,僅做了解知道是調(diào)用函數(shù)即可。
【 僅作了解:
1)call可以調(diào)用靜態(tài)方法,實(shí)例方法和虛方法
callvirt只能調(diào)用實(shí)例方法和虛方法,不能調(diào)用靜態(tài)方法
2)call一般是以非虛的方式來調(diào)用函數(shù)的
callvirt是以已多態(tài)的方式來調(diào)用函數(shù)的 】
2.5 運(yùn)算指令
運(yùn)算分為兩類,算術(shù)運(yùn)算和邏輯運(yùn)算。
2.5.1 算術(shù)運(yùn)算
算術(shù)運(yùn)算主要是加減乘除,分別為 add、sub、mul、div。
2.5.2 邏輯運(yùn)算
邏輯運(yùn)算主要是與或非,分別為 and、or、not;異或也常用到,為xor。
0x3.舉例分析
例子1:
ldc.i4 0x2 stfld int32 value1 ldc.i4 0x3 ldfld int32 value1 mul stfld int32 value2
//將數(shù)值2加載到內(nèi)存 //將其存儲(chǔ)整型變量value1 //將數(shù)值3加載到內(nèi)存 //將value1的值加載到內(nèi)存 //數(shù)值3和value1的值進(jìn)行乘法運(yùn)算 //運(yùn)算結(jié)果存儲(chǔ)到value2中
ldc.r4 0.5 stfld float32 value1 ldc.r4 0.6 ldfld float32 value1 beq IL_0020 call void function() br IL_0020
//將浮點(diǎn)數(shù)0.5加載到內(nèi)存中 //將0.5存儲(chǔ)到float32變量value1中 //將浮點(diǎn)數(shù)0.6加載到內(nèi)存中 //將value1的值加載到內(nèi)存中 //比較0.6和value1的值,如果相等就跳轉(zhuǎn)到IL_0020 //如果不相等就執(zhí)行call來調(diào)用函數(shù)function() //直接跳轉(zhuǎn)到IL_0020