记录一次.net项目的破解过程

来源:互联网 发布:淘宝企业店铺运营方案 编辑:程序博客网 时间:2024/04/30 13:13

声明:本CSDN博客中的所有文章均为本人原创 请勿转载    

 

注意:本次演示破解了一个当前网络的商业项目,请务必遵守互联网及软件版权的相关规定。不要对原公司造成侵权,及利益上的侵害。

同时,我也无意侵犯该商业项目的相关权益。下面的内容仅供学习交流。

 


[如何破解]

破解一个软件,最强大,最直接,最让人情有独钟的非调试莫属。不管怎样,调试方式几乎像一把软件的解剖刀。无所不能。通过调试,能够窥探加密,为程序去壳,解密口令,修改源码,这些关键的操作在许多强大的工具支持下其实并不困难,一些很著名的工具可以帮助我们轻松完成。微软也提供了一些调试工具,如winDbg,虽然它可能不是最强大的,但却是最适应于windows调试的工具。

 

软件的加密,加壳,证书等手段都是人们总结的能够抵制破解的一些方法。正如人们所说,没有一个软件是完美的,也没有一个软件是不能被破解的。

这次演示中并不打算使用调试,而是一种类似测试中的“白盒”形式来分析并提出方案。专业的建议使用调试。

下面简单聊几句.net的基础知识,这些是我们使用.net的基础。

作为.net应用程序,它依赖于.netCLR运行,CLR(公共语言运行时)是.net平台的核心,它管理了一个内存区,将其称为托管堆。所以许多人称.net程序为托管应用程序。一般WIN32等程序使用的内存分配直接由操作系统管理,即存储在操作系统的分配的堆栈上。但.net内存由CRL管理。因此,当应用层发生异常时,将不会直接抛向操作系统,而是首先由CLR接管并处理。CLR自身很难出现异常。所以,这样的程序在一定程度上是安全的。CRL内驻留的一个GC(垃圾回收)进程来专门负责对象的回收任务。GC的出现降低了程序开发人员的内存管理负担,同时在一定程度上防止了疏忽造成的内存泄露。

CLR类似于一个虚拟CPU,只不过它面向的数据不是进制码,而是MSILMSIL(简称IL),是微软创建的一种中间语言。微软的.net平台的语言无关性就是靠它来体现。在NET平台上,你可以使用多种语言进行开发,最终,将被编译为同一种MSIL语言。你可以将其看做一种低级的类似Win32/64汇编的语言。一句话,.net编译生成的文件exe,Dll等,都是以MSIL码存储的。它只有在运行时才会被JIT即时译为适应于目标机器CPU的语言。而不像CC++等是直接的机器语言。事实上如JAVA等有平台虚拟机的程序框架都具有如此的特征。JAVA就是被译为JVM可执行的字节码存放。这样的好处是跨平台能力增强。并且具备了一次编译多次运行的较强移植能力。

 

上面的基础应该足够了,回到正题,我们要破解一个软件,在不通过调试时似乎理解源码是至关重要的,因为我们需要知道软件中在哪些地方进行了限制。但没有源码,就必须有一定的低层知识。由一些MFCWIN32等直接生成的文件已经成了二进制代码,经过了一系列的链接,和优化,已经和源代码相去甚远了,你可以使用如UltraEdit的工具直接查看甚至修改二进制文件,但这几乎不可行,不过你可以反汇编,汇编语言要好理解多了,想返回源码的想法在Win32/64下最好打消。但在.net下却可以很好的还原到一定的程度。汇编你可能也不太熟悉,但.net生成的是MSIL,所以,我们只需要看MSIL。和汇编一样,MSIL也是由一些助记符构成的,这些指令的含意,你可以在微软的相关技术文档上查阅。我就在此不多延伸。

既然我们看到的DLL都是MSIL,那么我们可以通过VS下的工具箱中的IL DASM来查看MSILIL DASM IL ASM工具都是微软提供的比较基础和强大的反IL工具。

 

[寻找突破口]

 从演示项目中找到可能使用证书的页面或者事件,逐渐排除一些无关的业务逻辑。首先我们登陆系统。可以发现,当前系统没有注册。

 

