dotNET 高阶反射(RTTI):.NET 程序集反编译函数为 IL 代码
我们知道在 “反射” 的应用中是可以在运行时 “动态的即时编译IL”(.NET Emit ≈≈≈ C/C++ __emit),那么既然可以即时编译,自然可以逆向,但这是属于 “高阶” 反射方面的内容,基本的说任何只要是托管类型的程式,都是可以在运行时IL逆转的,类似 JavaScript 语言逆转代码相对 .NET、JVM 会极其直观,像设计立于 “通用语言平台” 的 “过程虚拟机” 都没办法
我们知道在 “反射” 的应用中是可以在运行时 “动态的即时编译IL”(.NET Emit ≈≈≈ C/C++ __emit),那么既然可以即时编译,自然可以逆向,但这是属于 “高阶” 反射方面的内容,基本的说任何只要是托管类型的程式,都是可以在运行时IL逆转的,类似 JavaScript 语言逆转代码相对 .NET、JVM 会极其直观,像设计立于 “通用语言平台” 的 “过程虚拟机” 都没办法做到这种事情,我们xiang,参照对应平台的指令集进行人工的或者自动化的逆向过程。
当然本人对并没有耗费太多精力用于 Java JVM 的体系上面(本人并不喜欢从事 Java 的那一堆人,当然还是不少的人我还是觉得不错的),但客观的说 JVM 这个东西的确是做的比较不错的东西,只是说某些设计的确有点反人类,当然这是后话不再本文中深入探究。
我知道很多人非常喜欢利用 “ILSpy”、“.NET Reflector”、“ildasm”、“dnSpy” 这几类反编译工具,但是严格的说对于 .NET 的反编译分为两种技术流派:Mono .Cecil、Microsoft .NET,这些工具都是属于这两个流派的,例如:“dnSpy”、“ILSpy” 则属于 Mono .Cecil 的类别,但 “dnSpy” 又有些特殊它是 “0xd4d” 大佬从 “Mono .Cecil” 精简改进过后的变种,但根是 “Mono .Cecil”,“.NET Reflector” 则是 “.NET 反射”、“ildasm” 这个东西并不是利用的 “.NET 反射” 实现的,而是参杂着 “dd .NET sscil*” 源代码(.NET CLR、mscorlib) #include and link lib 的方式用 C/C++ 编译的,具体可以参考 “sscil*” 的源代码。
本文是利用 “.NET 反射” 对函数进行反编译的,与 “.NET Reflector” 基本同出一源,当然 “.NET 反射” 的方式进行反编译是一把双面刃,对于那种加了抗 ILSpy 这一类借助 Mono .Cecil 的程序集它会有不错的效果,但是坏处也并非未有,它必须把要被 “反编译的程序集映像(.NET Image)” load 到本进程的 “AppDomain” 的内存空间内,无论你是以反射方式载入还是正常方式载入映像,dotNET 程序集一旦被载入到 AppDomain 就会很蛋疼了,所以一般会采取利用 .NET Sandbox 的机制(即多 AppDomain)或者多进程 IPC 交互的方式,Mono .Cecil 则不会存在 “.NET 反射” 这方面的问题。
当然上面只是探讨两种流派的一些问题,我们在对不同目标进行逆向时,会根据目标的具体情况采取恰当的做法,抗 “ILSpy” 基本是很多的 “.NET 保护工具” 所提供的功能,显然这种做法只要 .NET CLR 能够正常的载入保护过后的映像,人们都可以通过各种手段搞它,这是很正常的事情,.NET CLR 的调试器API,其实用好点在搞某些程式的时候是很恶心的与有效滴~,当然从另一方面来说真的会很爽的~啦!,不过这显然不是本文该探讨的问题;
上述是本人利用反射编写的一个很 Simple 的 IL 反编译东东的执行效果(很多东西是不支持的,具体各位遇到那些的时候自己改自己支持),但为了有一些参考物,本人下面提供 ILSpy 中反编译出的 IL 代码,当然肯定会有所不同,但这个都是芝麻蒜皮的细节,最终两者反编译出的IL代码执行效果是相同的。
IL_0000: nop
IL_0001: call bool [SupersocksR]SupersocksR.Win32.Debugger::AdjustPrivilege()
IL_0006: pop
.try
{
.try
{
IL_0007: nop
IL_0008: ldnull
IL_0009: stloc.0
IL_000a: ldloc.0
IL_000b: ldc.i4.s 88
IL_000d: stfld int32 MININATs.Program/Aff::b
IL_0012: ldloc.0
IL_0013: ldnull
IL_0014: callvirt instance void MININATs.Program/Aff::A(class [System]System.Text.RegularExpressions.Match)
IL_0019: nop
IL_001a: call valuetype [mscorlib]System.Nullable`1<bool> MININATs.Program::TestDOO()
IL_001f: pop
IL_0020: ldc.i4 1000
IL_0025: stloc.1
IL_0026: ldc.i8 72057593787461923
IL_002f: stloc.2
IL_0030: ldc.r4 3.142122
IL_0035: stloc.3
IL_0036: ldc.r8 3.142122515
IL_003f: stloc.s 4
IL_0041: ldloc.1
IL_0042: ldc.i4.0
IL_0043: div
IL_0044: call void [mscorlib]System.Console::WriteLine(int32)
IL_0049: nop
IL_004a: nop
IL_004b: leave.s IL_0060
} // end .try
catch [mscorlib]System.Exception
{
IL_004d: stloc.s 5
IL_004f: nop
IL_0050: ldloc.s 5
IL_0052: callvirt instance string [mscorlib]System.Exception::get_Message()
IL_0057: call void [mscorlib]System.Console::WriteLine(string)
IL_005c: nop
IL_005d: nop
IL_005e: leave.s IL_0060
} // end handler
IL_0060: leave.s IL_0070
} // end .try
finally
{
IL_0062: nop
IL_0063: ldstr "finally"
IL_0068: call void [mscorlib]System.Console::WriteLine(string)
IL_006d: nop
IL_006e: nop
IL_006f: endfinally
} // end handler
IL_0070: ret
从上述的 ILSpy 反编译出来的IL与本人编写的很 Simple 工具反出来的结果还是有一些不少的差距的,当然我们进行反编译时更多是为了理解某些我们想要关注的东西的行为与实现,而上述两者反编译出的 IL 代码都仅仅只是做参考意义。
回到此处:那么我们应当如何的利用 “反射”,反编译一个方法 IL文本代码或者 IL字节代码流呢?其实它非常的令人惊喜与蛋疼,与其说它难倒不如说它真的太傻白甜了呢,你仅仅只需要获得到一个需要被反编译的 “MethodInfo” 的反射信息对象的引用即可,MethodInfo 提供了一个 “GetMethodBody” 的方法可以获取到此 “方法” 内部的情况,它包括局部变量的定义还有 IL字节代码流等一系列反编译时所需的信息呢。
但是拿到 IL字节代码流应该如何正确的转换成一条一条的IL指令?其实很简单的,你仅仅只需要按照IL字节代码每个不同的IL指令之间的对齐来读取携带的参数及其指令操作符即可。
private static IList<Instruction> GetInstructions(MethodInfo m)
{
if (m == null)
{
throw new ArgumentNullException("m");
}
IList<Instruction> instructions = new List<Instruction>();
MethodBody body = m.GetMethodBody();
if (body == null)
{
return instructions;
}
byte[] il = body.GetILAsByteArray();
int ofs = 0;
while (ofs < il.Length)
{
int start = ofs;
short op = il[ofs];
ofs++;
if (op == 0xFE || opcodes[op].OpCodeType == OpCodeType.Prefix)
{
op = (short)((op << 8) + il[ofs]);
ofs++;
}
OpCode code = opcodes[op];
long argument = 0;
int extsz = 4;
if (code.OperandType == OperandType.InlineNone)
{
extsz = 0;
}
else if (code.OperandType == OperandType.ShortInlineBrTarget || code.OperandType == OperandType.ShortInlineI || code.OperandType == OperandType.ShortInlineVar)
{
extsz = 1;
}
else if (code.OperandType == OperandType.InlineVar)
{
extsz = 2;
}
else if (code.OperandType == OperandType.InlineI8 || code.OperandType == OperandType.InlineR)
{
extsz = 8;
}
else if (code.OperandType == OperandType.InlineSwitch)
{
long n = il[ofs] + (il[ofs + 1] << 8) + (il[ofs + 2] << 16) + (il[ofs + 3] << 24);
extsz = (int)(4 * n + 4);
}
if (extsz > 0)
{
long n = 0;
for (int i = 0; i < extsz; ++i)
{
long v = il[ofs + i];
n += v << (i * 8);
}
argument = n;
ofs += extsz;
}
instructions.Add(new Instruction() { OpCode = code, Value = argument, Alignment = extsz + code.Size });
}
return instructions;
}
参考上述的代码,此函数则是把 IL 字节代码流正确的转换成一条一条的 IL 字节代码,当然这个函数无法做到反编译成 IL 的文本形式,另外很值得注意的一点,MSIL 在设计 “RVA 相对地址” 的时候采取的办法与 “x86/x64” RVA地址的计算方法是相同的,即:目标指令位置 -(当前指令位置 + 当前指令长条),所以说在逆转回去的时候你的把这个位置加对不然是要出问题的,但是这个东西主要是用在流程跳转IL操作指令方面的东西,例如:beq、blt、bgt 指令,还有就是 try catch 方面的会用到,另一方面 .try、.catch. .finally 三者与反编译出来的指令之间没有任何的想干,它们是以附加到函数指令的二进制流位置的形式存在的,类似 hook 但又不同呢~~~。
一个需要关注的问题是,IL字节代码流里面,我举一个例子:call void [???]A::xxx() 那么它的字节代码格式就是 HEX: “28 20 00 00 0a”(小端)
28 代表则 CALL 这个指令,然后它的对齐是四个字节,20 00 00 0a = 0x0a000020,它代表了对某个成员方法的引用ID(俗称RID)但并不是什么指令后面携带的参数都一定是 RID,有些指令接收 “标准的数值常量” 而不是 RID,参考下面提供的 CorTokenType 定义的枚举。
typedef enum CorTokenType {
mdtModule = 0x00000000,
mdtTypeRef = 0x01000000,
mdtTypeDef = 0x02000000,
mdtFieldDef = 0x04000000,
mdtMethodDef = 0x06000000,
mdtParamDef = 0x08000000,
mdtInterfaceImpl = 0x09000000,
mdtMemberRef = 0x0a000000,
mdtCustomAttribute = 0x0c000000,
mdtPermission = 0x0e000000,
mdtSignature = 0x11000000,
mdtEvent = 0x14000000,
mdtProperty = 0x17000000,
mdtModuleRef = 0x1a000000,
mdtTypeSpec = 0x1b000000,
mdtAssembly = 0x20000000,
mdtAssemblyRef = 0x23000000,
mdtFile = 0x26000000,
mdtExportedType = 0x27000000,
mdtManifestResource = 0x28000000,
mdtGenericParam = 0x2a000000,
mdtMethodSpec = 0x2b000000,
mdtGenericParamConstraint = 0x2c000000,
mdtString = 0x70000000,
mdtName = 0x71000000,
mdtBaseType = 0x72000000
} CorTokenType;
当然如何把 RID 转换成对应类型的引用的话,这个还真比较简单,你可以利用 Module 对象或者 ModuleHandle 的几个成员方法解析数据,例如:Module::ResovleMethod(int metadataToken)、MethodInfo.GetMethodFromHandle(ModuleHandle.ResolveMethodHandle(int metadataToken)) 等等。
但是此处引发了一个问题,如何获取RID到底使用的是那个模块,在整个.NET反射进行反编译时是绕不开的坑,如果你无法获取到使用此 RID 的正确 Module 的引用,这一切的一切都将是扯淡虚无的,而 dotNET 并未直接提供函数如何获取,所以你只能通过另外的办法来解决这个问题,但这个前提是你对 dotNET 需要有明确的认知才可以。
private static TMember ResolveMember<TMember>(Func<Module, TMember> rcb)
where TMember : class
{
var assemblys = Assembly.GetEntryAssembly().
GetReferencedAssemblies().
Select(n => Assembly.Load(n)).ToList();
assemblys.Insert(0, typeof(Program).Assembly);
TMember mi = null;
foreach (Assembly i in assemblys)
{
foreach (Module m in i.GetModules())
{
try
{
mi = rcb(m);
}
catch (Exception) { }
}
if (mi != null) break;
}
return mi;
}
任何面向编译 dotNET 平台的编译器都遵顼一个守恒原则,即执行模块是作为必须第一个被加载的,所以它永远都是 RID 的链条的顶点 First One,然后是由此执行模块引用的模块之间进行依赖排至向树枝一般扩展,被执行模块引用的模块调用其它引用的其它模块时,顶点就会变成这个被执行模块引用的模块了,编译器必须按照这种顺序来构建成员之间的 RID,当然在我们反编译时也必须按照这种顺序来进行,否则将无法正确的进行反编译;这里的话,感兴趣的好好理解吧,有点绕哈!!!不过具体的大家可以自行参考下面的代码,build 即可用(C# build 什么的最爽~~~~了)。
namespace MININATs
{
using MININATs.Configuration;
using MININATs.NATs;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Reflection.Emit;
using System.Text.RegularExpressions;
using System.Windows.Forms;
class Program
{
public static class MSIL
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly static IDictionary<int, OpCode> opcodes =
typeof(OpCodes).GetFields().Select(fi => (OpCode)fi.GetValue(null)).ToDictionary((op) => (int)op.Value);
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly static IList<OpCode> k__BackingField_Get1 = new List<OpCode>()
{
OpCodes.Ldarg_0,
OpCodes.Ldfld,
OpCodes.Ret,
};
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly static IList<OpCode> k__BackingField_Get2 = new List<OpCode>()
{
OpCodes.Ldarg_0,
OpCodes.Ldfld,
OpCodes.Stloc_0,
OpCodes.Br_S,
OpCodes.Ldloc_0,
OpCodes.Ret,
};
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly static IList<OpCode> k__BackingField_Set1 = new List<OpCode>()
{
OpCodes.Ldarg_0,
OpCodes.Ldarg_1,
OpCodes.Stfld,
OpCodes.Ret,
};
private class Instruction
{
public long Value
{
get;
set;
}
public long Alignment
{
get;
set;
}
public OpCode OpCode
{
get;
set;
}
private bool IsCall()
{
OpCode op = this.OpCode;
return op == OpCodes.Call || op == OpCodes.Callvirt || op == OpCodes.Calli;
}
private bool IsJmp()
{
OpCode op = this.OpCode;
return op == OpCodes.Jmp ||
op == OpCodes.Brfalse ||
op == OpCodes.Brfalse_S ||
op == OpCodes.Brtrue ||
op == OpCodes.Brtrue_S ||
op == OpCodes.Leave ||
op == OpCodes.Leave_S ||
op == OpCodes.Ble ||
op == OpCodes.Ble_S ||
op == OpCodes.Ble_Un ||
op == OpCodes.Ble_Un_S ||
op == OpCodes.Blt ||
op == OpCodes.Blt_S ||
op == OpCodes.Blt_Un ||
op == OpCodes.Blt_Un_S ||
op == OpCodes.Bge ||
op == OpCodes.Bge_S ||
op == OpCodes.Bge_Un ||
op == OpCodes.Bge_Un_S ||
op == OpCodes.Bgt ||
op == OpCodes.Bgt_S ||
op == OpCodes.Bgt_Un ||
op == OpCodes.Bgt_Un_S ||
op == OpCodes.Beq ||
op == OpCodes.Beq_S ||
op == OpCodes.Bne_Un ||
op == OpCodes.Bne_Un_S ||
op == OpCodes.Bne_Un ||
op == OpCodes.Bne_Un_S;
}
private bool IsRDField()
{
OpCode op = this.OpCode;
return op == OpCodes.Ldfld ||
op == OpCodes.Stfld;
}
private bool IsLdIUValue()
{
OpCode op = this.OpCode;
return op == OpCodes.Ldc_I8 ||
op == OpCodes.Ldc_I4 ||
op == OpCodes.Ldc_I4_S ||
op == OpCodes.Ldarg ||
op == OpCodes.Ldarg_S ||
op == OpCodes.Ldarga ||
op == OpCodes.Ldarga_S ||
op == OpCodes.Stloc ||
op == OpCodes.Stloc_S ||
op == OpCodes.Ldloc ||
op == OpCodes.Ldloca ||
op == OpCodes.Ldloca_S ||
op == OpCodes.Ldloc_S ||
op == OpCodes.Starg ||
op == OpCodes.Starg_S;
}
public unsafe string ToString(long position, string fmt)
{
OpCode op = this.OpCode;
string s = op.ToString();
if (this.IsCall())
{
s += GetCallTypeILString();
}
else if (this.IsJmp())
{
long RVA = ((position + this.Alignment) + this.Value);
s += string.Format(" IL_{0}", RVA.ToString(fmt));
}
else if (this.IsLdIUValue())
{
long n = this.Alignment;
if ((n & 1) > 0)
{
n++;
}
s += " " + this.Value + " // 0x" + this.Value.ToString("x" + n);
}
else if (op == OpCodes.Ldc_R8)
{
s += " " + BitConverter.Int64BitsToDouble(this.Value);
}
else if (op == OpCodes.Ldc_R4)
{
long n = this.Value;
s += " " + *(float*)&n;
}
else if (op == OpCodes.Ldstr)
{
s += " " + "\"" + ResolveString(Convert.ToInt32(this.Value)).Replace("\"", "\\\"") + "\"";
}
else if (this.IsRDField())
{
FieldInfo f = ResolveField(Convert.ToInt32(this.Value));
string r;
if (!TryGetBasicTypeName(f.FieldType, out r))
{
s += " valuetype";
}
s += string.Format(" {0} {1}::{2}",
r,
GetBasicTypeName(f.DeclaringType),
f.Name);
}
return s;
}
private string GetCallTypeILString()
{
MethodInfo m = (MethodInfo)ResolveMethod(Convert.ToInt32(this.Value));
string s = string.Empty;
if (m != null)
{
string parameters = string.Empty;
foreach (ParameterInfo pi in m.GetParameters())
{
parameters += string.Format("{0}, ", GetBasicTypeName(pi.ParameterType));
}
if (parameters.Length > 0)
{
parameters = parameters.Remove(parameters.Length - 2);
}
if (!m.IsStatic)
{
s += " instance";
}
string r;
if (!TryGetBasicTypeName(m.ReturnType, out r))
{
s += " valuetype";
}
s += string.Format(" {0} {1}::{2}({3})",
r,
GetBasicTypeName(m.DeclaringType),
m.Name,
parameters);
}
return s;
}
private static Dictionary<Type, string> m_BasicTypeNameTable = new Dictionary<Type, string>
{
{ typeof(int), "int" },
{ typeof(uint), "uint" },
{ typeof(long), "long" },
{ typeof(ulong), "ulong" },
{ typeof(short), "short" },
{ typeof(ushort), "ushort" },
{ typeof(sbyte), "sbyte" },
{ typeof(byte), "byte" },
{ typeof(bool), "bool" },
{ typeof(float), "float" },
{ typeof(double), "double" },
{ typeof(char), "char" },
{ typeof(decimal), "decimal" },
{ typeof(void), "void" },
};
private static string GetBasicTypeName(Type type)
{
string s;
TryGetBasicTypeName(type, out s);
return s;
}
private static bool TryGetBasicTypeName(Type type, out string value)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
if (type.IsGenericType && !type.IsGenericTypeDefinition)
{
Type[] gtypes = type.GetGenericArguments();
string ss = string.Empty;
foreach (Type gi in gtypes)
{
ss += GetBasicTypeName(gi) + ", ";
}
if (ss.Length > 0)
{
ss = ss.Remove(ss.Length - 2);
}
string gfn = type.FullName;
int ii = gfn.IndexOf('[');
if (ii >= 0)
{
gfn = gfn.Substring(0, ii);
}
value = ("[" + GetModuleName(type) + "]") + (ss = gfn + "<" + ss + ">");
return false;
}
string t;
if (m_BasicTypeNameTable.TryGetValue(type, out t))
{
value = t;
return true;
}
else
{
value = ("[" + GetModuleName(type) + "]") + type.FullName;
}
return false;
}
private static TMember ResolveMember<TMember>(Func<Module, TMember> rcb)
where TMember : class
{
var assemblys = Assembly.GetEntryAssembly().
GetReferencedAssemblies().
Select(n => Assembly.Load(n)).ToList();
assemblys.Insert(0, typeof(Program).Assembly);
TMember mi = null;
foreach (Assembly i in assemblys)
{
foreach (Module m in i.GetModules())
{
try
{
mi = rcb(m);
}
catch (Exception) { }
}
if (mi != null) break;
}
return mi;
}
public static MethodBase ResolveMethod(int metadataToken)
{
return ResolveMember(m => m.ResolveMethod(metadataToken));
}
public static FieldInfo ResolveField(int metadataToken)
{
return ResolveMember(m => m.ResolveField(metadataToken));
}
public static string ResolveString(int metadataToken)
{
return ResolveMember(m => m.ResolveString(metadataToken));
}
}
private static IList<Instruction> GetInstructions(MethodInfo m)
{
if (m == null)
{
throw new ArgumentNullException("m");
}
IList<Instruction> instructions = new List<Instruction>();
MethodBody body = m.GetMethodBody();
if (body == null)
{
return instructions;
}
byte[] il = body.GetILAsByteArray();
int ofs = 0;
while (ofs < il.Length)
{
int start = ofs;
short op = il[ofs];
ofs++;
if (op == 0xFE || opcodes[op].OpCodeType == OpCodeType.Prefix)
{
op = (short)((op << 8) + il[ofs]);
ofs++;
}
OpCode code = opcodes[op];
long argument = 0;
int extsz = 4;
if (code.OperandType == OperandType.InlineNone)
{
extsz = 0;
}
else if (code.OperandType == OperandType.ShortInlineBrTarget || code.OperandType == OperandType.ShortInlineI || code.OperandType == OperandType.ShortInlineVar)
{
extsz = 1;
}
else if (code.OperandType == OperandType.InlineVar)
{
extsz = 2;
}
else if (code.OperandType == OperandType.InlineI8 || code.OperandType == OperandType.InlineR)
{
extsz = 8;
}
else if (code.OperandType == OperandType.InlineSwitch)
{
long n = il[ofs] + (il[ofs + 1] << 8) + (il[ofs + 2] << 16) + (il[ofs + 3] << 24);
extsz = (int)(4 * n + 4);
}
if (extsz > 0)
{
long n = 0;
for (int i = 0; i < extsz; ++i)
{
long v = il[ofs + i];
n += v << (i * 8);
}
argument = n;
ofs += extsz;
}
instructions.Add(new Instruction() { OpCode = code, Value = argument, Alignment = extsz + code.Size });
}
return instructions;
}
private static string GetModuleName(Assembly assembly)
{
if (assembly == null)
{
throw new ArgumentNullException("assembly");
}
string s = assembly.FullName;
int i = s.IndexOf(",");
if (i >= 0)
{
s = s.Substring(0, i);
}
return s;
}
private static string GetModuleName(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
return GetModuleName(type.Assembly);
}
public static string Decompiler(MethodInfo m)
{
if (m == null)
{
throw new ArgumentNullException("m");
}
MethodBody body = m.GetMethodBody();
string out_ = string.Empty;
IList<Instruction> instructions = GetInstructions(m);
IList<ExceptionHandlingClause> clauses = body.ExceptionHandlingClauses;
int iltot = body.GetILAsByteArray().Length;
int ilcxc = 0;
while (iltot > 0)
{
iltot = iltot / 16;
ilcxc++;
}
if (ilcxc < 4)
{
ilcxc = 4;
}
string ilsxc = "x" + ilcxc;
long position = 0;
int S_Try_depth = 0; // 顶点
int S_Finally_depth = 0;
foreach (Instruction i in instructions)
{
string line = string.Empty;
ExceptionHandlingClause clause = clauses.FirstOrDefault((c) => c.TryOffset == position);
if (clause != null && clause.Flags == ExceptionHandlingClauseOptions.Clause)
{
line += "".PadLeft(4 * S_Try_depth) + ".try\r\n{\r\n";
S_Try_depth++;
}
clause = clauses.FirstOrDefault((c) => (c.TryOffset + c.TryLength) == position);
if (clause != null && clause.Flags == ExceptionHandlingClauseOptions.Clause)
{
S_Try_depth--;
line += "".PadLeft(4 * S_Try_depth) + "} // end .try\r\n";
}
clause = clauses.FirstOrDefault((c) => c.HandlerOffset == position);
if (clause != null)
{
if (clause.Flags == ExceptionHandlingClauseOptions.Finally)
{
string s1sp_ = "".PadLeft(4 * S_Finally_depth);
int iii_xx26 = out_.LastIndexOf("\r\n", out_.Length - 2);
string s3sp_ = null;
if (iii_xx26 < 0 || ((s3sp_ = out_.Substring(iii_xx26 + 2)).IndexOf("} ") != -1))
{
line += s1sp_ + "finally\r\n" + s1sp_ + "{\r\n";
}
else
{
string s2sp_ = out_.Substring(0, iii_xx26 + 2);
out_ = s2sp_;
S_Finally_depth++;
line += s1sp_ + "finally\r\n" + s1sp_ + "{\r\n" + "".PadLeft(4 * S_Finally_depth) + s3sp_;
}
}
else
{
string s1sp_ = "".PadLeft(4 * S_Try_depth);
line += s1sp_ + string.Format("catch [{0}]{1}\r\n{2}{{\r\n",
GetModuleName(clause.CatchType), clause.CatchType.FullName, s1sp_);
S_Try_depth++;
}
}
clause = clauses.FirstOrDefault((c) => (c.HandlerOffset + c.HandlerLength) == position);
if (clause != null)
{
if (clause.Flags == ExceptionHandlingClauseOptions.Finally)
{
S_Finally_depth--;
line += "".PadLeft(4 * S_Finally_depth) + "} // end handler \r\n";
}
else
{
S_Try_depth--;
line += "".PadLeft(4 * S_Try_depth) + "} // end handler \r\n";
}
}
line += (S_Finally_depth > 0 ? "".PadLeft(4 * S_Finally_depth) : "".PadLeft(4 * S_Try_depth)) +
string.Format("IL_{0}: {1}\r\n", position.ToString(ilsxc), i.ToString(position, ilsxc));
out_ += line;
position += i.Alignment;
}
return out_.Length >= 2 ? out_.Remove(out_.Length - 2) : out_;
}
}
public static bool? TestDOO()
{
return false;
}
class Aff
{
public int b;
public void A(Match m)
{
}
};
public static void TestDecompiler()
{
SupersocksR.Win32.Debugger.AdjustPrivilege();
try {
Aff aff = null;
aff.b = 88;
aff.A(null);
TestDOO();
int a = 1000;
long b = 0xFFFFFFF1123123;
float c = 3.142122f;
double d = 3.142122515;
Console.WriteLine(a / 0);
}
catch (Exception e) {
Console.WriteLine(e.Message);
}
finally {
Console.WriteLine("finally");
}
}
static void Main(string[] args)
{
var s = typeof(Program).GetMethod("TestDecompiler");
string il = MSIL.Decompiler(s);
}
}
}
更多推荐
所有评论(0)