当前位置: 澳门新濠3559 > 编程 > 正文

  在应用Ildasm.exe具体反编译代码之前,暂时就

时间:2019-11-08 23:18来源:编程
上一篇介绍了 IL 的部分, 基础的部分, 暂时就介绍到那里了,接下来要进入代码编写阶段了. ** Ildasm.exe 的使用方法 今天的主题是 在代码运行的过程中, 去动态的创建类, 属性, 方法. 示例

上一篇介绍了 IL 的部分, 基础的部分, 暂时就介绍到那里了, 接下来要进入代码编写阶段了.

**Ildasm.exe 的使用方法

今天的主题是 在代码运行的过程中, 去动态的创建类, 属性, 方法.

示例:

来源:

  在应用Ildasm.exe具体反编译代码之前,先附上MSDN对于用Ildasm.exe反编译的经典帮助。**

废话不多说了, 直接上示例

 

一、示例

澳门新濠3559 1

我这边所用的示例跟来源中是一样的,请看代码:

 

public class Add
    {

        int numA = 0;
        public int NumA  {  get { return numA; }  set { numA = value; }  }

        int numB = 0;
        public int NumB  { get { return NumB; } set { NumB = value; } }

        public Add(int a, int b)
        {
            numA = a;
            numB = b;
        }

        public int Calc()
        {
            return numA + numB;
        }
    }

 

我们要动态的创建这么一个类, 先不给你们看编码过程, 先给你们看结果吧, 先知道下, 这么做, 能大致得到一个什么结果.

  然后我们用Ildasm.exe具体反编译经典的"Hello World"控制台程序的可执行文件,展现出来的视图为:

运行代码之后, 会在bin里面得到一个 Elvin.dll 文件, 把这个文件和 ConsoleApplication2.exe 一起拿去反编译, 去看里面 Add 类的内容

 

澳门新濠3559 2

澳门新濠3559 3

比较下来, 原生的和动态生成的稍有不同, 里面的IL代码也会有部分不同,这个是正常的, 虽然是参照着反编译的代码写的, 但是只是参照, 不是完全相同的.

  在应用Ildasm.exe具体反编译代码之前,暂时就介绍到那里了澳门新濠3559。 

 

 

二、编码

分析具体IL代码

先看几个主要的部分, 后面我会把完整的代码贴出来

1.MANIFEST清单:

  1. 字段

    private int numA; --> .field private int32 numA

    var fieldABuilder = typeBldr.DefineField("numA", typeof(Int32), FieldAttributes.Private); //fieldABuilder.SetConstant(0); 此处为副初始值, 这里可省略

     MANIFEST是一个附加信息列表,主要包含程序集的一些属性,如程序集名称、版本号、哈希算法等;

没什么好解释的, 一眼就能看懂, 至于这个 typeBldr 暂且不去管它

2.ConsoleApplication1.Program类:

  1. 属性

    //1.属性 public int NumA { get{return numA;} set{numA = value;} }

             var propertyABuilder = typeBldr.DefineProperty("NumA", PropertyAttributes.None, 
                 CallingConventions.HasThis, typeof(Int32), null);
    
             //2. 定义 get, set 方法
    

            

             //2.1 get方法 代码部分和上图上的是有些不同的, 是参照着上图这个来的
             var getPropertyABuilder = typeBldr.DefineMethod("get", MethodAttributes.Public | 
                 MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(Int32), Type.EmptyTypes);
             //ILGenerator
             var getAIL = getPropertyABuilder.GetILGenerator();
             getAIL.Emit(OpCodes.Ldarg_0);   //this
             getAIL.Emit(OpCodes.Ldfld, fieldABuilder); //numA
             getAIL.Emit(OpCodes.Ret); //return numA
    

              

            

             //2.2 set方法 代码部分和上图中是不一样的, 是参照着上图来的
             var setPropertyABuilder = typeBldr.DefineMethod("set", MethodAttributes.Public | 
                 MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(Int32) });
             //ILGenerator
             var setAIL = setPropertyABuilder.GetILGenerator();
             //setAIL.Emit(OpCodes.Nop);   //这句可省略
             setAIL.Emit(OpCodes.Ldarg_0);  //this
             setAIL.Emit(OpCodes.Ldarg_1);  //value
             setAIL.Emit(OpCodes.Stfld, fieldABuilder); //numA = value;
             setAIL.Emit(OpCodes.Ret);   //return;
    
             //3.绑定get,set方法到属性上
             propertyABuilder.SetGetMethod(getPropertyABuilder);
             propertyABuilder.SetSetMethod(setPropertyABuilder);
    

    这才是我们介绍的主角。

很多时候, 我们用的是匿名的属性, 如: public int NumA{get;set;}, 这种情况, 会自动生成一个匿名私有变量来代替numA, 去与之匹配, 属性的本质是方法, 并不能用来存储数据

首先是Program类: 代码为

  1. 构造函数

    IL代码: .method public hidebysig specialname rtspecialname instance void .ctor(int32 a, int32 b) cil managed {

     .maxstack 8
     L_0000: ldarg.0 
     L_0001: ldc.i4.0 
     L_0002: stfld int32 ConsoleApplication2.Add::numA
     L_0007: ldarg.0 
     L_0008: ldc.i4.0 
     L_0009: stfld int32 ConsoleApplication2.Add::numB
     L_000e: ldarg.0 
     L_000f: call instance void [mscorlib]System.Object::.ctor()
     L_0014: nop 
     L_0015: nop 
     L_0016: ldarg.0 
     L_0017: ldarg.1 
     L_0018: stfld int32 ConsoleApplication2.Add::numA
     L_001d: ldarg.0 
     L_001e: ldarg.2 
     L_001f: stfld int32 ConsoleApplication2.Add::numB
     L_0024: nop 
     L_0025: ret 
    

    }

      //定义构造函数 ConstructorBuilder

             var constructorBuilder = typeBldr.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, new Type[] { typeof(Int32), typeof(Int32) });
             var ctorIL = constructorBuilder.GetILGenerator();
             // numA = a;
             ctorIL.Emit(OpCodes.Ldarg_0);
             ctorIL.Emit(OpCodes.Ldarg_1);
             ctorIL.Emit(OpCodes.Stfld, fieldABuilder);
             //NumB = b;
             ctorIL.Emit(OpCodes.Ldarg_0);
             ctorIL.Emit(OpCodes.Ldarg_2);
             ctorIL.Emit(OpCodes.Stfld, fieldBBuilder);
             ctorIL.Emit(OpCodes.Ret);
    
  2. 方法

    IL代码: .method public hidebysig instance int32 Calc() cil managed {

     .maxstack 2
     .locals init (
         [0] int32 num)
     L_0000: nop 
     L_0001: ldarg.0 
     L_0002: ldfld int32 ConsoleApplication2.Add::numA
     L_0007: ldarg.0 
     L_0008: ldfld int32 ConsoleApplication2.Add::numB
     L_000d: add 
     L_000e: stloc.0 
     L_000f: br.s L_0011
     L_0011: ldloc.0 
     L_0012: ret 
    

    }

              //8.定义方法 MethodBuilder
             var calcMethodBuilder = typeBldr.DefineMethod("Calc", MethodAttributes.Public | MethodAttributes.HideBySig, typeof(Int32), Type.EmptyTypes);
             var calcIL = calcMethodBuilder.GetILGenerator();
             //加载私有字段numA
             calcIL.Emit(OpCodes.Ldarg_0);
             calcIL.Emit(OpCodes.Ldfld, fieldABuilder);
             //加载属性NumB
             calcIL.Emit(OpCodes.Ldarg_0);
             calcIL.Emit(OpCodes.Ldfld, fieldBBuilder);
             //想加并返回栈顶的值
             calcIL.Emit(OpCodes.Add);
             calcIL.Emit(OpCodes.Ret);
    
  3. 到这里, 主要的部分就介绍完了, 下面给出检验的部分:

    //9.结果

             Type type = typeBldr.CreateType();
             int a = 2;
             int b = 3;
             Object ob = Activator.CreateInstance(type, new object[] { a, b });
             Console.WriteLine("The Result of {0} + {1} is {2}", type.GetProperty("NumA").GetValue(ob), type.GetProperty("NumB").GetValue(ob), ob.GetType().GetMethod("Calc").Invoke(ob, null));
    

