-
-
[原创]初摸dotnet(简析logkiller丢的两个老外的dotnet CM)
-
发表于:
2010-4-7 23:29
6749
-
[原创]初摸dotnet(简析logkiller丢的两个老外的dotnet CM)
【文章标题】 初摸dotnet
【文章作者】 GoodGavin
【作者邮箱】 gavin_soung@163.com
【使用工具】 Reflector, ildasm2.0, UltraEdit, ILASM
【破解平台】 WindowsXP
【软件名称】 2keygen_me.rar
【下载地址】 http://bbs.pediy.com/showthread.php?t=109837
【软件简介】 dotnet程序
【加壳方式】 无
【作者声明】 dotnet没怎么弄过,看这两个CM简单,也没什么人玩,娱乐下,做个笔记,
也给初次接触dotnet的朋友入入门
--------------------------------------------------------------------------------
【详细过程】
先介绍一下工具的作用:
Reflector: 可以将未混淆的程序反编译成各种语言,方便阅读代码(如果可以轻松读懂IL代码的话,这个两个CM可以不用他)
ildasm2.0: 将dotnet程序导出为IL文件(dotnet的中间文件)
UltraEdit: 修改ildasm生成的IL文件
ILASM: 将修改后的IL文件在编译成exe程序, 命令格式:ilasm /resource=cm.res cm.il
好了,Let's go!
/*****************************************************************************************/
keygenMe: easy_Keygne Me - Sadiqhirani.exe
/*****************************************************************************************/
先用Reflector打开程序,之前已经打开了系统的一些东西了哦,提前观察一下,不要找不到自己的CM,哈哈
我这里系统的东西有:mscorlib,System,System.Xml,System.Web,System.Drawing,System.Windows.Forms等等,
好了先找按钮事件,在
private void button1_Click(object sender, EventArgs e)
{
if (this.code(Encoding.Unicode.GetBytes(this.textBox1.Text), this.textBox2.Text))
{
this.p3();
}
else
{
this.p2();
}
}
好,他调用了this.code,code就应该是写了关键代码的函数了吧,哈哈,
看看他(这代码多好读,如果是IL的话对我们这样的初学者就要费尽多了)
public bool code(byte[] c1, string c2)
{
string str = "";
foreach (byte num in c1)
{
short num2 = this.ys(num);
str = str + Convert.ToString((int) num2);
}
if (((c2 != str) || (str.Length < 10)) || (c1.Length < 4))
{
return false;
}
return true;
}
他还调用了ys:
public short ys(byte g)
{
string str = @"9TYU63257jJHGklL:{]qQW;.<KpERfcv[}'/,>FDSgh=+\_|oiuytrew^$-IOP`~!#NBVCXZAa%)*(&@?bnmMsd8410zx";
char ch = Strings.ChrW(g);
if (g == 0)
{
return 0;
}
return (short) str.ToString().IndexOf(ch);
}
给两组组简单的key吧:
name: 9999999999
serial: 00000000000000000000
name: YYYYYYYYYY
serial: 20202020202020202020
简单说下算法:(没用.net写过程序,函数的意思也就是猜的了。)
程序将name转换为Unicode编码:Encoding.Unicode.GetBytes
然后每一位的name在一个给定的字符串中查找index:this.ys(num)
将的到的index转换为string然后连成字符串作为serial
输入有个最小长度的限制:(str.Length<10: name转换后的字符串必须大于等于10;c1.Length<4:name必须大于等于4)
需要注意的是Unicode编码用0-0x10FFFF范围的数字来映射编码,一个Unicode编码包括两个byte,高位是0
if (g == 0){return 0;} 大概就是针对Unicode的处理。
现在考虑爆破:
1、用ildasm2.0打开程序,在button1_Click函数中找到如下代码(看了上面的的c#代码,在看下面的IL代码应该没问题了):
IL_002e: brtrue.s IL_003b //改为: brfalse.s IL_003b 应该就算爆破了
IL_0030: nop
IL_0031: ldarg.0
IL_0032: call instance void WindowsApplication1.Form1::p3()
IL_0037: nop
IL_0038: nop
IL_0039: br.s IL_0044
IL_003b: nop
IL_003c: ldarg.0
IL_003d: call instance void WindowsApplication1.Form1::p2()
IL_0042: nop
IL_0043: nop
IL_0044: ret
2、选择文件菜单,转存(dump),dump为il文件了(没有第一步也可以,直接转存任何在il文件里找关键代码)
3、用UntraEdit打开程序,找到上面的代码,brtrue.s 改为 brfalse.s
(不能改为br,虽然可以编译成功,但程序会出错,没想通为什么)
4、用ilasm编译修改好的il文件,格式:ilasm /resource=cm.res cm.il
这个CM算是解决了。
/*****************************************************************************************/
keygenMe: keygenme-sadiqhirani.exe
/*****************************************************************************************/
这个CM要求必须输入name和serial,并且serial必须是24位的(123456789012345678901234)
如果我没理解错的话这个程序给不出serial,似乎他给出SHA1值,让我们给字符串(也不知道理解的对不对,没用过dotnet)
那只好爆破了。
if (registration.ValidRegKey(regkey))对应的IL代码是:
IL_0056: stloc.1
IL_0057: ldloc.0
IL_0058: ldarg.2
IL_0059: callvirt instance bool keygenme_sadiqhirani.Form1/Registration::ValidRegKey(string)
IL_005e: ldc.i4.0
IL_005f: ceq
IL_0061: stloc.s V_8
IL_0063: ldloc.s V_8
IL_0065: brtrue IL_0170 // 改为brfalse就爆了
即便是正确的serial这个错误提示也会出现,估计是个bug吧,把他nop掉,注意:
1、最后一个pop也要nop掉,不然堆栈不平衡,程序就出错了
2、nop的数量也必须够哦(11个nop替换如下代码)
IL_017d: ldstr "Wrong Serial"
IL_0182: call valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string)
IL_0187: pop
public void Register(string name, string regkey)
{
try
{
if (name.Length == 0) // name 只此一处判断,再没有被用
{
MessageBox.Show("wrong Serial");
}
else if (regkey.Length != 0x18) // 长度要求24位
{
MessageBox.Show("wrong Serial");
}
else
{
Registration registration = new Registration();
DateTime date = registration.GetDate(regkey);
// 这个函数的成败直接决定了程序的成功与否,他是用类实现的
// 但是如果我没理解错的话,他是给出SHA1值,然后让我们给出字符串(SHA1不是还安全着么?)
// 也许是我理解错了?
// HashAlgorithm algorithm = new SHA1CryptoServiceProvider();
// byte[] bytes = Encoding.UTF8.GetBytes(key);
// byte[] buffer2 = algorithm.ComputeHash(bytes);
if (registration.ValidRegKey(regkey))
{
string[] hashCodes = registration.GetHashCodes(regkey);
if (hashCodes == null)
{
MessageBox.Show("wrong Serial");
}
else
{
string str = "";
string[] strArray2 = registration.GetHash(Environment.MachineName).Split(new char[] { '-' });
string[] strArray3 = hashCodes[0].Split(new char[] { '-' });
string[] strArray4 = hashCodes[1].Split(new char[] { '-' });
for (int i = 0; i < strArray2.Length; i++)
{
str = str + ((i == 0) ? strArray2[i] : ("-" + strArray2[i])) + "-" + strArray3[i] + "-" + strArray4[i];
}
MessageBox.Show("Correct Serial");
}
}
else
{
MessageBox.Show("Wrong Serial");
}
// 这个对话框即便注册码对也会弹出嘛!
MessageBox.Show("Wrong Serial");
}
}
catch
{
MessageBox.Show("Wrong Serial");
}
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)