其次找到验证的入口,点击“未授权网站”铵钮。打开如下页面:


可以看到,底部有一个上传证书的文本框。根据WEB程序的特点。这些处理全部集中在下面“确认提交”这个事件中完成的。单击右键-》属性,可以看到该页面的名称,然后在VS项目下找到该页面。但我们从原页面程序中并没有看到该事件的处理函数。Asp.net的机制是后台与页面相分离,通过页面指令来关联后台文件,所以,使用VS环境寻找并打开这一页面源码,可以看到后台地址的映射:

 

可以看到,后台程序放在了ShopWe 空间下的Admin_ShopWeCert类。

这个名为ShopWeDLLBin目录下。

 

 

[顺藤摸瓜 寻找相应的工作模块]

既然锁定了入口的DLL,我们便可以使用VS提供的IL DASM工具反射原程序集,我不想在此说反射是多么强大的一种工具,这全归功于元数据集。

程序-SDK-》工具,打开DASM,然后选择“文件”=-》选择SHOPWE ,即可打开该DLL,如下图所示。


上面清楚的列举了当前模块中的类,方法,字段和属性,还有版本等信息。

对于右侧的三角符号,正方形的含义不清楚的,可以查下IL DASM的用法中有介绍。

蓝色的“集成快”表示类,“集成块”中间有I标识的是接口,向右红三角表示版本,元数据信息,平行四边形表示字段,向上红三角表示属性,正方形是方法。带S的是静态方法。

如果不清楚,请单击IL DSAM 帮助菜单。或者查找 该工具用法。

 

在页面的提交事件中,我们已经看到,该事件的处理函数为Submit_Click

 

 

双击列表中的Submit_Click方法以查看MSIL代码。下面是该方法的MSIL码:

.method family hidebysig instance void  Submit_Click(object sender,

                                                     class [mscorlib]System.EventArgs e) cil managed

{

  // 代码大小       250 (0xfa)

  .maxstack  5

  .locals init (class [Common]ShopWe.Common.XMLControl V_0)

  IL_0000:  ldarg.0

  IL_0001:  ldfld      class [System.Web]System.Web.UI.WebControls.FileUpload Admin_WebSetting_Cert::UploadCert

  IL_0006:  callvirt   instance bool [System.Web]System.Web.UI.WebControls.FileUpload::get_HasFile()

  IL_000b:  brfalse.s  IL_0031

  IL_000d:  br         IL_00d9

  IL_0012:  ret

  IL_0013:  ldarg.0

  IL_0014:  ldfld      class [System.Web]System.Web.UI.HtmlControls.HtmlInputText Admin_WebSetting_Cert::cert

  IL_0019:  callvirt   instance string [System.Web]System.Web.UI.HtmlControls.HtmlInputControl::get_Value()

  IL_001e:  ldsfld     string [mscorlib]System.String::Empty

  IL_0023:  call       bool [mscorlib]System.String::op_Inequality(string,

                                                                   string)

  IL_0028:  brtrue.s   IL_009a

  IL_002a:  ldc.i4     0x1

  IL_002f:  brfalse.s  IL_0062

  IL_0031:  ldarg.0

  IL_0032:  callvirt   instance class [System.Web]System.Web.UI.Page [System.Web]System.Web.UI.Control::get_Page()

  IL_0037:  callvirt   instance class [System.Web]System.Web.UI.ClientScriptManager [System.Web]System.Web.UI.Page::get_ClientScript()

  IL_003c:  ldarg.0

  IL_003d:  call       instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()

  IL_0042:  ldstr      ""

  IL_0047:  ldstr      "gnjikabjhphjdapjhpfklpmkmpdldmkldobmloimbopmlognko"

  + "nnljeohjloamcpcnjpgnaaenhailoadmfbmkljpobiafhkbdalpbmjgiildgfehojlmeeoj"

  + "colopnoakhlolfnkcgmndnheehocdfoahlpmboodmnakiaaflaaaeglpdnloeemmelmmdcn"

  + "nhjnkgaoghhokgooogfppgmpgdda"

  IL_004c:  ldc.i4     0x921899a

  IL_0051:  call       string xb9d8bb5e6df032aa.x1110bdd110cdcea4::_xaacba899487bce8c(string,

                                                                                      int32)

  IL_0056:  call       string [mscorlib]System.String::Intern(string)

  IL_005b:  callvirt   instance void [System.Web]System.Web.UI.ClientScriptManager::RegisterStartupScript(class [mscorlib]System.Type,

                                                                                                          string,

                                                                                                          string)

  IL_0060:  br.s       IL_0098

  IL_0062:  newobj     instance void [Common]ShopWe.Common.XMLControl::.ctor()

  IL_0067:  stloc.0

  IL_0068:  ldloc.0

  IL_0069:  ldarg.0

  IL_006a:  call       instance class [System.Web]System.Web.HttpServerUtility [System.Web]System.Web.UI.Page::get_Server()

  IL_006f:  ldstr      "~/Setting/ShowSetting.xml"

  IL_0074:  callvirt   instance string [System.Web]System.Web.HttpServerUtility::MapPath(string)

  IL_0079:  ldstr      "root/Cert"

  IL_007e:  ldarg.0

  IL_007f:  ldfld      class [System.Web]System.Web.UI.HtmlControls.HtmlInputText Admin_WebSetting_Cert::cert

  IL_0084:  callvirt   instance string [System.Web]System.Web.UI.HtmlControls.HtmlInputControl::get_Value()

  IL_0089:  callvirt   instance void [Common]ShopWe.Common.XMLControl::UpdateInnerText(string,

                                                                                       string,

                                                                                       string)

  IL_008e:  ldc.i4     0xfffffffe

  IL_0093:  brtrue     IL_0012

  IL_0098:  br.s       IL_00f9

  IL_009a:  ldarg.0

  IL_009b:  ldstr      "~/cert/"

  IL_00a0:  call       instance string [System.Web]System.Web.UI.Page::MapPath(string)

  IL_00a5:  call       bool [mscorlib]System.IO.Directory::Exists(string)

  IL_00aa:  brfalse.s  IL_00de

  IL_00ac:  ldarg.0

  IL_00ad:  ldfld      class [System.Web]System.Web.UI.WebControls.FileUpload Admin_WebSetting_Cert::UploadCert

  IL_00b2:  ldarg.0

  IL_00b3:  call       instance class [System.Web]System.Web.HttpServerUtility [System.Web]System.Web.UI.Page::get_Server()

  IL_00b8:  ldstr      "~/cert/"

  IL_00bd:  callvirt   instance string [System.Web]System.Web.HttpServerUtility::MapPath(string)

  IL_00c2:  ldarg.0

  IL_00c3:  ldfld      class [System.Web]System.Web.UI.WebControls.FileUpload Admin_WebSetting_Cert::UploadCert

  IL_00c8:  callvirt   instance string [System.Web]System.Web.UI.WebControls.FileUpload::get_FileName()

  IL_00cd:  call       string [mscorlib]System.String::Concat(string,

                                                              string)

  IL_00d2:  callvirt   instance void [System.Web]System.Web.UI.WebControls.FileUpload::SaveAs(string)

  IL_00d7:  br.s       IL_00f4

  IL_00d9:  br         IL_0013

  IL_00de:  ldarg.0

  IL_00df:  ldstr      "~/cert/"

  IL_00e4:  call       instance string [System.Web]System.Web.UI.Page::MapPath(string)

  IL_00e9:  call       class [mscorlib]System.IO.DirectoryInfo [mscorlib]System.IO.Directory::CreateDirectory(string)

  IL_00ee:  pop

  IL_00ef:  ldc.i4.0

  IL_00f0:  brtrue.s   IL_00ac

  IL_00f2:  br.s       IL_00ac

  IL_00f4:  br         IL_0062

  IL_00f9:  ret

} // end of method Admin_WebSetting_Cert::Submit_Click

 

如果你对MSIL还不了解,那么必然会面对上面的代码感到迷惑。不要紧,我只所以刚才将其描述为助记符是有原因的,上面的指令(第二列)表示了一些特定的意义。你也应该发现,这些指令是一些单词的简单形式:如:ret (return)