.class private auto ansi beforefieldinit ConsoleApplication1.Program
       extends [mscorlib]System.Object
{
} // end of class ConsoleApplication1.Program

执行之后, 会输出  "The Result of 2 + 3 is 5"

  1).class,表示Program是一个类。并且它继承自程序集—mscorlib的System.Object类;

至此, 今天要介绍的部分就结束了, 我把自己学习的过程和结果贴出来, 供有兴趣的童鞋瞄一下.

  2)private,表示访问权限;

以下是完整的代码

  3)auto,表示程序的内存加载全部由CLR来控制;

澳门新濠3559 4澳门新濠3559 5

  4)ansi,是为了在没有托管代码与托管代码之间实现无缝转换。这里主要指C、C++代码等;

static void Main(string[] args)
        {
            //1.构建程序集
            var asmName = new AssemblyName("Elvinle");
            var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);

            //2.创建模块 
            var mdlBldr = asmBuilder.DefineDynamicModule("Elvin", "Elvin.dll");

            //3.定义类, public class Add
            var typeBldr = mdlBldr.DefineType("Add", TypeAttributes.Public | TypeAttributes.BeforeFieldInit);

            //4. 定义属性和字段
            //4.1字段 FieldBuilder
            var fieldABuilder = typeBldr.DefineField("numA", typeof(Int32), FieldAttributes.Private);
            //fieldABuilder.SetConstant(0); 此处为副初始值, 这里可省略

            var fieldBBuilder = typeBldr.DefineField("numB", typeof(Int32), FieldAttributes.Private);

            //4.2属性 PropertyBuilder
            var propertyABuilder = typeBldr.DefineProperty("NumA", PropertyAttributes.None, CallingConventions.HasThis, typeof(Int32), null);

            var propertyBBuilder = typeBldr.DefineProperty("NumB", PropertyAttributes.None, CallingConventions.HasThis, typeof(Int32), null);

            //5.定义属性numA的get;set;方法 MethodBuilder
            //5.1 get方法
            var getPropertyABuilder = typeBldr.DefineMethod("get", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(Int32), Type.EmptyTypes);
            //ILGenerator
            GetPropertyIL(getPropertyABuilder, fieldABuilder);
            //var getAIL = getPropertyABuilder.GetILGenerator();
            //getAIL.Emit(OpCodes.Ldarg_0);   //this
            //getAIL.Emit(OpCodes.Ldfld, fieldABuilder); //numA
            //getAIL.Emit(OpCodes.Ret); //return numA

            //5.2 set方法
            var setPropertyABuilder = typeBldr.DefineMethod("set", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(Int32) });
            //ILGenerator
            SetPropertyIL(setPropertyABuilder, fieldABuilder);
            //var setAIL = setPropertyABuilder.GetILGenerator();
            ////setAIL.Emit(OpCodes.Nop);   //这句可省略
            //setAIL.Emit(OpCodes.Ldarg_0);  //this
            //setAIL.Emit(OpCodes.Ldarg_1);  //value
            //setAIL.Emit(OpCodes.Stfld, fieldABuilder); //numA = value;
            //setAIL.Emit(OpCodes.Ret);   //return;

            //5.3 绑定
            propertyABuilder.SetGetMethod(getPropertyABuilder);
            propertyABuilder.SetSetMethod(setPropertyABuilder);

            //6.定义属性numA的get;set;方法 MethodBuilder
            var getPropertyBBuilder = typeBldr.DefineMethod("get", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(Int32), Type.EmptyTypes);
            GetPropertyIL(getPropertyBBuilder, fieldBBuilder);

            var setPropertyBBuilder = typeBldr.DefineMethod("set", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(Int32) });
            SetPropertyIL(setPropertyBBuilder, fieldBBuilder);

            propertyBBuilder.SetGetMethod(getPropertyBBuilder);
            propertyBBuilder.SetSetMethod(setPropertyBBuilder);

            //7.定义构造函数 ConstructorBuilder
            var constructorBuilder = typeBldr.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, new Type[] { typeof(Int32), typeof(Int32) });
            var ctorIL = constructorBuilder.GetILGenerator();
            // numA = a;
            ctorIL.Emit(OpCodes.Ldarg_0);
            ctorIL.Emit(OpCodes.Ldarg_1);
            ctorIL.Emit(OpCodes.Stfld, fieldABuilder);
            //NumB = b;
            ctorIL.Emit(OpCodes.Ldarg_0);
            ctorIL.Emit(OpCodes.Ldarg_2);
            ctorIL.Emit(OpCodes.Stfld, fieldBBuilder);
            ctorIL.Emit(OpCodes.Ret);

            //8.定义方法 MethodBuilder
            var calcMethodBuilder = typeBldr.DefineMethod("Calc", MethodAttributes.Public | MethodAttributes.HideBySig, typeof(Int32), Type.EmptyTypes);
            var calcIL = calcMethodBuilder.GetILGenerator();
            //加载私有字段numA
            calcIL.Emit(OpCodes.Ldarg_0);
            calcIL.Emit(OpCodes.Ldfld, fieldABuilder);
            //加载属性NumB
            calcIL.Emit(OpCodes.Ldarg_0);
            calcIL.Emit(OpCodes.Ldfld, fieldBBuilder);
            //相加并返回栈顶的值
            calcIL.Emit(OpCodes.Add);
            calcIL.Emit(OpCodes.Ret);

            //9.结果
            Type type = typeBldr.CreateType();
            int a = 2;
            int b = 3;
            Object ob = Activator.CreateInstance(type, new object[] { a, b });
            Console.WriteLine("The Result of {0} + {1} is {2}", type.GetProperty("NumA").GetValue(ob), type.GetProperty("NumB").GetValue(ob), ob.GetType().GetMethod("Calc").Invoke(ob, null));

            asmBuilder.Save("Elvin.dll");
            Console.ReadKey();
        }

        private static void GetPropertyIL(MethodBuilder getPropertyBuilder, FieldBuilder fieldBuilder)
        {
            //ILGenerator
            var getAIL = getPropertyBuilder.GetILGenerator();
            getAIL.Emit(OpCodes.Ldarg_0);   //this
            getAIL.Emit(OpCodes.Ldfld, fieldBuilder); //numA
            getAIL.Emit(OpCodes.Ret); //return numA
        }

        private static void SetPropertyIL(MethodBuilder setPropertyBuilder, FieldBuilder fieldBuilder)
        {
            //ILGenerator
            var setAIL = setPropertyBuilder.GetILGenerator();
            //setAIL.Emit(OpCodes.Nop);   //这句可省略
            setAIL.Emit(OpCodes.Ldarg_0);  //this
            setAIL.Emit(OpCodes.Ldarg_1);  //value
            setAIL.Emit(OpCodes.Stfld, fieldBuilder); //numA = value;
            setAIL.Emit(OpCodes.Ret);   //return;
        }

  5)beforefieldinit,是用来标记运行库(CLR)可以在静态字段方法生成后的任意时刻,来加载构造器(构造函数);

View Code

 

希望我在学习的过程中, 也能带给你们一些不同的东西!

其次是 .ctor方法,代码为:

 

.method public hidebysig specialname rtspecialname 
        instance void  .ctor() cil managed
{
  // Code size       7 (0x7)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  call       instance void [澳门新濠3559,mscorlib]System.Object::.ctor()
  IL_0006:  ret
} // end of method Program::.ctor

  1)cil managed:表示其中为IL代码,指示编译器编译为托管代码;

  2).maxstack:表示调用构造函数.otor期间的评估堆栈(Evaluation Stack) ;

  3)IL_0000:标记代码行开头;

  4)ldarg.0:表示转载第一个成员参数,在实例方法中指的是当前实例的引用;

  5)call:call一般用于调用静态方法,因为静态方法是在编译期就确定的。而这里的构造函数.otor()也是在编译期就制定的。而另一指令callvirt则表示调用实例方法, 它是在运行时确定的,因为如前述,当调用方法的继承关系时,就要比较基类与派生类的同名函数的实现方法(virtual和new),以确定调用的函数所属的Method Table;

  6)ret:表示执行完毕,返回;

 

最后是Main()方法,代码为:

.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       13 (0xd)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "Hello world"
  IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000b:  nop
  IL_000c:  ret
} // end of method Program::Main

  1) .entrypoint指令表示CLR加载程序时,是首先从.entrypoint开始的,即从Main方法作为程序的入口函数;

  2)ldstr:表示将字符串压栈,在这里就是将"Hello World." 压栈;

  3)hidebysig:表示当把此类作为基类,存在派生类时,此方法不被继承,同上构造函数;

 

   至此,我们对IL代码的一些指令有了了解。

 

IL指令说明

                  MSIL Instruction Set

Base Instructions

 

Instruction

Description

Stack Transition

1

add

add two values, returning a new value

…, value1, value2à…, result

2

add.ovf.<signed>

add integer value with overflow check

…, value1, value2à…, result

3

and

bitwise AND

…, value1, value2 à…, result

4

arglist

get argument list

… à …, argListHandle

5

beq.<length>

branch on equal

…, value1, value2 à …

6

bge.<length>

branch on greater than or equal to

…, value1, value2 à …

7

bge.un.<length>

branch on greater/equal, unsigned or unordered

…, value1, value2 à …

8

bgt.<length>

branch on greater than

…, value1, value2 à …

9

bgt.un<length>

branch on greater than, unsigned or unordered

…, value1, value2 à …

10

ble.<length>

branch on less than or equal to

…, value1, value2 à …

11

ble..un<length>

branch on less/equal, unsigned or unordered

…, value1, value2 à …

12

blt.<length>

branch on less than

…, value1, value2 à …

13

blt.un.<length>

branch on less than, unsigned or unordered

…, value1, value2 à …

14

bne.un<length>

branch on not equal or unorded

…, value1, value2 à …

15

br.<length>

unconditional branch

…, à …

16

break

breakpoint instruction

…, à …

17

brfalse.<length>

branch on false, null, or zero

…, value à …

18

brtrue.<length>

branch on non-false or non-null

…, value à …

19

call

call a method

…, arg1, arg2 … argn à …, retVal (not always returned)

20

calli

indirect method call

…, arg1, arg2 … argn, ftn à …, retVal (not always returned)

21

ceq

compare equal

…, value1, value2à…, result

22

cgt

compare greater than

…, value1, value2à…, result

23

cgt.un

compare greater than, unsigned or unordered

…, value1, value2à…, result

24

ckfinite

check for a finite real number

…, value à …, value

25

clt

compare less than

…, value1, value2à…, result

26

clt.un

compare less than, unsigned or unordered

…, value1, value2à…, result

27

conv.<to type>

data conversion

…, value à …, result

28

conv.ovf<to type>

data conversion with overflow detection

…, value à …, result

29

conv.ovf.<to type>.un

unsigned data conversion with overflow detection

…, value à …, result

30

cpblk

copy data from memory to memory

…, destaddr, srcaddr, size à …

31

div

divide values

…, value1, value2à…, result

32

div.un

divide integer values, unsigned

…, value1, value2à…, result

33

dup

duplicate the top value of the stack

…, value à …, value, value

34

endfilter

end filter clause of SEH

…, value à …

35

endfinally

end the finally or fault clause of exception block

… à …

36

initblk

initialize a block of memory to a value

…, addr, value, size à …

37

jmp

jump to method

… à …

38

ldarg.<length>

load argument onto the stack

… à …, value

39

ldarga.<length>

load an argument address

…, à …, address of argument number argNum

40

ldc.<type>

load numeric constant

