修改了一下:
00410072 | . 6A 00 PUSH 0 ; / pModule = NULL
00410074 | . E8 310A0000 CALL < JMP. & KERNEL32.GetModuleHandleA > ; /GetModuleHandleA
00410079 | . A3 B0004200 MOV DWORD PTR DS:[4200B0],EAX
0041007E | . A3 24004200 MOV DWORD PTR DS:[ 420024 ],EAX
00410083 | . E8 160A0000 CALL < JMP. & KERNEL32.GetCommandLineA > ; [GetCommandLineA
00410088 90 NOP 《- 注意这里
00410089 90 NOP
0041008A 90 NOP
0041008B 90 / NOP
0041008C 90 NOP
0041008D 90 | NOP
0041008E 90 | NOP
0041008F 90 NOP
00410090 90 | NOP
00410091 90 NOP 《- 还有这里
00410092 | . C705 20004200 >| MOV DWORD PTR DS:[ 420020 ],loaddll. 00420 > ; ASCII " Missing DLL name "
0041009C | . E9 EB010000 | JMP loaddll.0041028C
004100A1 |> 3C 22 | CMP AL, 22
004100A3 | . ^ 75 E6 /JNZ SHORT loaddll.0041008B
004100A5 |> 8A06 / MOV AL,BYTE PTR DS:[ESI]
004100A7 | . 3C 20 | CMP AL, 20
004100A9 | . 75 03 | JNZ SHORT loaddll.004100AE
004100AB | . 46 | INC ESI
004100AC | . ^ EB F7 /JMP SHORT loaddll.004100A5
00410072 | . 6A 00 PUSH 0 ; / pModule = NULL
00410074 | . E8 310A0000 CALL < JMP. & KERNEL32.GetModuleHandleA > ; /GetModuleHandleA
00410079 | . A3 B0004200 MOV DWORD PTR DS:[4200B0],EAX
0041007E | . A3 24004200 MOV DWORD PTR DS:[ 420024 ],EAX
00410083 | . E8 160A0000 CALL < JMP. & KERNEL32.GetCommandLineA > ; [GetCommandLineA
00410088 EB 08 JMP SHORT loaddll. 00410092 《- 注意 已经没有00410092
0041008A 2910 SUB DWORD PTR DS:[EAX],EDX
0041008C F8 CLC
0041008D 60 PUSHAD
0041008E 99 CDQ
0041008F F8 CLC
00410090 E8 E8C70520 | CALL 2046C87D
00410095 0042 00 ADD BYTE PTR DS:[EDX],AL
00410098 |? 59 POP ECX
00410099 |? 0142 00 ADD DWORD PTR DS:[EDX],EAX
0041009C | . E9 EB010000 | JMP loaddll.0041028C
004100A1 |> 3C 22 | CMP AL, 22
004100A3 | . ^ 75 E6 /JNZ SHORT loaddll.0041008B
004100A5 |> 8A06 / MOV AL,BYTE PTR DS:[ESI]
004100A7 | . 3C 20 | CMP AL, 20
004100A9 | . 75 03 | JNZ SHORT loaddll.004100AE
004100AB | . 46 | INC ESI
004100AC | . ^ EB F7 /JMP SHORT loaddll.004100A5
块编号
|
块代码
|
1
|
第一个功能
|
2
|
第二个功能
|
3
|
第三个功能
|
4
|
第四个功能
|
块编号
|
块代码
|
跳转
|
1
|
第一个功能
|
Jmp 2
|
4
|
第四个功能
|
|
3
|
第三个功能
|
Jmp 4
|
2
|
第二个功能
|
Jmp 3
|
.method private hidebysig instance string CreatePassword(char[] passwords, int32 arraylenghts, int32 lenghts) cil managed
{
// Code Size: 50 byte(s)
.maxstack 4
.locals (
int32 num1,
[mscorlib]System.Random random1,
string text1)
L_0000: newobj instance void [mscorlib]System.Random::.ctor()
L_0005: stloc.1
L_0006: ldstr ""
L_000b: stloc.2
L_000c: ldc.i4.0
L_000d: stloc.0
L_000e: br.s L_002c
L_0010: ldloc.2
L_0011: ldarg.1
L_0012: ldloc.1
L_0013: callvirt instance float64 [mscorlib]System.Random::NextDouble()
L_0018: ldarg.2
L_0019: conv.r8
L_001a: mul
L_001b: conv.i4
L_001c: ldelem.u2
L_001d: box char
L_0027: stloc.2
L_0028: ldloc.0
L_0029: ldc.i4.1
L_002a: add
L_002b: stloc.0
L_002c: ldloc.0
L_002d: ldarg.3
L_002e: ble.s L_0010
L_0030: ldloc.2
L_0031: ret
}
.method private hidebysig instance string CreatePassword(char[] xb97f21c4af3d3653, int32 x37f140bfe992d2c4, int32 x6ad44599b278247e) cil managed
{
// Code Size: 56 byte(s)
.maxstack 4
.locals (
int32 num1,
[mscorlib]System.Random random1,
string text1)
L_0000: newobj instance void [mscorlib]System.Random::.ctor()
L_0005: stloc.1
L_0006: ldstr ""
L_000b: br.s L_0021
L_000d: mul
L_000e: conv.i4
L_000f: ldelem.u2
L_0010: box char
L_001a: stloc.2
L_001b: ldloc.0
L_001c: ldc.i4.1
L_001d: add
L_001e: stloc.0
L_001f: br.s L_0032
L_0021: stloc.2
L_0022: ldc.i4.0
L_0023: stloc.0
L_0024: br.s L_0032
L_0026: ldloc.2
L_0027: ldarg.1
L_0028: ldloc.1
L_0029: callvirt instance float64 [mscorlib]System.Random::NextDouble()
L_002e: ldarg.2
L_002f: conv.r8
L_0030: br.s L_000d
L_0032: ldloc.0
L_0033: ldarg.3
L_0034: ble.s L_0026
L_0036: ldloc.2
L_0037: ret
}
同时,有说得不对之处,还请高手赐教
由浅至深 谈谈.NET混淆原理(三)-- 流程混淆(续)
由于昨天发布MaxtoCode,所以没有时间写随笔。
本来是没有这一篇的,但想了想,觉得自己讲得太肤浅,怕有的朋友听不懂,所以决定在流程混淆里再讲一篇。这次我们拿XenoCode的混淆算法来进行一次详细的讲解。
XenoCode可能是需要保护自己软件的朋友最常用的混淆工具,他的流程混淆算法是怎样的呢?(有的叫做 控制流程模糊,其实原理都一样)
首先,我再次申请,制造混淆最常用的方式是跳转指令。它就是把原有的代码结构错位,再用跳转指令把原有的执行逻辑连接起来。见上一篇文章的表。而跳转指令有强形跳转如:C#中的goto,也有逻辑跳转,如C#中的 if (a==0){goto ?}等,如果在混淆中充分利用这些技术,混淆的程序将相当复杂,反混淆器将更加困难。还好XenoCode使用的仅仅是goto,而没有包含逻辑跳转在其中。(当然,如果有逻辑跳转,也可以写出反混淆器,因为必须模式是一样的,总要有条件,比方说: a==0才跳,这一句就必须跳,所以a必须恒等于0,那么在逻辑处理的前面肯定有a置0的语句,满足这两个条件,我们就可以判断这是一个破坏条件的条件,名进行恢复)
好,这次我们主要分析XenoCode是如何来进行流程混淆的,你也可以手工校仿,不过效率并不高。
我们还是来看上篇文章的代码:
.method private hidebysig instance string CreatePassword(char[] xb97f21c4af3d3653, int32 x37f140bfe992d2c4, int32 x6ad44599b278247e) cil managed
{
// Code Size: 56 byte(s)
.maxstack 4
.locals (
int32 num1,
[mscorlib]System.Random random1,
string text1)
L_0000: newobj instance void [mscorlib]System.Random::.ctor()
L_0005: stloc.1
L_0006: ldstr ""
L_000b: br.s L_0021
L_000d: mul
L_000e: conv.i4
L_000f: ldelem.u2
L_0010: box char
L_0015: call string string::Concat(object, object)
L_001a: stloc.2
L_001b: ldloc.0
L_001c: ldc.i4.1
L_001d: add
L_001e: stloc.0
L_001f: br.s L_0032
L_0021: stloc.2
L_0022: ldc.i4.0
L_0023: stloc.0
L_0024: br.s L_0032
L_0026: ldloc.2
L_0027: ldarg.1
L_0028: ldloc.1
L_0029: callvirt instance float64 [mscorlib]System.Random::NextDouble()
L_002e: ldarg.2
L_002f: conv.r8
L_0030: br.s L_000d
L_0032: ldloc.0
L_0033: ldarg.3
L_0034: ble.s L_0026
L_0036: ldloc.2
L_0037: ret
}
分析一下其中的 br.s 指令,(br.s指令是强跳指令)我们可以得出一个结论:
L_000b: br.s L_0021
L_001f: br.s L_0032
L_0030: br.s L_000d
这三个是重要跳转指令,其算法如下:
序号 | 源代码块 | 序号 | 新代码块 |
1 | 块1 | 1 | 块1 |
2 | 块2 | 2 | 块4 |
3 | 块3 | 3 | 块3 |
4 | 块4 | 4 | 块2 |
这是什么意思呢?
从方法的头尾开始分析,直至中间分析完毕。尾部的基本上就是头部的代码,头部的也有尾部的代码,互相交错,从而实现混淆,一般的反编译器只能对此Say No了。
如果你要手工混淆你的代码,你需要做以下几件事:
1. 把源代码分成几块
2. 把这么几块的顺序打乱
3. 用br.s对这几块的顺序进行连接,并保护执行达到原来的逻辑
4. 重新计算行号
这样,你就能拥有自己的流程混淆了。如果你加入真真假假的逻辑跳转来混淆,强度将会更大。
下一篇,我们讲讲反流程混淆的工作,其实,反流程混淆就是从混淆中找到共同点,并对其进行重新整理,而混淆都有共同点,即使存在特殊情况,也可以用手工来辅助处理。混淆安全吗?你马上就可以知道结果。
赶时间之作,如有错误,请见谅。欢迎各位朋友进行讨论。