还有意思类的:.ldstr (load string) call (调用静态方法)callvirt(调用实例方法)ldarg加载参数

Ld这个前缀预示着要向托管堆分配内存并复制数据。

我们同时看到有熟悉的类库成员,一般使用类库时就会以类似原形的形式出现在代码中。

第一列是什么意思?怎么那么像地址。它就是地址,这种地址是相对地址,用于进行指令跳转,并不是内存中的真正地址。

上面蓝色的部分只是我在第一次接触MSIL时的猜测。之所以写出来是想让别人多一种懒人的办法。MSIL的相关知识建议看国外较为权威的书籍,或者去MSDN上进行指令含义的速查。想学MSIL,我可以推荐几本书,当前引进国内的这一方面的书几乎没有。

 

[查看DLL的内部,跟踪验证函数的思路,确定修改地点和修改方式]

现在我们分析上面的代码,不论怎样,这个事件当中必然有验证证书的逻辑。我们只需要先定位这段逻辑。

我们发现这段核心的验证代码:

 

其它的代码很明显是属于一般的IO操作。这一段初始了一个ValidateCert对象并调用它的一个返回BOOLValidCert方法。由IF来判断,因此,这一段属于验证判断。是我们需要修改的部分。很明显,我们可以取掉这段IF判断,只让其顺序执行为真的代码即可。

类似于下面的代码:

If(true)

{

  //TO DO:合法证书操作

}else{

  //TO DO: 不合法证书

}

但是,根据一般编程规律。一个验证逻辑应该被共享。因为如果验证仅仅在该事件被触发时才验证一次,那么当页面加载时,如果判断该软件是否注册?所以,很明显这个验证会在许多地方进行。我们要一一找出并修改,的确是一件很麻烦的事。但假设它们的验证点调用的是一个验证方法呢?事实上前面已经说了,这个逻辑应该被共享,所以,我们在这里不应该去改,而继续追踪 ValidCert方法。

下图为该验证类ValidateCert

 

这个方法的代码如下,

       .method public hidebysig instance bool  ValidCert() cil managed

{

  // 代码大小       311 (0x137)

  .maxstack  5

  .locals init (class [Common]ShopWe.Common.XMLControl V_0,

           char[] V_1,

           string[] V_2,

           bool V_3,

           bool V_4)

  .try

  {

    IL_0000:  call       class [System.Web]System.Web.HttpContext [System.Web]System.Web.HttpContext::get_Current()

    IL_0005:  callvirt   instance class [System.Web]System.Web.HttpRequest [System.Web]System.Web.HttpContext::get_Request()

    IL_000a:  ldstr      "~/Certificate.xml"

    IL_000f:  callvirt   instance string [System.Web]System.Web.HttpRequest::MapPath(string)

    IL_0014:  call       bool [mscorlib]System.IO.File::Exists(string)

    IL_0019:  brfalse.s  IL_0020

    IL_001b:  br         IL_00d7

    IL_0020:  ldc.i4.0

    IL_0021:  stloc.3

    IL_0022:  ldloc      V_3

    IL_0026:  conv.u4

    IL_0027:  ldloc      V_3

    IL_002b:  conv.u4

    IL_002c:  add

    IL_002d:  ldc.i4.0

    IL_002e:  clt.un

    IL_0030:  stloc      V_4

    IL_0034:  ldloc      V_4

    IL_0038:  brfalse.s  IL_0075

    IL_003a:  ldc.i4.1

    IL_003b:  stloc.3

    IL_003c:  leave      IL_0135

    IL_0041:  br.s       IL_006b

    IL_0043:  call       class [System.Web]System.Web.HttpContext [System.Web]System.Web.HttpContext::get_Current()

    IL_0048:  callvirt   instance class [System.Web]System.Web.HttpRequest [System.Web]System.Web.HttpContext::get_Request()

    IL_004d:  callvirt   instance class [System]System.Uri [System.Web]System.Web.HttpRequest::get_Url()

    IL_0052:  callvirt   instance string [System]System.Uri::get_Host()

    IL_0057:  callvirt   instance string [mscorlib]System.String::ToLower()

    IL_005c:  ldloc.2

    IL_005d:  ldc.i4.0

    IL_005e:  ldelem.ref

    IL_005f:  callvirt   instance string [mscorlib]System.String::ToLower()

    IL_0064:  callvirt   instance bool [mscorlib]System.String::Contains(string)

    IL_0069:  brtrue.s   IL_00b1

    IL_006b:  ldc.i4.0

    IL_006c:  stloc.3

    IL_006d:  leave      IL_0135

    IL_0072:  ldc.i4.0

    IL_0073:  brfalse.s  IL_0020

    IL_0075:  br.s       IL_00d0

    IL_0077:  ldarg.0

    IL_0078:  ldloc.0

    IL_0079:  call       class [System.Web]System.Web.HttpContext [System.Web]System.Web.HttpContext::get_Current()

    IL_007e:  callvirt   instance class [System.Web]System.Web.HttpRequest [System.Web]System.Web.HttpContext::get_Request()

    IL_0083:  ldstr      "~/Certificate.xml"

    IL_0088:  callvirt   instance string [System.Web]System.Web.HttpRequest::MapPath(string)

    IL_008d:  ldstr      "root/CertCode"

    IL_0092:  callvirt   instance string [Common]ShopWe.Common.XMLControl::GetInnerText(string,

                                                                                        string)

    IL_0097:  call       instance string ValidateCert::xcc381ffa3ede662f(string)

    IL_009c:  ldc.i4.1

    IL_009d:  newarr     [mscorlib]System.Char

    IL_00a2:  stloc.1

    IL_00a3:  ldloc.1

    IL_00a4:  ldc.i4.0

    IL_00a5:  ldc.i4.s   124

    IL_00a7:  stelem.i2

    IL_00a8:  ldloc.1

    IL_00a9:  callvirt   instance string[] [mscorlib]System.String::Split(char[])

    IL_00ae:  stloc.2

    IL_00af:  br.s       IL_0043

    IL_00b1:  call       valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Now()

    IL_00b6:  ldloc.2

    IL_00b7:  ldc.i4.1

    IL_00b8:  ldelem.ref

    IL_00b9:  call       valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::Parse(string)

    IL_00be:  call       bool [mscorlib]System.DateTime::op_LessThanOrEqual(valuetype [mscorlib]System.DateTime,

                                                                            valuetype [mscorlib]System.DateTime)

    IL_00c3:  brfalse.s  IL_006b

    IL_00c5:  ldc.i4.0

    IL_00c6:  brtrue     IL_0043

    IL_00cb:  br         IL_003a

    IL_00d0:  ldc.i4     0x3

    IL_00d5:  brtrue.s   IL_00fa

    IL_00d7:  ldloc      V_3

    IL_00db:  conv.u4

    IL_00dc:  ldloc      V_3

    IL_00e0:  conv.u4

    IL_00e1:  sub

    IL_00e2:  ldc.i4.0

    IL_00e3:  clt.un

    IL_00e5:  stloc      V_4

    IL_00e9:  ldloc      V_4

    IL_00ed:  brtrue.s   IL_00ef

    IL_00ef:  newobj     instance void [Common]ShopWe.Common.XMLControl::.ctor()

    IL_00f4:  stloc.0

    IL_00f5:  br         IL_0077

    IL_00fa:  leave.s    IL_0135

  }  // end .try

  catch [mscorlib]System.Object

  {

    IL_00fc:  pop

    IL_00fd:  call       class [System.Web]System.Web.HttpContext [System.Web]System.Web.HttpContext::get_Current()

    IL_0102:  callvirt   instance class [System.Web]System.Web.HttpRequest [System.Web]System.Web.HttpContext::get_Request()

    IL_0107:  ldstr      "~/Certificate.xml"

    IL_010c:  callvirt   instance string [System.Web]System.Web.HttpRequest::MapPath(string)

    IL_0111:  call       bool [mscorlib]System.IO.File::Exists(string)

    IL_0116:  brfalse.s  IL_0131

    IL_0118:  call       class [System.Web]System.Web.HttpContext [System.Web]System.Web.HttpContext::get_Current()

    IL_011d:  callvirt   instance class [System.Web]System.Web.HttpRequest [System.Web]System.Web.HttpContext::get_Request()

    IL_0122:  ldstr      "~/Certificate.xml"

    IL_0127:  callvirt   instance string [System.Web]System.Web.HttpRequest::MapPath(string)

    IL_012c:  call       void [mscorlib]System.IO.File::Delete(string)

    IL_0131:  ldc.i4.0

    IL_0132:  stloc.3

    IL_0133:  leave.s    IL_0135

  }  // end handler

  IL_0135:  ldloc.3

  IL_0136:  ret

} // end of method ValidateCert::ValidCert

 

或许和上面的代码一样,你感觉很晕,不要紧,首先这个方法返回的是一个BOOL,我们可以想到,返回真是为验证通过,返回假时为验证不通过。事实上代码中很明显进行了一次“证书加密的字符串比较”

如下面的核心代码。

 

这段代码进行了一次比较,如果比较结果为真,则表示验证成功,当前方法返回为真。代码中是从XML中读取一个字符串并调用一个方法解密后分隔为一个数组,这段比较了数组第一个项和当前路径的值。

事实上完全没有必要看方法的内部,你既然猜测它返回真假就意味着是否通过验证,那么只要注释该方法内部,加入直接返回真的代码即可。这种情况下,必须是在该方法内部没有和其它验证部分有影响的操作。比如,该方法内部同时写了一个私钥文件。而其它地方却需要使用这个文件。这种情况是不能这样处理的。但是,通过这段代码,并没有发现这类操作。

所以,我们只需要删除该方法内部的代码,编写一个返回为真的语句即可。

 

确定了修改地点和修改方案,那么接下来我们要将该DLL转储为IL文件,以便修改它。

[反编译DLLMSIL代码]

有许多工具可以选择,但微软提供的IL DASM工具已经绰绰有余了。

IL DASM打开 ShopWe DLL,然后执行 文件-》转储,在弹出的文件对话框中选择转储地址,输入文件名后确定即可,此时,你会在设置的路径下看到两个文件,一个为IL后缀的MSIL文件和一个RES的资源文件。

 

[修改MSIL]

现在,我们有了IL文件,接下来需要修改这个IL。用一般的文本编辑器都可以打开编辑。

在该.method public hidebysig instance bool

          ValidCert() cil managed

  方法体开始加入如下代码,这段代码只是简单的返回了一个真值。

 

//破解代码

// 代码大小       7 (0x7)

  .maxstack  1

  .locals init ([0] bool CS$1$0000)

  IL_0000:  nop

  IL_0001:  ldc.i4.1

  IL_0002:  stloc.0

  IL_0003:  br.s       IL_0005

  IL_0005:  ldloc.0

  IL_0006:  ret

//破解代码完

 

注释下面的逻辑,IL同样支持C++的单行多行注释符。

接下来编译修改过的DLL

 

[编译IL文件为DLL]

我使用微软的ilasm工具进行编译

 VS2005命令提示符下,输入ilasm filefullname /dll

Filefuname:你的IL文件的路径和文件名,后面的/DLL选项是告诉编译器输出为DLL

回车即可显示编译进度:

 

最后提示成功。如果没有成功,请仔细查看输出的错误信息。

一般常见的有:你的文件不可访问。这常是由于命令参数不对。或者当前用户缺少权限。

还有,就是你当前目录已经生成了一个DLL,并且由其它程序使用而造成无法覆盖的问题。

同时也要注意你修改的源文件是不是有语法等错误。

不会使用,请参考:http://msdn.microsoft.com/zh-cn/library/496e4ekx(VS.80).aspx

 

生成成功后,你就可以看到IL文件目录下生成的一个DLL文件。

 

[偷梁换柱 替换修改后的DLL]

将该DLL替换原网站下的DLL即可。到此,我打开系统并登陆,便可以看到“注册成功”的提示。

 

事实上,此时你会发现,这原来是如此简单的过程。这个简单的演示中,我们得到的不是一个免费的软件,而是知识。

 

 

原创粉丝点击