… à …, num

41

ldftn

load method pointer

… à …, ftn

42

ldind.<type>

load value indirect onto the stack

…, addr à …, value

43

ldloc

load local variable onto the stack

… à …, value

44

ldloca.<length>

load local variable address

… à …, address

45

ldnull

load a null pointer

… à …, null value

46

leave.<length>

exit a protected region of code

…, à

47

localloc

allocate space in the local dynamic memory pool

size à address

48

mul

multiply values

…, value1, value2 à …, result

49

mul.ovf<type>

multiply integer values with overflow check

…, value1, value2 à …, result

50

neg

negate

…, value à …, result

51

nop

no operation

…, à …,

52

not

bitwise complement

…, value à …, result

53

or

bitwise OR

…, value1, value2 à …, result

54

pop

remove the top element of the stack

…, value à …

55

rem

compute the remainder

…, value1, value2 à …, result

56

rem.un

compute integer remainder, unsigned

…, value1, value2 à …, result

57

ret

return from method

retVal on callee evaluation stack (not always present) à

…, retVal on caller evaluation stack (not always present)

58

shl

shift integer left

…, value, shiftAmount à …, result

59

shr

shift integer right

…, value, shiftAmount à …, result

60

shr.un

shift integer right, unsigned

…, value, shiftAmount à …, result

61

starg.<length>

store a value in an argument slot

…, value à …,

62

stind.<type>

store value indirect from stack

…, addr, val à …

63

stloc

pop value from stack to local variable

…, value à …

64

sub

substract numeric values

…, value1, value2 à …, result

65

sub.ovf.<type>

substract integer values, checking for overflow

…, value1, value2 à …, result

66

switch

table switch on value

…, value à …,

67

xor

bitwise XOR

..., value1, value2 à ..., result

 

 

Object Model Instructions

 

Instruction

Description

Stack Transition

1

box

convert value type to object reference

…, valueType à …, obj

2

callvirt

call a method associated, a runtime, with an object

…, obj, arg1, … argN à …, returnVal (not always returned)

3

cast class

cast an object to a class

…, obj à …, obj2

4

cpobj

copy a value type

…, destValObj, srcValObj à …,

5

initobj

Initialize a value type

…,addrOfValObj à …,

6

isinst

test if an object is is an instance of a class or interface

…, obj à …, result

7

ldelem.<type>

load an element fo an array

…, array, index à …, value

8

ldelema

load address of an element of an array

…, array, index à …, address

9

ldfld

load field of an object

…, obj à …, value

10

ldflda

load field address

…, obj à …, address

11

ldlen

load the length of an array

…, array à …, length

12

ldobj

copy value type to the stack

…, addrOfValObj à …, valObj

13

ldsfld

load static field of a class

…, à …, value

14

ldsflda

load static field address

…, à …, address

15

ldstr

load a literal string

…, à …, string

16

ldtoken

load the runtime representation of metadata token

… à …, RuntimeHandle

17

ldvirtfn

load a virtual method pointer

… object à …, ftn

18

mkrefany

push a typed reference on the stack

…, ptr à …, typedRef

19

newarr

Create a zero-base, on-dimensional array

…, numElems à …, array

20

newobj

create a new object

…, arg1, … argN à …, obj

21

refanytype

load the type out of a typed reference

…, TypedRef à …, type

22

refanyval

load the address out of a typed reference

…, TypedRef à …, address

23

rethrow

rethrow the current exception

…, à …,

24

sizeof

load the size in bytes of a value type

…, à …, size (4 bytes, unsigned)

25

stelem.<type>

store an element of an array

…, array, index, value à …,

26

stfld

store into a field of an object

…, obj, value à …,

27

stobj

store a value type from the stack into memory

…, addr, valObj à …,

28

stsfld

store a static field of class

…, val à …,

29

throw

throw an exception

…, object à …,

30

unbox

convert boxed value type to its raw form

 

 

 

 

 

 转自:

编辑:编程 本文来源:  在应用Ildasm.exe具体反编译代码之前,暂时就

关键词: