本文主要介绍常用的IL指令,主要分一下几个类型来进行介绍。
常用IL指令文档 链接: https://pan.baidu.com/s/1dp507PpZfhofud9LDAp8lQ 密码: arhh
官方介绍地址:https://msdn.microsoft.com/zh-cn/library/system.reflection.emit.opcodes(v=vs.110).aspx
接下来我们分类进行介绍。
0x1.IL是什么
U3D游戏的脚本开发语言为C#,dll脚本反编译后的语言即为IL,也被称为微软中间语言MSIL。
0x2.常用指令
我将IL分析中常用的指令分为了五种,分别是用于加载的ld开头指令、用于存储的st开头指令、用于跳转的b开头指令、用于调用的call开头指令、运算指令。
2.1 用于加载的ld开头指令
ld是load的意思,是将操作数推送/加载到堆栈中,等待下一个语句调用或者存储。下面介绍几种常见的指令:
2.1.1 ldc指令
ldc.i4 → 将所提供的int32类型的值推送到堆栈上,简言之,就是在内存中加载一个整数。
例如:ldc.i4 0x10 意思就是将十六进制数0x10加载到内存中,也有ldc.i4.0~ldc.i4.8代表整数1到8加载到内存中。
2.1.2 ldstr指令
ldstr → 将字符串对象推送到堆栈中,简言之,就是在内存中加载一个字符串对象。
例如:ldstr “hello world” 意思就是将字符串“hello world”加载到内存中。
2.1.2 ldfld指令
ldfld → 查找对象中其引用的当前位于计算堆栈的字段的值。
例如:ldfld string name 意思就是将字符串变量name中的值查找出来待用。
2.2 用于存储的st开头指令
st是store的意思,是将操作数从堆栈中弹出,相当于将其赋值给某些变量的意思。
stfld → 用新值替换在对象引用或指针的字段中存储的值。
例如:stfld string name 意思就是将堆栈中的字符串对象赋值给字符串变量name。
2.3 用于跳转的b开头指令
b是branch的意思,可以理解为分支或者跳转。
2.3.1 beq指令
beq → 如果两个值相等,则将控制转移到目标指令。这个与smali中的是类似的。
例如:beq IL_0020 意思就是如果前面提供的两个值相等,就跳转到IL_0020这一行执行。
2.3.2 br指令
br → 无条件的将控制转移到目标指令。
例如:br IL_0020 意思就是不进行任何判断直接跳转到IL_0020这一行执行。
2.4 用于调用的call开头指令
call是调用的意思,常见的两种,带返回值的和不带返回值的。
2.4.1 call指令
call → 调用由传递的方法说明符指示的方法。
2.4.2 callvirt指令
callvirt → 对对象调用后期绑定方法,并且将返回值推送到计算堆栈上。
两者有区别但是我们现在并不必深究,仅做了解知道是调用函数即可。
【 仅作了解:
1)call可以调用静态方法,实例方法和虚方法
callvirt只能调用实例方法和虚方法,不能调用静态方法
2)call一般是以非虚的方式来调用函数的
callvirt是以已多态的方式来调用函数的 】
2.5 运算指令
运算分为两类,算术运算和逻辑运算。
2.5.1 算术运算
算术运算主要是加减乘除,分别为 add、sub、mul、div。
2.5.2 逻辑运算
逻辑运算主要是与或非,分别为 and、or、not;异或也常用到,为xor。
0x3.举例分析
例子1:
ldc.i4 0x2 stfld int32 value1 ldc.i4 0x3 ldfld int32 value1 mul stfld int32 value2
//将数值2加载到内存 //将其存储整型变量value1 //将数值3加载到内存 //将value1的值加载到内存 //数值3和value1的值进行乘法运算 //运算结果存储到value2中
ldc.r4 0.5 stfld float32 value1 ldc.r4 0.6 ldfld float32 value1 beq IL_0020 call void function() br IL_0020
//将浮点数0.5加载到内存中 //将0.5存储到float32变量value1中 //将浮点数0.6加载到内存中 //将value1的值加载到内存中 //比较0.6和value1的值,如果相等就跳转到IL_0020 //如果不相等就执行call来调用函数function() //直接跳转到IL_0020