第27课 .net程序破解
.net程序破解主要使用的工具是.net Reflector。本教程所用的版本为4.2.43.0。
.net程序要想运行起来,系统必须装有.net Frame Work环境,目前有1.1和2.0两个版本。
有6种语言可供切换、选择。你可以选择你熟悉的编程语言。IL是中间语言,可读性差。但修改时要通过它来定位字节码,修改指令,最后通过16进制编辑器(ultraedit或winhex)来达成心愿。微软的Ildasm只能反汇编为IL语言,可读性差,因此,破解时不如.net Reflector好用。另外,IDA pro也是破解.net程序不错的工具。
Ildasm的使用参见附录1,IL语言中各函数的含义参见附录2,仔细研读,你就会熟悉il语言,破解起来游刃有余。
〔例1〕ForUIC
运行程序,如图:
就是弹出个窗口,说未注册
.net Reflector载入程序,如图:
目标程序总在最下方,像剥粽子一样的层层剥开。注意:其中,References不是我们关心的,不必展开。
双击Main程序,在右边可以看到代码,我选的是VB。如图:
你若稍微懂一点编程,很容易看懂。程序进行了一个比较,13和23比,不相等,因此,永远弹出注册失败。因此,有3种改法:
(1)13改为23
(2)23改为13
(3)num1不等于23,不相等则跳,bne改为beq
然后,切换到IL语言,代码如下:
.method public hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 2
.locals init (
[0] int32 num1)
L_0000: ldc.i4.s 13
L_0002: stloc.0
L_0003: ldloc.0
L_0004: ldc.i4.s 23
L_0006: bne.un.s L_001a
L_0008: ldstr "Registrato!"
L_000d: ldstr "Crackme"
L_0012: call [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string, string)
L_0017: pop
L_0018: br.s L_002a
L_001a: ldstr "Devi registrarmi! :-("
L_001f: ldstr "Crackme"
L_0024: call [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string, string)
L_0029: pop
L_002a: ret
}
光标停在 L_0000: ldc.i4.s 13显示指令1f 而13的16进制为0d
光标停在 L_0002: stloc.0 显示指令0a
用ILDasm察看,更加清晰。注意:“视图”菜单中,将“显示字节”打上对号,如图:
.method public hidebysig static void Main() cil managed
// SIG: 00 00 01
{
.entrypoint
// 方法在 RVA 0x2050 处开始
// 代码大小 43 (0x2b)
.maxstack 2
.locals init (int32 V_0)
IL_0000: /* 1F | 0D */ ldc.i4.s 13
IL_0002: /* 0A | */ stloc.0
IL_0003: /* 06 | */ ldloc.0
IL_0004: /* 1F | 17 */ ldc.i4.s 23
IL_0006: /* 33 | 12 */ bne.un.s IL_001a
IL_0008: /* 72 | (70)000001 */ ldstr "Registrato!"
IL_000d: /* 72 | (70)000019 */ ldstr "Crackme"
IL_0012: /* 28 | (0A)00000E */ call valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string,
string)
IL_0017: /* 26 | */ pop
IL_0018: /* 2B | 10 */ br.s IL_002a
IL_001a: /* 72 | (70)000029 */ ldstr "Devi registrarmi! :-("
IL_001f: /* 72 | (70)000019 */ ldstr "Crackme"
IL_0024: /* 28 | (0A)00000E */ call valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string,
string)
IL_0029: /* 26 | */ pop
IL_002a: /* 2A | */ ret
} // end of method crackme::Main
故ultraedit 打开程序,搜索1f0d0a,搜到后,将其中的0d即13,改为17即23即可。
运行修改后的程序,如图:
注册成功。
我们在此,尝试了第一种改法。其余两种改法作为作业,布置给大家,希望大家认真完成。
〔例2〕Dot_NET_ReverseMe_1.exe
这个比较简单,不详细写了。.net Reflector载入程序。
注意:其中,Resources和References不是我们关心的,不必展开。
btnCheck_Click是关键所在,双击:
Private Sub btnCheck_Click(ByVal sender As Object, ByVal e As EventArgs)
If (Not Me.txtSerial.Text Is "Dot_NET_Reversing_101_Is_Fun_For_All") Then
MessageBox.Show("Wrong !", "Error !!!!!!")
Else
MessageBox.Show("Right! Now onto the next step in Reversing, Byte-Patching", "Good Work!")
End If
End Sub
很容易可以看出,Dot_NET_Reversing_101_Is_Fun_For_All就是注册码,固定的明码。
〔例3〕SimpleCrackme.exe
这是一个dos窗口程序:
.net Reflector载入程序,语言切换为C#,如图:
双击Main(),在右边得到:
private static void Main(string[] args)
{
Console.WriteLine();
Console.WriteLine(" **************************************");
Console.WriteLine(" *** ***");
Console.WriteLine(" *** Simple crackme coded in C# ***");
Console.WriteLine(" *** written by ***");
Console.WriteLine(" *** Mattia Buccarella (active85k) ***");
Console.WriteLine(" *** www.active85k.da.ru ***");
Console.WriteLine(" *** ***");
Console.WriteLine(" **************************************");
Console.WriteLine();
Console.WriteLine();
Console.Write(" User name (at least six chars): ");
string text1 = Console.ReadLine();
Console.Write(" Serial N.: ");
string text2 = Console.ReadLine();
if (!Class1.IsSerialValid(text2))
{
Console.WriteLine(" Invalid serial.");
Console.WriteLine(" Try again.");
}
else
{
int num1 = text1.Length;
if (num1 < 6)
{
Console.WriteLine(" Your user name must be at least six!!");
}
else
{
int num2 = 1;
int num3 = 2;
for (int num4 = 0; num4 < num1; num4++)
{
num2 *= text1[num4];
num3 += (num2 * text1[num4]) + ((num4 + 1) * 2);
}
string text3 = string.Concat(new object[] { "", num2, "-", num3 });
if (text3.Equals(text2))
{
Console.WriteLine(" ! ! ! C O N G R A T U L A T I O N S ! ! !");
}
else
{
Console.WriteLine(" Invalid serial.");
Console.WriteLine(" Try again.");
}
}
}
}
如果,你稍微懂点C++语言,就可以看懂,源码在此。在Visual C++中稍微编译一下,注册机就出来了。
同样,作为作业布置给大家,希望大家认真完成。
〔例4〕ForUIC2
.net Reflector载入程序,语言仍选择VB,如图:
双击,来到右边:
Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim text1 As String = Me.textBox1.Text
Dim text2 As String = Me.textBox2.Text
Dim builder1 As New StringBuilder
Dim numArray1 As Integer() = New Integer(text1.Length - 1) {}
Dim num1 As Integer = 0
Do While (num1 < text1.Length)
numArray1(num1) = (text1.Chars(num1) Xor ChrW(2))
builder1.Append(numArray1(num1))
num1 += 1
Loop
If (Me.textBox2.Text Is builder1.ToString) Then
MessageBox.Show("Registrato! Bravo!", "Pbdz Crackme")
Else
MessageBox.Show("Codice sbagliato!!", "Pbdz Crackme")
End If
End Sub
注册算法很简单:逐个取姓名,ASCII码与2异或,连起来的十进制的数即为注册码。
例如:姓名输入ab
a的ASCII码为97,97异或2=99
b的ASCII码为98,98异或2=96
故注册码为9996
〔例5〕Dot_Net_ReverseMe_2
.net Reflector载入程序,语言仍选择VB,如图:
很容易定位到CheckReg(),双击,右边代码为:
Private Sub CheckReg()
If Me.IsRegistered Then
Me.lblMessage.Text = "Registered Well Done!"
Else
Me.lblMessage.Text = "Unregistered, get to work!"
End If
End Sub
Me.IsRegistered的值最关键,由上图下方知道,它是一个布尔值。我们需要找到给它赋值的地方。双击.ctor(),右边为:
Public Sub New()
Me.IsRegistered = False
Me.InitializeComponent
End Sub
切换语言为IL,代码如下:
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 2
L_0000: ldarg.0
L_0001: ldc.i4.0 修改为ldc.i4.1,查微软的MSDN可知,其字节为17
L_0002: stfld bool Dot_Net_ReverseMe_2.frmMain::IsRegistered
L_0007: ldarg.0
L_0008: call instance void [System.Windows.Forms]System.Windows.Forms.Form::.ctor()
L_000d: ldarg.0
L_000e: call instance void Dot_Net_ReverseMe_2.frmMain::InitializeComponent()
L_0013: ret
}
鼠标停在 L_0001: ldc.i4.0 行,看到ldc.i4.0指令的字节为16。同样地,确定上下的字节分别为02,7d。下面,ultraedit哥们该粉墨登场了。搜索02167d,定位,然后,将16改为17即可。
〔例6〕Dot_NET_ReverseMe_3.exe
.net Reflector载入程序,语言仍选择VB,如图:
双击,右边代码如下:
Private Sub frmReverseMeMain_Load(ByVal sender As Object, ByVal e As EventArgs)
Me.btnEnableMe2.Enabled = False ××××第2个按钮激活与否的特征值
MessageBox.Show("Unregistered - Get Rid Of Me!", "Nag Messagebox")
End Sub
切换语言为IL,代码如下:
.method private hidebysig instance void frmReverseMeMain_Load(object sender, [mscorlib]System.EventArgs e) cil managed
{
.maxstack 2
L_0000: ldarg.0
L_0001: ldfld [System.Windows.Forms]System.Windows.Forms.Button Dot_NET_ReverseMe_3.frmReverseMeMain::btnEnableMe2
L_0006: ldc.i4.0
L_0007: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Enabled(bool)
L_000c: ldstr "Unregistered - Get Rid Of Me!"
L_0011: ldstr "Nag Messagebox"
L_0016: call [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string, string)
L_001b: pop
L_001c: ret
}
由于字节码不容易确定。因此,用ILDasm打开目标程序,定位到这里:
.method private hidebysig instance void frmReverseMeMain_Load(object sender,
class [mscorlib]System.EventArgs e) cil managed
// SIG: 20 02 01 1C 12 15
{
// 方法在 RVA 0x2324 处开始
// 代码大小 29 (0x1d)
.maxstack 2
IL_0000: /* 02 | */ ldarg.0
IL_0001: /* 7B | (04)000002 */ ldfld class [System.Windows.Forms]System.Windows.Forms.Button Dot_NET_ReverseMe_3.frmReverseMeMain::btnEnableMe2
IL_0006: /* 16 | */ ldc.i4.0 将16改为17
IL_0007: /* 6F | (0A)000015 */ callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Enabled(bool)
IL_000c: /* 72 | (70)0000F1 */ ldstr "Unregistered - Get Rid Of Me!"
IL_0011: /* 72 | (70)00012D */ ldstr "Nag Messagebox"
IL_0016: /* 28 | (0A)00002F */ call valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string,
string)
IL_001b: /* 26 | */ pop
IL_001c: /* 2A | */ ret
} // end of method frmReverseMeMain::frmReverseMeMain_Load
Ultraedit打开程序,搜索027B02000004166F1500000A ,定位,将其中的16改为17。
即ldc.i4.0改为ldc.i4.1。则第二个按钮被激活。
常用的去掉消息框的方法:将IL_000c 开始直到IL_001b为止的代码全部nop掉,即可去掉第一个nag消息框。注意:nop在.net程序中,不是90,而是00。即以上红颜色的代码,ultaredit中修改即可。
接下来还有两个任务需要解决:激活第1个按钮,去掉第2个nag窗口。
双击,右边代码中,定位这里:
Me.btnEnableMe1.Enabled = False ××××第1个按钮激活与否的特征值
Me.btnEnableMe1.FlatStyle = FlatStyle.Flat
Me.btnEnableMe1.Location = New Point(8, 8)
Me.btnEnableMe1.Name = "btnEnableMe1"
Me.btnEnableMe1.Size = New Size(272, 32)
Me.btnEnableMe1.TabIndex = 0
为方便定位代码位置,以利于今后的修改,我们用IDA Pro打开程序,记得选择 .net 程序。
可见,代码位于10ED处,ultraedit打开程序,ctrl+G,输入0x10ed,如图:
定位,将其中的16改为17。
即ldc.i4.0改为ldc.i4.1。则第1个按钮被激活。
Private Sub t_Tick(ByVal sender As Object, ByVal e As EventArgs)
New Nag.Show
Me.t.Stop
End Sub
双击,右边关键代码如下:
Me.t.Enabled = True
Me.t.Interval = 1000
AddHandler Me.t.Tick, New EventHandler(AddressOf Me.t_Tick)
Me.btnAbout.FlatStyle = FlatStyle.Flat
为方便定位代码位置,以利于今后的修改,我们用IDA Pro打开程序,记得选择 .net 程序。
可见,代码位于11BC处,ultraedit打开程序,ctrl+G,输入0x11bc,如图:
定位,将其中的17改为16。
即ldc.i4.1改为ldc.i4.0。则第2个NAG窗口被消除。
成功后的界面如下: