• 标 题:【原创】GMSI.NET的注册破解——.Net程序破解的一个例子
  • 作 者:银河水
  • 时 间:2004-12-15,20:15
  • 链 接:http://bbs.pediy.com

【破解作者】 银河水
【作者邮箱】 galaxy_water@163.com;galaxywater@126.com
【作者主页】 http://milkyway.ys168.com
【使用工具】 ildasm 
【破解平台】 Windows XP
【软件名称】 GMSI.NET Instruments v1.1 released
【下载地址】 http://www.3dlinx.com/downloads/instruments/dotNet/GMSNETInstrumentLibrary.zip
【软件简介】The Instrumentation .NET Library (INL) features a bundle of seven common instrumentation interface components including Alpha-Numeric LED, Angular Gauge, Knob, LED, Linear Gauge, Odometer, and Toggle. Together these components provide developers with an economical, powerful set of tools for control interfaces and data display in technical applications.
  以上是这个软件的原文简介,其实它就是一大堆控件,可以做出非常漂亮的仪表,信号灯,开关,按钮等,可以和真实的相媲美,就说这么多了,关心的自己下载下去看看吧。
【破解声明】 本破解纯属以学习为目的,偶得一点心得,愿与大家分享。另外此控件要在Visual Studio .Net 2003下才可以正常使用,还有本文提供的注册机(在我的主页上可以下载),也要求在安装了.net框架程序的系统下才可以运行。
【破解内容】
  背景知识介绍:首先,我们遇到的是一个全新的东西,.NET框架,这个东西是什么呢,他怎么工作的,如果你用WIN32DASM反汇编一下这个程序,你会看到莫名其妙的代码,因为它不再是我们传统意义上的汇编代码了,它是.NET的核心也就是MSIL语言,IL全称是INTERMEDIATE LANGUAGE,也就是一种中间语言,类似PCODE,但这回所有的编程语言包括VB,VC,C#全都编译成MSIL然后再利用.NET框架的JIT实时转译成本地机的可执行代码,从而实现了平台无关性,于是我们要破解这类程序就要找到一种类似PCODE反编译器的东西,很幸运的是微软大叔为我们提供了全套超强绿色套装:)对我们最有用的就是ILDASM(这些东西在.NET FRAMEWORK SDK中提供) 
  想了解关于.net开发程序的破解请去看windcbf的《.Net环境下的程序破解》。
    好了基本的东西知道了一点,现在开始就要了解这种语言了,当然微软的MSDN有所有你想知道的东西,所以我这里就不罗索了,你可以去看看他的教程,我就来讲讲具体的破解,这才是我等感兴趣的:)
  首先用ILDASM把源程序载入,很快我们得到了反编译的代码,你看到的是一种树状的结构图:
 

