.NET Reactor 是個好東西,只不過這家伙升級的速度非常快,加密算法經常變化,而且越來越厲害,實在懶得 "跟" 了。這類工具通常在 "殼" 上做了大量的工作,諸如什么 JIT Hook、native loader 之類的。而我通常只使用它的混淆功能,所以用另外一種方法 "繞" 過去,即便不注冊,也可以使用最新版本。
首先,我們准備一個簡單一點的 DLL,用於分析 .NET Reactor 混淆后的限制。test.dll
namespace MyLibrary
{
public class MyClass
{
public void Test()
{
Console.WriteLine("MyClass.Test...");
}
}
}
namespace MyLibrary.Test
{
public class MyClass2
{
public void TestXXX()
{
Console.WriteLine("MyClass2.Test...");
}
}
}
我們使用 .NET Reactor 對該 DLL 進行混淆后,調用時會出現如下提示。

OK! 接下來,我們把這個東西給去掉。
打開 Reflector,我們會發現每個 .cctor 中都增加了如下代碼 (可能不同加密結果名稱有所不同)。
.method private hidebysig specialname rtspecialname static void .cctor() cil managed
{
.maxstack 8
L_0000: call void <PrivateImplementationDetails>{B4838DC1-AC79-43d1-949F-41B518B904A8}::CS$0$0006()
L_0005: ret
}
很顯然,<PrivateImplementationDetails>{B4838DC1-AC79-43d1-949F-41B518B904A8} 類型是 .NET Reactor 注入進去的,順藤摸瓜進入 CS$0$0006()。
.method assembly hidebysig static void CS$0$0006() cil managed
{
.maxstack 8
L_0000: br L_0007
L_0005: pop
L_0006: ldc.i4.0
L_0007: ldsfld bool <PrivateImplementationDetails>{B4838DC1-AC79-43d1-949F-41B518B904A8}::CS$0$0004
L_000c: brtrue.s L_002f
L_000e: ldc.i4.1
L_000f: stsfld bool <PrivateImplementationDetails>{B4838DC1-AC79-43d1-949F-41B518B904A8}::CS$0$0004
L_0014: ldstr "This assembly is protected by an unregistered version of \".NET Reactor\". Copyright @ Eziriz, www.eziriz.com"
L_0019: ldstr "Lock System"
L_001e: call valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult
[System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string, string)
L_0023: pop
L_0024: leave L_002f
L_0029: pop
L_002a: leave L_002f
L_002f: ret
.try L_0014 to L_0029 catch object handler L_0029 to L_002f
}
那行字符串符合我們通緝目標的特征,接下來怎么做?當然是把這個方法內部代碼刪除掉了。(如果你願意,也可以將所有 .cctor 中的那行代碼給批量替換掉)
d:\temp> ildasm test.dll /out=test.il
Protected module -- cannot disassemble
不好意思,Suppress ILDASM 是最基本的手段。我們換一個 ILDASM.exe (可從網上找該修改版本,剔除了 SuppressIldasmAttribute 特性限制)。
d:\temp> d:\program\tools\ILDasm\ILDasm.exe test.dll /out=test.il
// WARNING: Created Win32 resource file test.res
打開編輯器,搜索 CS$0$0006,然后將該方法體刪除,只保留 ret。(如果有 publickey,注意刪除)
.method assembly hidebysig static void CS$0$0006() cil managed
{
.maxstack 8
ret
}
保存,重新編譯該 IL 代碼 (如果有 Public Key,注意使用 /key=...)。
d:\temp> ilasm /dll test.il /out=test2.dll
...
Emitting fields and methods:
Global Methods: 1;
Class 1 Fields: 4; Methods: 8;
Class 2 Methods: 3;
Class 3 Methods: 3;
Resolving local member refs: 9 -> 9 defs, 0 refs, 0 unresolved
Emitting events and properties:
Global
Class 1
Class 2
Class 3
Resolving local member refs: 0 -> 0 defs, 0 refs, 0 unresolved
Writing PE file
Signing file with strong name
Operation completed successfully
我們試試這個 test2.dll,那個討厭的對話框已經消失了,不見了……
結束了?等等……
我們給 MyClass2 添加一個私有方法。
namespace MyLibrary.Test
{
public class MyClass2
{
public void TestXXX()
{
Test2();
}
private void Test2()
{
Console.WriteLine("MyClass2 Private Test...");
}
}
}
用 .NET Reactor 混淆后,可能你會發現上面寫的那個 <PrivateImplementationDetails>{B4838DC1-AC79-43d1-949F-41B518B904A8} 不見了,.cctor 里面也沒有注入額外的代碼。所不同的是出現了一個名字古里古怪的家伙,就像下面這樣。
.namespace AKEtMeX)o
{
.class private auto ansi beforefieldinit AAxshPnXX
extends [mscorlib]System.Object
{
.method private hidebysig specialname rtspecialname static void .cctor() cil managed
{
}
.method assembly hidebysig static pinvokeimpl("nr_native_lib.dll" as "nr_nli" ansi winapi) bool AAxshPnXX(string marshal(bstr), int32) cil managed preservesig
{
}
.method assembly hidebysig static pinvokeimpl("Learn.Library_nat.dll" as "nr_nli" ansi winapi) bool ABy2LSAxY(string marshal(bstr), int32) cil managed preservesig
{
}
.method assembly hidebysig static pinvokeimpl("Learn.Library_nat.dll" as "nr_startup" ansi winapi) void ACiuCWtbY(string marshal(bstr)) cil managed preservesig
{
}
.method assembly hidebysig static void ADxAfYIbq() cil managed
{
}
.method assembly hidebysig static void AER(Ib2WO(bool) cil managed
{
}
.method assembly hidebysig static string AFxcDdVK8(string) cil managed
{
}
.method assembly hidebysig static string AGEdqxnDQ(string) cil managed
{
}
.method assembly hidebysig static void AHrgRGDAh() cil managed
{
}
.method assembly hidebysig static int32 AI0mY6Kel() cil managed
{
}
.method assembly hidebysig static object AJM2IfMnl() cil managed
{
}
.method assembly hidebysig static void AKEtMeX)o() cil managed
{
}
.method assembly hidebysig static void ALJw(16JK() cil managed
{
}
.field private static bool AAxshPnXX
.field private static bool ABy2LSAxY
.field private static bool ACiuCWtbY
.field private static bool ADxAfYIbq
}
}
我們翻看其內部方法,很顯然下面這個就是我們要修改的目標。
.method assembly hidebysig static void AHrgRGDAh() cil managed
{
.maxstack 4
L_0000: br L_0007
L_0005: pop
L_0006: ldc.i4.0
L_0007: ldsfld bool AKEtMeX)o.AAxshPnXX::AAxshPnXX
L_000c: brtrue.s L_002f
L_000e: ldc.i4.1
L_000f: stsfld bool AKEtMeX)o.AAxshPnXX::AAxshPnXX
L_0014: ldstr ""
L_0019: ldstr "Lock System"
L_001e: call valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult
[System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string, string)
L_0023: pop
L_0024: leave L_002f
L_0029: pop
L_002a: leave L_002f
L_002f: ret
.try L_0014 to L_0029 catch object handler L_0029 to L_002f
}
至於后面怎么做,無需我多言了。(其實在這個例子中,根本沒有調用該方法,也就是說不會出現彈出框……)
-------------------------------
附:如果你希望加密 EXE,那么還是老老實實進行脫殼,然后修復,再然后……
