上一回我们试验了通过反射的方式获取method的源代码。
这次我们就用一个实例来演示dump一个程序集中的所有类型和方法的IL源代码。
首先打开VS2005 新建一个C#的windows程序:
在窗体添加添加一个2个 button,2个label,一个textbox,一个 checkbox,一个savefiledialog。
界面如下:
事件代码如下:
1
public
class
Form1 : Form
2
{
3
//
Methods
4
//
选择IL字节码保存文件
5
private
void
button1_Click(
object
sender, EventArgs e)
6
{
7
if
(
this
.saveFileDialog1.ShowDialog()
==
DialogResult.OK)
8
{
9
this
.textBox1.Text
=
this
.saveFileDialog1.FileName;
10
}
11
}
12
//
点击开始dump。
13
private
void
button3_Click(
object
sender, EventArgs e)
14
{
15
this
.button3.Enabled
=
false
;
16
this
.DumpAssembly(Assembly.GetExecutingAssembly(),
this
.textBox1.Text);
17
MessageBox.Show(
"
dump ok
"
);
18
this
.button3.Enabled
=
true
;
19
}
20
//
这个函数将一个Assembly全部dump到path中。
21
private
void
DumpAssembly(Assembly ass,
string
path)
22
{
23
StreamWriter writer1
=
new
StreamWriter(path,
false
);
24
Type[] typeArray1
=
ass.GetTypes();
25
for
(
int
num1
=
0
; num1
<
typeArray1.Length; num1
++
)
26
{
27
this
.DumpType(typeArray1[num1], writer1);
28
}
29
writer1.Flush();
30
writer1.Close();
31
}
32
33
//
dump单个类型,由dumpassembly调用
34
private
void
DumpType(Type tp, StreamWriter sw)
35
{
36
BindingFlags flags1
=
BindingFlags.NonPublic
|
BindingFlags.Public
|
BindingFlags.Static
|
BindingFlags.Instance
|
BindingFlags.DeclaredOnly;
37
string
text1
=
tp.ToString();
38
sw.Write(
"
TYPE:
"
+
text1
+
"
\r\n
"
);
39
if
(tp.IsEnum)
40
{
41
sw.Write(
"
IsEnum
"
);
42
}
43
if
(tp.IsImport)
44
{
45
sw.Write(
"
IsImport
"
);
46
}
47
if
(tp.IsNested)
48
{
49
sw.Write(
"
IsNested
"
);
50
}
51
if
(tp.IsClass)
52
{
53
sw.Write(
"
IsClass
"
);
54
}
55
sw.Write(
"
\r\n
"
);
56
if
((text1
!=
"
InFaceMaxtoCode
"
)
||
!
this
.checkBox1.Checked)
57
{
58
sw.Write(
"
**********Begin MemberInfo**********\r\n
"
);
59
MemberInfo[] infoArray1
=
tp.GetMembers(flags1);
60
for
(
int
num1
=
0
; num1
<
infoArray1.Length; num1
++
)
61
{
62
MemberInfo info1
=
infoArray1[num1];
63
sw.Write(info1.MemberType.ToString()
+
"
\t
"
+
infoArray1[num1].ToString()
+
"
\r\n
"
);
64
if
((info1.MemberType
==
MemberTypes.Method)
||
(info1.MemberType
==
MemberTypes.Constructor))
65
{
66
this
.DumpMethod((MethodBase) info1, sw);
67
}
68
}
69
sw.Write(
"
********** End MemberInfo**********\r\n
"
);
70
sw.Write(
"
\r\n\r\n
"
);
71
}
72
}
73
74
75
76
//
dump单个方法,由dumptype调用
77
private
void
DumpMethod(MethodBase mb, StreamWriter sw)
78
{
79
MethodBody body1
=
mb.GetMethodBody();
80
if
(body1
!=
null
)
81
{
82
byte
[] buffer1
=
body1.GetILAsByteArray();
83
try
84
{
85
sw.Write(
"
\tMaxStackSize:
"
+
body1.MaxStackSize.ToString());
86
sw.Write(
"
\tCodeSize:
"
+
buffer1.Length.ToString());
87
sw.Write(
"
\r\n
"
);
88
}
89
catch
(Exception exception1)
90
{
91
MessageBox.Show(
"
1:
"
+
mb.ToString()
+
"
\r\n
"
+
exception1.ToString());
92
}
93
foreach
(LocalVariableInfo info1
in
body1.LocalVariables)
94
{
95
sw.Write(
"
LocalVar:
"
+
info1.ToString());
96
sw.Write(
"
\r\n
"
);
97
}
98
sw.Write(
"
\r\n\r\n
"
);
99
StringBuilder builder1
=
new
StringBuilder();
100
foreach
(
byte
num1
in
buffer1)
101
{
102
builder1.Append(num1.ToString(
"
X2
"
));
103
}
104
sw.Write(builder1.ToString());
105
sw.Write(
"
\r\n\r\n
"
);
106
foreach
(ExceptionHandlingClause clause1
in
body1.ExceptionHandlingClauses)
107
{
108
sw.Write(clause1.ToString());
109
sw.Write(
"
\r\n
"
);
110
}
111
sw.Write(
"
\r\n
"
);
112
}
113
}
114
115
116
117
118
119
}
120
121
编译这个程序,运行,dump出il字节码,
然后拿 maxtocode加密。再运行,dump出il字节码,然后找一个method 如 button1_click,比较一下他们的IL字节码是否一样。
当然结果应该是一样的。
这里主要有三个关键函数
private void DumpAssembly(Assembly ass, string path);
private void DumpMethod(MethodBase mb, StreamWriter sw);
private void DumpType(Type tp, StreamWriter sw);
这三个就是一个例子演示如何dump整个程序集。
如要dump 一个加密的dll,我们就可以直接用这个程序来改,
首先添加引用,引用那个dll,然后随便实例话一个该dll中的type。
然后获取该dll的 Assembly 对象,再调用DumpAssembly函数即可。
好了,今回就到这里,下回再讲解怎么理解、查看IL字节码。