很清晰的结构,完全采用类的结构,但是可能是开发者的编程习惯不太好,名字起的不太好,这里面有一个类,那么注册函数就在这个类里面了,由于名子不好,所以只能一个一个查看了,双击每一个方法,就会看到他们内部的东而了,自己去分析吧,很简单的,最后可以确定A:void(object,class[mscorlib]System.EventArgs是我们要找的。他的几个方法也是一看就明白做什么用的,关键就在它里面代码的含义,就是msil语言究竟是怎么样的。我们从它入手。 
所有的misl语言都基于CLR(公共语言运行库),CLR 是.NET 框架应用程序的执行引擎,它有别于传统的CPU结构,传统的CPU执行依赖于寄存器和堆栈,而CLR只使用堆栈,所以你所看到的MSIL语言都是下面的形式: 
ld.... 
ld.... 
语句(call,比较。。) 

实际上类似于 

push 
push 
call 

也就是说全都是这样的函数,方法调用。

 
从这个图中我们可以看到一共有四个参数,其中三个是用来Product,和Order ID是我们提供给程序的,而Computer ID是程序自己参生的,有了这个认识我们来分析上面我们找到的那个函数。
.method private hidebysig instance void  A(object A_1, class [mscorlib]System.EventArgs A_2) cil managed  //方法的名称
{
  // Code size       271 (0x10f)      //代码的大小
  .maxstack  3            //最大的堆栈数
  .locals init (string V_0,        //参数      
           string V_1,
           string V_2,
           string V_3,
           unsigned int32 V_4,
           string V_5,
           unsigned int32 V_6,
           string V_7,
           class [mscorlib]Microsoft.Win32.RegistryKey V_8)
  IL_0000:  ldarg.0
  IL_0001:  ldflda     unsigned int32 A.A::A
  IL_0006:  call       instance string [mscorlib]System.UInt32::ToString()      //程序自动得到的Computer ID
  IL_000b:  stloc.0                            //放到V_0中,V_0是即是Computer ID的值
  IL_000c:  ldarg.0
  IL_000d:  ldfld      class [System.Windows.Forms]System.Windows.Forms.TextBox A.A::a
  IL_0012:  callvirt   instance string [System.Windows.Forms]System.Windows.Forms.Control::get_Text()
  IL_0017:  stloc.1      //上面两行还有这行是得到Order ID的值,是从TextBox中得到的,放到V_1中
  IL_0018:  ldarg.0
  IL_0019:  ldfld      class [System.Windows.Forms]System.Windows.Forms.ComboBox A.A::A
  IL_001e:  callvirt   instance string [System.Windows.Forms]System.Windows.Forms.Control::get_Text()
  IL_0023:  stloc.2      //上面两得还有这行是得到Product的内容,是从ComboBox是得到的,放到V_2中
  IL_0024:  ldloc.1      //将索引 1 处的局部变量加载到计算堆栈上
  IL_0025:  ldloc.0      //将索引 0 处的局部变量加载到计算堆栈上
  IL_0026:  ldloc.2      //将索引 2 处的局部变量加载到计算堆栈上
  IL_0027:  call       string [mscorlib]System.String::Concat(string, string, string)
              //上面这个函数非常明白了吧,是堆栈三个字符串连接,顺序是Order ID,Computer ID,Product
  IL_002c:  stloc.3      //将值从堆栈中弹出到局部变量 3 中,即V_3中,里面是三个字符串连接成的字符串
  IL_002d:  ldloc.3
  IL_002e:  callvirt   instance int32 [mscorlib]System.String::GetHashCode()   //求V_3的哈希代码
  IL_0033:  stloc.s    V_4                      //放到V_4中,V_4中就是V_3的哈希代码
  IL_0035:  ldarg.0
  IL_0036:  ldfld      class [System.Windows.Forms]System.Windows.Forms.TextBox A.A::A
  IL_003b:  callvirt   instance string [System.Windows.Forms]System.Windows.Forms.Control::get_Text()
  IL_0040:  stloc.s    V_5    //这三行是得到用户输入的Key Code的值,是从TextBox中得到的,放到V_5中
  IL_0042:  ldloc.s    V_5
  IL_0044:  ldstr      "-80001"  //这个值比较有意思,输入他到Key Code中可以删除所有的注册信息
  IL_0049:  call       bool [mscorlib]System.String::op_Equality(string,
                                                                 string)
  IL_004e:  brfalse.s  IL_006d
  IL_0050:  ldsfld     class [mscorlib]Microsoft.Win32.RegistryKey [mscorlib]Microsoft.Win32.Registry::LocalMachine
  IL_0055:  ldarg.0
  IL_0056:  ldfld      string A.A::A
  IL_005b:  callvirt   instance void [mscorlib]Microsoft.Win32.RegistryKey::DeleteSubKeyTree(string)
  IL_0060:  ldarg.0
  IL_0061:  ldstr      "Removed Instruments.Net Keys"  
  IL_0066:  call       valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(class [System.Windows.Forms]System.Windows.Forms.IWin32Window, string)
    //上面这段程序,就是在输入”-80001”这个值时删除注册信息用的,并有一个Removed Instruments.Net Keys窗口弹出
  IL_006b:  pop
  IL_006c:  ret
  IL_006d:  ldc.i4.0
  IL_006e:  stloc.s    V_6
  .try
  {
    IL_0070:  ldloc.s    V_5
    IL_0072:  call       unsigned int32 [mscorlib]System.UInt32::Parse(string)    
    IL_0077:  stloc.s    V_6    //这三行是把字符型的V_5就是用户输入的Key Code转换成整型并放在V_6中
    IL_0079:  leave.s    IL_0081
  }  // end .try
  catch [mscorlib]System.Object 
  {
    IL_007b:  pop
    IL_007c:  ldc.i4.0
    IL_007d:  stloc.s    V_6
    IL_007f:  leave.s    IL_0081
  }  // end handler
  IL_0081:  ldloc.s    V_6
  IL_0083:  ldloc.s    V_4
  IL_0085:  bne.un.s   IL_0102              //就是从这里跳到注册失败的地方去的,关键地方找到了,这是比较V_6和V_4如果不等,就跳到注册失败的地方去,很显然,如果相等,那么我们就注册成功了。分析一下,V_6中现在是用户输入的Key Code,而用V_4和他比较,那么就是说V_4就是真正的注册码了,好了,现在回顾一下V_4是怎么来的,它是V_3的哈希代码,而V_3是Order ID的值,Computer ID的值,Product的值三个字符串相连,结果出来了,注册码就是三个参数的字符型相连所得字符串哈希代码,记得三个字符串的顺序是Order ID,Computer ID,Product

  IL_0087:  ldarg.0                  //从这里向下没什么好研究的了,都是一些注册表的操作
  IL_0088:  ldfld      string A.A::A
  IL_008d:  ldloc.2
  IL_008e:  call       string [mscorlib]System.String::Concat(string,
                                                              string)
  IL_0093:  stloc.s    V_7
  IL_0095:  ldsfld     class [mscorlib]Microsoft.Win32.RegistryKey [mscorlib]Microsoft.Win32.Registry::LocalMachine
  IL_009a:  ldloc.s    V_7
  IL_009c:  ldc.i4.1
  IL_009d:  callvirt   instance class [mscorlib]Microsoft.Win32.RegistryKey [mscorlib]Microsoft.Win32.RegistryKey::OpenSubKey(string,
                                                                                                                              bool)
  IL_00a2:  stloc.s    V_8
  IL_00a4:  ldloc.s    V_8
  IL_00a6:  brtrue.s   IL_00d3
  IL_00a8:  ldsfld     class [mscorlib]Microsoft.Win32.RegistryKey [mscorlib]Microsoft.Win32.Registry::LocalMachine
  IL_00ad:  ldloc.s    V_7
  IL_00af:  callvirt   instance class [mscorlib]Microsoft.Win32.RegistryKey [mscorlib]Microsoft.Win32.RegistryKey::CreateSubKey(string)
  IL_00b4:  stloc.s    V_8
  IL_00b6:  ldloc.s    V_8
  IL_00b8:  ldstr      "CustomerID"
  IL_00bd:  ldloc.1
  IL_00be:  callvirt   instance void [mscorlib]Microsoft.Win32.RegistryKey::SetValue(string,
                                                                                     object)
  IL_00c3:  ldloc.s    V_8
  IL_00c5:  ldstr      "KeyCode"
  IL_00ca:  ldloc.s    V_5        
  IL_00cc:  callvirt   instance void [mscorlib]Microsoft.Win32.RegistryKey::SetValue(string,
                                                                                     object)
  IL_00d1:  br.s       IL_00f5
  IL_00d3:  ldloc.s    V_8
  IL_00d5:  ldstr      "CustomerID"
  IL_00da:  ldloc.1
  IL_00db:  callvirt   instance void [mscorlib]Microsoft.Win32.RegistryKey::SetValue(string,
                                                                                     object)
  IL_00e0:  ldloc.s    V_8
  IL_00e2:  ldstr      "KeyCode"
  IL_00e7:  ldloc.s    V_5
  IL_00e9:  callvirt   instance void [mscorlib]Microsoft.Win32.RegistryKey::SetValue(string,
                                                                                     object)
  IL_00ee:  ldloc.s    V_8
  IL_00f0:  callvirt   instance void [mscorlib]Microsoft.Win32.RegistryKey::Close()
  IL_00f5:  ldarg.0
  IL_00f6:  ldstr      "Registration Succeeded"          //这里是注册成功
  IL_00fb:  call       valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(class [System.Windows.Forms]System.Windows.Forms.IWin32Window,
                                                                                                                                                     string)
  IL_0100:  pop
  IL_0101:  ret                        //这里有返回
  IL_0102:  ldarg.0                      //一定有跳到这的,注册失败的时候跳到这,向上找
  IL_0103:  ldstr      "Registration Failed"            //看到了吧,这就是注册失败的地方
  IL_0108:  call       valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(class [System.Windows.Forms]System.Windows.Forms.IWin32Window,
                                                                                                                                                     string)
  IL_010d:  pop
  IL_010e:  ret
} // end of method A::A


【破解总结】
  怎么样,简单吧,这个程序不适用于爆破,原因,是每次程序向注册表中写的都是用户输入的东西,所以在用控件的时候,控件自身验证总是不正确的注册码,所以就有问题了,而想把V_4代替V_5却有数据类型转换的问题,也是一件很麻烦的事情。注册机已经做成,是用C#编的,原因无它,可以直接借用GetHashCode()这个函数。写的不是很细致,有不明白的语句,去查Visual Studio.net 2003带的MSDN吧。
【算法注册机】
总结一下用C#源码描述如下:
      string str1,str2,str3,str4;
      int hash;

      str1 = textBox1.Text;          //得到Product
      str2 = textBox2.Text;          //得到Computer ID
      str3 = textBox3.Text;          //得到Order ID

      str4 = string.Concat(str3, str2, str1);  //连接三个字符串
      hash = str4.GetHashCode();        //得到连接好的字符串的哈希代码,即注册码

【版权声明】 本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢!