原文地址:
http://bbs.pediy.com/showthread.php?p=1079718
已测环境 :
XP SP3
原版 OD
OllyICE v1.10[汉化第二版],LordPE(LordPE Deluxe by youda),
CFF Explorer II,Windbg:6.11.0001.404 X86, .net Reflector V6.6.0.30,WinHex 15.1,IL字节码解码工具V 2.0。
WinDbg
AxProtector
AxProtector 是一款德国瑞步的加密狗dotNet加壳器。产品介绍去自己看http://www.wibu.us/products/axprotector.html
先加壳 加壳选项如图1-2:选上AES加密 基本反调试选项
----------ok,
我们看看 加壳前的区段如图所示,加壳后程序的区段如图所示。可以看出加壳后的程序增加了一个.sdata区段。
输入表比较,加壳前后的输入表没有变化,请看下图
先静态反编译一下,看看它对我们的小程序做了什么手脚。
采用Reflector载入dot_NET_bounce后,可以发现加壳后的程序的增加了威步相关的类,程序原来的类的名称和字段名称相关信息没有改变,如图所示。
加壳后程序的方法中采用switch加入了流程混淆,只能采用IL代码查看,以bounce_loop为例该方法的IL代码如下。从中可以看出用的是动态调用和委托来执行原来的代码。
.method public hidebysig virtual instance void
bounce_loop(object ob,
class [mscorlib]System.EventArgs ev) cil managed
{
// Code size 246 (0xf6)
.maxstack 12
.locals init (int32 pinned V_0, class [mscorlib]System.Type[] pinned V_1)
IL_0000: ldc.i4.4
IL_0001: br IL_0019
IL_0006: ldnull
IL_0007: stsfld class [mscorlib]System.Type[] com.wibu.xpm.AxpNet.QTvJOYTWFEBSHZO::voX0cCgoco
IL_000c: ldc.i4.0
IL_000d: br IL_0019
IL_0012: ldnull
IL_0013: stsfld class [mscorlib]System.Type[] com.wibu.xpm.AxpNet.QTvJOYTWFEBSHZO::kuFup3Ww5UH
IL_0018: ldc.i4.1
IL_0019: switch ( IL_0012, IL_002f, IL_0047)
IL_002a: br IL_0006
IL_002f: br.s IL_0038
IL_0031: ldc.i4.s 20
IL_0033: call void [mscorlib]System.Threading.Thread::Sleep(int32)
IL_0038: volatile.
IL_003a: ldsfld bool modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) com.wibu.xpm.AxpNet.QTvJOYTWFEBSHZO::GOnQQaxbvpt0
IL_003f: brfalse.s IL_0031
IL_0041: ldc.i4.2
IL_0042: br IL_0019
IL_0047: ldc.i4 0x2
IL_004c: ldc.i4 0x244
IL_0051: newarr [mscorlib]System.Byte
IL_0056: dup
IL_0057: ldtoken field valuetype $ArrayType$580 com.wibu.xpm.AxpNet.QTvJOYTWFEBSHZO::m2
IL_005c: call void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array,
valuetype [mscorlib]System.RuntimeFieldHandle)
IL_0061: ldtoken [mscorlib]System.Void
IL_0066: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_006b: ldc.i4.s 3
IL_006d: newarr [mscorlib]System.Type
IL_0072: stloc.1
IL_0073: ldloc.1
IL_0074: ldc.i4.0
IL_0075: ldtoken Aladdin.BouncingBall.Sample
IL_007a: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_007f: stelem.ref
IL_0080: ldloc.1
IL_0081: ldc.i4.s 1
IL_0083: ldtoken [mscorlib]System.Object
IL_0088: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_008d: stelem.ref
IL_008e: ldloc.1
IL_008f: ldc.i4.s 2
IL_0091: ldtoken [mscorlib]System.EventArgs
IL_0096: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_009b: stelem.ref
IL_009c: ldloc.1
IL_009d: ldtoken Aladdin.BouncingBall.Sample
IL_00a2: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_00a7: ldnull
IL_00a8: ldsfld class [mscorlib]System.Reflection.MethodBase[] com.wibu.xpm.AxpNet.QTvJOYTWFEBSHZO::BaseMethods
IL_00ad: ldc.i4 0x2
IL_00b2: ldelem.ref
IL_00b3: ldnull
IL_00b4: ceq
IL_00b6: brfalse.s IL_00be
IL_00b8: pop
IL_00b9: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetCurrentMethod()
IL_00be: call class [mscorlib]System.Reflection.Emit.DynamicMethod com.wibu.xpm.AxpNet.QTvJOYTWFEBSHZO::GetMethod(int32,
uint8[],
class [mscorlib]System.Type,
class [mscorlib]System.Type[],
class [mscorlib]System.Type,
class [mscorlib]System.Reflection.MethodBase)
IL_00c3: ldtoken class com.wibu.xpm.AxpNet.QTvJOYTWFEBSHZO/da00<object,class [mscorlib]System.EventArgs>
IL_00c8: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_00cd: ldarg.0
IL_00ce: callvirt instance class [mscorlib]System.Delegate [mscorlib]System.Reflection.Emit.DynamicMethod::CreateDelegate(class [mscorlib]System.Type,
object)
IL_00d3: castclass class com.wibu.xpm.AxpNet.QTvJOYTWFEBSHZO/da00<object,class [mscorlib]System.EventArgs>
IL_00d8: ldarg.1
IL_00d9: ldarg.2
IL_00da: ldsfld int32 com.wibu.xpm.AxpNet.QTvJOYTWFEBSHZO::okVUZmPoInkRot
IL_00df: stloc.0
IL_00e0: ldc.i4 0x2
IL_00e5: stsfld int32 com.wibu.xpm.AxpNet.QTvJOYTWFEBSHZO::okVUZmPoInkRot
IL_00ea: callvirt instance void class com.wibu.xpm.AxpNet.QTvJOYTWFEBSHZO/da00<object,class [mscorlib]System.EventArgs>::Invoke(!0,!1)
IL_00ef: ldloc.0
IL_00f0: stsfld int32 com.wibu.xpm.AxpNet.QTvJOYTWFEBSHZO::okVUZmPoInkRot
IL_00f5: ret
} // end of method Sample::bounce_loop
解密加密数据方法的C#代码如下所示,从中可以看出使用AES算法进行解密。
internal static byte[] Iw5cqEEEffEbCUV(byte[] Encrypted, byte[] Key)
{
try
{
RijndaelManaged managed = new RijndaelManaged();
managed .Mode = CipherMode.CBC;
managed .IV = IV;
managed .Key =Key ;
MemoryStream stream = new MemoryStream();
CryptoStream stream2 = new CryptoStream(, .CreateDecryptor(), CryptoStreamMode.Write);
stream2.Write(, 0, .Length);
stream2.FlushFinalBlock();
return stream2.ToArray();
}
catch
{
return new byte[1];
}
}
用OllyICE寻找动态生成的方法
运行动态方法,需要对动态生成的方法进行编译,因此可以在CompileMethod方法上下断点。
找到CompileMethod函数的地址
运行加壳后的程序,用OllyICE进行附加,查看mscorjit.dll模块的输出函数getJit函数,如所示。
地址790A60A0指向虚函数表,该虚函数表的第一个指针即为CompileMethod函数的地址,本例该函数的地址为7906114F,如图所示。
寻找动态方法中的IL代码的方法,此处以bounce_loop生成的动态方法为例。
用CFFExplorer在方法表中找到bounce_loop的IL代码的文件偏移为1318,如图所示。用地址转换工具将文件偏移转换为虚拟地址,结果如图所示。
bp 7906114F [[esp+0xC]+0x8]==0x00402318 设置条件断点,此断点的含义为要编译的IL代码的地址为0x00402318 ,中断后取消条件断点。中断后再次用bp7906114F 设置断点,此时查看堆栈,并在数据窗口中跟随来到esp+c处,如图3-6所示。从图中可以看出,动态生成的IL代码的地址为00152B40,大小为1BB。
图3-4
图3-5
图3-6
将字节码转换为IL代码。
从00152b40处开始,大小为1BB的字节码为:
02 7B 02 00 00 04 02 28 03 00 00 06 0A 12 00 28 04 00 00 06 33 19 02 7B 05 00 00 04 02 28 06 00
00 06 0A 12 00 28 07 00 00 06 3B A5 00 00 00 02 02 28 08 00 00 06 0A 12 00 28 09 00 00 06 7D 0A
00 00 04 02 02 28 0B 00 00 06 0A 12 00 28 0C 00 00 06 7D 0D 00 00 04 02 02 28 0E 00 00 06 0A 12
00 28 0F 00 00 06 18 5B 02 7B 10 00 00 04 18 5B 59 7D 11 00 00 04 02 02 28 12 00 00 06 0A 12 00
28 13 00 00 06 18 5B 02 7B 14 00 00 04 18 5B 59 7D 15 00 00 04 02 02 7B 16 00 00 04 1C 5B 7D 17
00 00 04 02 02 7B 18 00 00 04 1F 37 5B 7D 19 00 00 04 02 7B 1A 00 00 04 18 2F 07 02 18 7D 1B 00
00 04 02 7B 1C 00 00 04 1F 0A 31 08 02 1F 0A 7D 1D 00 00 04 02 7B 1E 00 00 04 17 FE 01 02 7B 1F
00 00 04 02 28 20 00 00 06 0A 12 00 28 21 00 00 06 02 7B 22 00 00 04 59 19 58 FE 04 5F 2C 15 02
25 7B 23 00 00 04 02 7B 24 00 00 04 58 7D 25 00 00 04 2B 2D 02 16 7D 26 00 00 04 02 7B 27 00 00
04 1F FD 31 15 02 25 7B 28 00 00 04 02 7B 29 00 00 04 59 7D 2A 00 00 04 2B 07 02 17 7D 2B 00 00
04 02 7B 2C 00 00 04 19 FE 01 02 7B 2D 00 00 04 02 28 2E 00 00 06 0A 12 00 28 2F 00 00 06 02 7B
30 00 00 04 59 19 58 FE 04 5F 2C 15 02 25 7B 31 00 00 04 02 7B 32 00 00 04 58 7D 33 00 00 04 2B
2D 02 18 7D 34 00 00 04 02 7B 35 00 00 04 1F FD 31 15 02 25 7B 36 00 00 04 02 7B 37 00 00 04 59
7D 38 00 00 04 2B 07 02 19 7D 39 00 00 04 02 02 28 3A 00 00 06 28 3B 00 00 06 2A
用字节码解码工具反编译为IL代码,对应的IL代码为:IL_0000: ldarg.0
IL_0001: ldfld <mdField> 0x4000002
IL_0006: ldarg.0
IL_0007: call <method> 0x6000003
IL_000C: stloc.0
IL_000D: ldloca.s 0x0
IL_000F: call <method> 0x6000004
IL_0014: bne.un.s <label> IL_002F
IL_0016: ldarg.0
IL_0017: ldfld <mdField> 0x4000005
IL_001C: ldarg.0
IL_001D: call <method> 0x6000006
IL_0022: stloc.0
IL_0023: ldloca.s 0x0
IL_0025: call <method> 0x6000007
IL_002A: beq <label> IL_00D4
IL_002F: ldarg.0
IL_0030: ldarg.0
IL_0031: call <method> 0x6000008
IL_0036: stloc.0
IL_0037: ldloca.s 0x0
IL_0039: call <method> 0x6000009
IL_003E: stfld <mdField> 0x400000A
IL_0043: ldarg.0
IL_0044: ldarg.0
IL_0045: call <method> 0x600000B
IL_004A: stloc.0
IL_004B: ldloca.s 0x0
IL_004D: call <method> 0x600000C
IL_0052: stfld <mdField> 0x400000D
IL_0057: ldarg.0
IL_0058: ldarg.0
IL_0059: call <method> 0x600000E
IL_005E: stloc.0
IL_005F: ldloca.s 0x0
IL_0061: call <method> 0x600000F
IL_0066: ldc.i4.2
IL_0067: div
IL_0068: ldarg.0
IL_0069: ldfld <mdField> 0x4000010
IL_006E: ldc.i4.2
IL_006F: div
IL_0070: sub
IL_0071: stfld <mdField> 0x4000011
IL_0076: ldarg.0
IL_0077: ldarg.0
IL_0078: call <method> 0x6000012
IL_007D: stloc.0
IL_007E: ldloca.s 0x0
IL_0080: call <method> 0x6000013
IL_0085: ldc.i4.2
IL_0086: div
IL_0087: ldarg.0
IL_0088: ldfld <mdField> 0x4000014
IL_008D: ldc.i4.2
IL_008E: div
IL_008F: sub
IL_0090: stfld <mdField> 0x4000015
IL_0095: ldarg.0
IL_0096: ldarg.0
IL_0097: ldfld <mdField> 0x4000016
IL_009C: ldc.i4.6
IL_009D: div
IL_009E: stfld <mdField> 0x4000017
IL_00A3: ldarg.0
IL_00A4: ldarg.0
IL_00A5: ldfld <mdField> 0x4000018
IL_00AA: ldc.i4.s 0x37
IL_00AC: div
IL_00AD: stfld <mdField> 0x4000019
IL_00B2: ldarg.0
IL_00B3: ldfld <mdField> 0x400001A
IL_00B8: ldc.i4.2
IL_00B9: bge.s <label> IL_00C2
IL_00BB: ldarg.0
IL_00BC: ldc.i4.2
IL_00BD: stfld <mdField> 0x400001B
IL_00C2: ldarg.0
IL_00C3: ldfld <mdField> 0x400001C
IL_00C8: ldc.i4.s 0xA
IL_00CA: ble.s <label> IL_00D4
IL_00CC: ldarg.0
IL_00CD: ldc.i4.s 0xA
IL_00CF: stfld <mdField> 0x400001D
IL_00D4: ldarg.0
IL_00D5: ldfld <mdField> 0x400001E
IL_00DA: ldc.i4.1
IL_00DB: ceq
IL_00DD: ldarg.0
IL_00DE: ldfld <mdField> 0x400001F
IL_00E3: ldarg.0
IL_00E4: call <method> 0x6000020
IL_00E9: stloc.0
IL_00EA: ldloca.s 0x0
IL_00EC: call <method> 0x6000021
IL_00F1: ldarg.0
IL_00F2: ldfld <mdField> 0x4000022
IL_00F7: sub
IL_00F8: ldc.i4.3
IL_00F9: add
IL_00FA: clt
IL_00FC: and
IL_00FD: brfalse.s <label> IL_0114
IL_00FF: ldarg.0
IL_0100: dup
IL_0101: ldfld <mdField> 0x4000023
IL_0106: ldarg.0
IL_0107: ldfld <mdField> 0x4000024
IL_010C: add
IL_010D: stfld <mdField> 0x4000025
IL_0112: br.s <label> IL_0141
IL_0114: ldarg.0
IL_0115: ldc.i4.0
IL_0116: stfld <mdField> 0x4000026
IL_011B: ldarg.0
IL_011C: ldfld <mdField> 0x4000027
IL_0121: ldc.i4.s 0xFFFFFFFD
IL_0123: ble.s <label> IL_013A
IL_0125: ldarg.0
IL_0126: dup
IL_0127: ldfld <mdField> 0x4000028
IL_012C: ldarg.0
IL_012D: ldfld <mdField> 0x4000029
IL_0132: sub
IL_0133: stfld <mdField> 0x400002A
IL_0138: br.s <label> IL_0141
IL_013A: ldarg.0
IL_013B: ldc.i4.1
IL_013C: stfld <mdField> 0x400002B
IL_0141: ldarg.0
IL_0142: ldfld <mdField> 0x400002C
IL_0147: ldc.i4.3
IL_0148: ceq
IL_014A: ldarg.0
IL_014B: ldfld <mdField> 0x400002D
IL_0150: ldarg.0
IL_0151: call <method> 0x600002E
IL_0156: stloc.0
IL_0157: ldloca.s 0x0
IL_0159: call <method> 0x600002F
IL_015E: ldarg.0
IL_015F: ldfld <mdField> 0x4000030
IL_0164: sub
IL_0165: ldc.i4.3
IL_0166: add
IL_0167: clt
IL_0169: and
IL_016A: brfalse.s <label> IL_0181
IL_016C: ldarg.0
IL_016D: dup
IL_016E: ldfld <mdField> 0x4000031
IL_0173: ldarg.0
IL_0174: ldfld <mdField> 0x4000032
IL_0179: add
IL_017A: stfld <mdField> 0x4000033
IL_017F: br.s <label> IL_01AE
IL_0181: ldarg.0
IL_0182: ldc.i4.2
IL_0183: stfld <mdField> 0x4000034
IL_0188: ldarg.0
IL_0189: ldfld <mdField> 0x4000035
IL_018E: ldc.i4.s 0xFFFFFFFD
IL_0190: ble.s <label> IL_01A7
IL_0192: ldarg.0
IL_0193: dup
IL_0194: ldfld <mdField> 0x4000036
IL_0199: ldarg.0
IL_019A: ldfld <mdField> 0x4000037
IL_019F: sub
IL_01A0: stfld <mdField> 0x4000038
IL_01A5: br.s <label> IL_01AE
IL_01A7: ldarg.0
IL_01A8: ldc.i4.3
IL_01A9: stfld <mdField> 0x4000039
IL_01AE: ldarg.0
IL_01AF: ldarg.0
IL_01B0: call <method> 0x600003A
IL_01B5: call <method> 0x600003B
IL_01BA: ret
从得到的IL代码可以看出,动态生成的代码的元数据并没有存储在文件中。要完全修复上面的代码需要找到每个token对应的元数据。
用windbg寻找动态方法中token对应的元数据
用windbg载入加壳后的程序。
置符号路径
srv*d:\zhuqf\symbols*http://msdl.microsoft.com/download/symbols
载入SOS.dll
sxe ld mscorwks(在载入mscorwks.dll时中断)
g(运行)
.loadby sos.dll mscorwks
载入mscorwks符号
ld mscorwks
在加壳后的程序的入口方法处中断
bp mscorwks!Assembly::GetEntryPoint
g
5. 载入mscorjit.dll时中断
sxe ld mscorjit
g
载入mscorjit符号
ld mscorjit
查看domain信息
!dumpdomain,结果如3-7图所示。
图3-7
查看dot_NET_bounce.exe 模块信息
!dumpmodule -mt 00992c5c,结果如图3-8所示。
图3—8
查看sample类的信息
!dumpmt -md 0099643c,结果如图3-9所示。
图3-9
在bounce_loop方法上设置未决断点
!bpmd -md 0099633c
g
查看bonunce_loop方法的信息
!dumpmd 0099633c,结果如图3-10所示,图中可以看出此时该方法已经被及时编译完成。
图
3-10
在compilemethod方法上设置断点
bp mscorjit!ciljit::compilemethod
g
中断后查看堆栈,找到方法描述符,dump IL代码
kb
dd 00c9f740 (该命令会显示CORINFO_METHOD_INFO结构)
!dumpil 01044538
g
结果如图3-11所示,从图中可以看出该方法不是动态生成的方法,因此需要继续运行到下一次中断处。
图
3-11
中断后查看堆栈,找到动态方法的描述符
kb
dd 0012ebf0
结果如图 3-12所示。
图3-12
Dump IL代码
!dumpil 0104751c
结果如图3-13所示,从图中可以看出这段IL代码为动态生成的代码,和之前用字节码解码工具解析的IL代码,其中的方法的token已经可以显示,然而Field的token代表的信息仍然不明确。
图3-13
总结
加壳后的程序为托管程序,程序运行时会调用安装在GAC中的WibuCmNet.dll,同时需要CodeMeter.exe服务程序的支持。
加壳后的程序的方法名,字段名等名称相关的信息均不改变,程序的方法体改变,中间采用了switch语句进行流程混淆,增加了调用CodeMeter锁相关的类。
程序运行时采用AES算法解密字节码,根据解密信息创建动态方法,通过委托技术来执行动态方法。动态方法在.net 2.0之后才支持,加壳前的程序为.net 1.1程序集,加壳后使用.net 2.0的程序集。
支持签署强名称。
优点:
加壳后程序的方法体进行了流程混淆,静态分析时只能查看IL代码。
在内存中生成的动态方法的元数据信息难寻找。
缺点:
加壳后的程序运行时需要codemeter.exe的支持,加壳后的程序在其他机器上运行时需要安装CodeMeter相关的组件。
反调试机制形同虚设,OllyICE和Windbg调试时没有遇到障碍。
流程混淆很容易手工去掉。
类名和字段名等名称信息,加壳后均没有发生改变。
综合所述,此壳虽说aes加密,但是对于专业cracker来说,捞代码,补全,重编译 就是一肉鸡,不过大家很难拿到这种加密狗演练,呵呵。