分享
 
 
 

r.a.d.treeview2.5破解手记

王朝asp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

自从开始使用DotNet做网站以来便顺手开发一个自己的技术论坛,倒没有别的目的,只是想检验一下自己对DotNet的掌握程度。整个论坛的帖子作为叶片绑定在Web树控件上,树控件使用的是微软的Microsoft.Web.UI.WebControls组件中的TreeView,由于Microsoft.Web.UI.WebControls的资源是指向IIS主目录的,当服务商未装载Microsoft.Web.UI.WebControls组件时,这棵树便成了一堆干柴,无奈之下,便下载了Microsoft.Web.UI.WebControls的源码啃了一阵,将资源指向了站点的虚拟目录,编译成自己的版本。论坛终于在局域网中建起来了,我给他起名就叫 “好大一棵树论坛”。朋友给我找了个免费空间让我测试,我便用那只56K的老猫灌起水来,运行当然是正常,但速度实在是不理想,闪烁问题虽然可以通过关闭回传来避免,但这是以牺牲论坛的实时性和其他重要功能为代价的。改用宽带再试,效果果然好了许多,但我的论坛便也就被同事戏称为“好大一棵树论坛 DotNet宽带版”了。由于一时找不到轻巧好用的Web树控件,这棵大树也就一直锁在深闺。

前几日在CSDN看到大家在对微软的TreeView大贬一通的同时,极力推崇r.a.d.treeview ,这便又一次勾起了我对那个论坛改换“树种”的想法。到r.a.d.treeview的老家http://www.telerik.com 上看了一下,果然响应速度和视觉效果都十分可心,便顺手下载了一个最新的2.5版。装入本机后,其演示画面如下:

由于是30天的免费试用版,我把计算机的日期向后调整了一年,结果随机的出现了如下过期提示。

由于两天前刚探究过DotNetTextBox1.3的授权方式(也顺便写了一篇破解手记,可惜这里不便发表),便直接用Reflector打开了RadTreeView.DLL,并直奔控件重载的渲染方法Render()。

反汇编得出如下代码:

VB代码

对应的IL汇编代码

Protected Overrides Sub Render(ByVal output As HtmlTextWriter)

Me.licenseMessage = String.Empty

If (Not Me.licenseMessage Is String.Empty) Then

output.Write(Me.licenseMessage)

Else

Me.Page.VerifyRenderingInServerForm(Me)

Dim text1 As String = String.Format("", Me.UniqueID, "trigger")

Dim objArray1 As Object() = New Object() { String.Concat(Me.UniqueID, "_expanded"), String.Concat(Me.UniqueID, "_expanded"), Me.UniqueID, "trigger" }

Dim text2 As String = String.Format("", objArray1)

objArray1 = New Object() { String.Concat(Me.UniqueID, "_checked"), String.Concat(Me.UniqueID, "_checked"), Me.UniqueID, "trigger" }

Dim text3 As String = String.Format("", objArray1)

objArray1 = New Object() { String.Concat(Me.UniqueID, "_selected"), String.Concat(Me.UniqueID, "_selected"), Me.UniqueID, "trigger" }

Dim text4 As String = String.Format("", objArray1)

output.Write(text1)

output.Write(text2)

output.Write(text3)

output.Write(text4)

End If

End Sub

.method family virtual instance void Render([System.Web]System.Web.UI.HtmlTextWriter output) cil managed

{

// Code Size: 344 byte(s)

.maxstack 5

.locals (

string text1,

string text2,

string text3,

string text4,

object[] objArray1)

L_0000: ldarg.0

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

L_0006: stfld string WebControlLibrary1.WebCustomControl1::licenseMessage

L_000b: ldarg.0

L_000c: ldfld string WebControlLibrary1.WebCustomControl1::licenseMessage

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

L_0016: beq.s L_0029

L_0018: ldarg.1

L_0019: ldarg.0

……中间无关代码略

L_0150: ldarg.1

L_0151: ldloc.3

L_0152: callvirt instance void [System.Web]System.Web.UI.HtmlTextWriter::Write(string)

L_0157: ret

}

与RadTreeView.DLL的Render方法的反汇编代码相对照,在WebControlLibrary1中得出如下对应关系

VB

对应的IL汇编代码

Me.licenseMessage = String.Empty

L_0000: ldarg.0

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

L_0006: stfld string Telerik.WebControls.RadTreeView::licenseMessage

现在,可以添加IL代码了。打开Visual Studio .NET 2003 命令提示

键入ILDASM 打开RadTreeView.DLL

然后转储IL反汇编代码,保存RadTreeView.IL,附属文件也一并出现在文件夹中

用记事本打开RadTreeView.IL文件,现取消强名称验证。在文件头部找到如下代码将其删除:

.publickey =(00 24 00 00 04 80 00 00 94 00 00 00 06 02 00 00 // .$..............

00 24 00 00 52 53 41 31 00 04 00 00 01 00 01 00 // .$..RSA1........

CD 62 12 05 0E 7C CD 6F 51 AF 2C 41 FD CC 65 44 // .b...|.oQ.,A..eD

AC E3 CF 79 6A 19 49 C5 80 C3 FF 52 7C AC 91 1D // ...yj.I....R|...

9B E0 5F AD 28 47 CE F4 E7 E5 EC 87 9F C9 4B E4 // .._.(G........K.

9E 31 C7 97 C2 B8 39 25 C4 ED F6 AA 83 FA 78 A3 // .1....9%......x.

5A 47 C0 F4 7B 44 A8 F9 3F D1 44 A9 B7 96 BF 74 // ZG..{D..?.D....t

9E 8D FC B3 99 82 11 52 A9 5C 7A 37 EB A3 82 B6 // .......R.\z7....

9D A5 8B 7A 1C 87 DA 5C ED 0B 7A 72 BA B1 3F 12 // ...z...\..zr..?.

52 C6 2F 50 DD 35 44 06 E6 F3 B0 4B AF F4 19 BD ) // R./P.5D....K....

查找Render方法,可见到其代码片断如下:

.method family hidebysig virtual instance void

Render(class [System.Web]System.Web.UI.HtmlTextWriter output) cil managed

{

// 代码大小 313 (0x139)

.maxstack 4

.locals init (class Telerik.WebControls.RadTreeViewHtmlRenderer V_0,

string V_1,

string V_2,

string V_3,

string V_4)

IL_0000: ldarg.0

IL_0001: ldfld string Telerik.WebControls.RadTreeView::licenseMessage

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

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

string)

IL_0010:

brfalse.s IL_001f

……中间无关代码略

IL_0124: callvirt instance void [mscorlib]System.IO.TextWriter::Write(string)

IL_0129: ldarg.1

IL_012a: ldloc.3

IL_012b: callvirt instance void [mscorlib]System.IO.TextWriter::Write(string)

IL_0130: ldarg.1

IL_0131: ldloc.s V_4

IL_0133: callvirt instance void [mscorlib]System.IO.TextWriter::Write(string)

IL_0138: ret

} // end of method RadTreeView::Render

将“仿真”的IL代码插入Render方法的最前面,见如下加粗代码。

.method family hidebysig virtual instance void

Render(class [System.Web]System.Web.UI.HtmlTextWriter output) cil managed

{

// 代码大小 313 (0x139)

.maxstack 4

.locals init (class Telerik.WebControls.RadTreeViewHtmlRenderer V_0,

string V_1,

string V_2,

string V_3,

string V_4)

L_0000: ldarg.0

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

L_0006: stfld string Telerik.WebControls.RadTreeView::licenseMessage

IL_0000: ldarg.0

IL_0001: ldfld string Telerik.WebControls.RadTreeView::licenseMessage

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

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

string)

IL_0010:

brfalse.s IL_001f

……中间无关代码略

IL_0133: callvirt instance void [mscorlib]System.IO.TextWriter::Write(string)

IL_0138: ret

} // end of method RadTreeView::Render

保存RadTreeView.IL准备使用ilasm重新编译,为应对编译出现反复,用记事本再做一个批处理文件Myasm.bat保存在同一目录中,内容如下:

ilasm /dll /resource: RadTreeView.res /output: RadTreeView.dll RadTreeView.IL

在Visual Studio .NET 2003 命令提示行运行Myasm,几秒钟后,新的RadTreeView.dll出现了。

为检查添加的IL指令的正确性,用Reflector打开破解后的RadTreeView.dll,反编译Render方法为VB代码,可惜的一幕出现了,Me.licenseMessage = String.Empty

指令准确地出现在我们预定的位置上,可见“仿真”的IL代码是正确的。见下图:

进入Microsoft Visual .NET 开发环境,将新的RadTreeView.dll添加到工具箱。仿照示例代码建立一测试页面WebForm1.aspx,将RadTreeView所需的资源TreeViewImages目录考入测试站点的虚拟目录中。

ContentFile="~/Examples/Advanced/ContextMenu/tree.xml" ImagesBaseDir="~/TreeViewImages/Round3d"

ContextMenuContentFile="~/Examples/Advanced/ContextMenu/ContextMenus.xml">

进行必要的设置后编译测试项目,在本机浏览器中用localhost方式进行检测,可见页面上的Web树工作正常,各节点展缩自如,不再出现过期警告。截屏如下:

在本机和其他机器上使用域名或IP地址访问测试页,则发现尽管也不再出现过期警告,但Web树不再响应鼠标点击。浏览器状态行还出现页面有错误,缺少对象的警告。看来,破解并未最终完成。

仔细查看RadTreeView帮助文档,发现该控件与域名和IP地址进行了捆绑。当时使用域名和IP地址访问时,如未通过验证则显示过期警告,并不再发送控件脚本至客户端。之前的工作仅屏蔽了过期警告,却未解决有关的脚本问题。

看来必须找到检测许可证的方法或函数,还是用Reflector,在Telerik.WebControls的RadTreeView节点上有一个CheckLicenseKeys函数,从其函数名便可以基本确定它就是我们要找的东西,如下图:

反汇编出CheckLicenseKeys()的代码如下

Private Function CheckLicenseKeys() As String

Dim text1 As String = String.Empty

Dim num1 As Integer = -1

Dim text2 As String = ""

Dim text3 As String = Me.Page.Request.ServerVariables.Get("SERVER_NAME").ToLower

Dim text4 As String = Me.Page.Request.ServerVariables.Get("LOCAL_ADDR")

If (((Me.Company Is String.Empty) AndAlso (Me.LicenseKey Is String.Empty)) AndAlso

(Not Me.LicenseFile Is String.Empty)) Then

Dim text5 As String = Me.Page.Request.MapPath(Me.LicenseFile.Replace("~/", Me.applicationPath))

Dim document1 As XmlDocument = New XmlDocument

Try

document1.Load(text5)

Dim reader1 As XmlTextReader = New

XmlTextReader(Assembly.GetExecutingAssembly.GetManifestResourceStream

("Telerik.WebControls.TreeViewResources.SchemaLicense.xsd"))

If Class2.Function4(document1, reader1) Then

Dim node1 As XmlNode

For Each node1 In document1.SelectNodes("//license[@control = 'treeview']")

Dim num2 As Integer = Class2.Function2(node1.Attributes.ItemOf("company").Value,

node1.Attributes.ItemOf("licenseKey").Value, text3, text4)

If (num2 > num1) Then

num1 = num2

End If

If (num1 = 1) Then

goto Label_016A

End If

Next

End If

Label_016A:

reader1.Close

Catch exception1 As XmlException

End Try

Else

num1 = Class2.Function2(Me.Company, Me.LicenseKey, text3, text4)

End If

If ((num1 <= 0) AndAlso ((text3 Is "localhost") OrElse (text4 Is "127.0.0.1"))) Then

num1 = 1

text2 = "Copyright ©

telerik 2003. To remove this message, please, obtain a href=""http://www.telerik.com/clientnet"">30-day trial key.

"

End If

If (num1 > 0) Then

If (text2.Length <= 0) Then

Return text1

End If

Dim time1 As DateTime = DateTime.Now

Dim random1 As Random = New Random(time1.Millisecond)

Dim num3 As Integer = random1.Next(19)

If (num3 <> 7) Then

Return text1

End If

Return text2

End If

Me.Controls.Clear

If (num1 < 0) Then

Return "r.a.d.

treeview v.2.1. You have not provided valid license key or company,

or you are trying to access the control by domain name, IP, or server name. Please,

use http://localhost instead or obtain a 30-day trial key."

End If

Return "r.a.d.treeview

v.2.1. Your trial key has expired.

To extend your key contact sales@telerik.com."

End Function

在记事本中打开RadTreeView.IL并搜索CheckLicenseKeys,发现整个控件仅在OnPreRender方法一处调用了CheckLicenseKeys函数,OnPreRender方法的VB代码为:

VB代码

对应的IL汇编代码

Protected Overrides Sub OnPreRender(ByVal e As EventArgs)

MyBase.OnPreRender(e)

Me.licenseMessage = Me.CheckLicenseKeys

If (Me.licenseMessage Is String.Empty) Then

If (Me.IsEmpty AndAlso (Not Me.ContentFile Is String.Empty)) Then

Me.LoadContentFile(Me.ContentFile)

End If

If ((Me.ContextMenus.Count = 0) AndAlso (Not Me.ContextMenuContentFile Is String.Empty)) Then

Dim document1 As XmlDocument = New XmlDocument

document1.Load(Me.Context.Server.MapPath(Me.ContextMenuContentFile.Replace("~/", Me.applicationPath)))

Me.LoadContextMenusXmlString(document1.OuterXml)

End If

If Not Me.IsEmpty Then

Me.Page.RegisterArrayDeclaration("tlrkTreeViews", Me.ID)

Me.Page.GetPostBackEventReference(Me, "dummy")

If (Not Me.CssFile Is String.Empty) Then

Me.Page.RegisterClientScriptBlock(String.Concat(Me.ID, "css"), String.Concat(", Me.CssFile.Replace("~/", Me.applicationPath), ">"))

End If

Me.RegisterStylesAsCss

If Not Me.Page.IsClientScriptBlockRegistered("RadTreeViewJavaScript") Then

If (Not Me.PathToJavaScript Is String.Empty) Then

Me.PathToJavaScript = Me.PathToJavaScript.Replace("~/", Me.applicationPath)

Me.Page.RegisterClientScriptBlock("RadTreeViewJavaScript", String.Concat("

" & ChrW(10)))

Else

Dim reader1 As StreamReader = New StreamReader(Assembly.GetExecutingAssembly.GetManifestResourceStream("Telerik.WebControls.TreeViewResources.RadTreeView_Client.js"))

Me.Page.RegisterClientScriptBlock("RadTreeViewJavaScript", String.Concat("

" & ChrW(10)))

End If

End If

End If

End If

End Sub

.method family hidebysig virtual instance

void OnPreRender([mscorlib]System.EventArgs e) cil managed

{

// Code Size: 488 byte(s)

.maxstack 7

.locals (

[System.Xml]System.Xml.XmlDocument document1,

[mscorlib]System.IO.StreamReader reader1)

L_0000: ldarg.0

L_0001: ldarg.1

L_0002: call instance void [System.Web]System.Web.UI.

WebControls.WebControl::OnPreRender([mscorlib]System.EventArgs)

L_0007: ldarg.0

L_0008: ldarg.0

L_0009: call instance string Telerik.WebControls.RadTreeView::

CheckLicenseKeys()

L_000e: stfld string Telerik.WebControls.RadTreeView::licenseMessage

L_0013: ldarg.0

L_0014: ldfld string Telerik.WebControls.RadTreeView::licenseMessage

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

L_001e: call bool string::op_Inequality(string, string)

L_0023: brfalse.s L_0026

L_0025: ret

L_0026: ldarg.0

L_0027: call instance bool Telerik.WebControls.RadTreeView::

get_IsEmpty()

L_002c: brfalse.s L_004c

L_002e: ldarg.0

L_002f: call instance string Telerik.WebControls.RadTreeView::

get_ContentFile()

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

L_0039: call bool string::op_Inequality(string, string)

L_003e: brfalse.s L_004c

L_0040: ldarg.0

……中间无关代码略

L_01c8: ldstr "RadTreeViewJavaScript"

L_01cd: ldstr "\n"

L_01dd: call string string::Concat(string, string, string)

L_01e2: callvirt instance void [System.Web]System.Web.UI.Page::

RegisterClientScriptBlock(string, string)

L_01e7: ret

}

看来,licenseMessage的值时从CheckLicenseKeys函数或取的,只要返回的字符串是空值便会将控件完整的渲染到客户端。这样一来,我们可以不必仔细研究CheckLicenseKey的代码了,反正我们又不是要制作授权码生成器。如果判断没有错误的话,现在唯一需要做的就是将OnPreRender方法中的 Me.licenseMessage = Me.CheckLicenseKeys 改为 Me.licenseMessage = String.Empty。结合前面分析Render方法的实的经验,我们得出了如下的代码对应关系。

VB代码

对应的IL汇编代码

Me.licenseMessage = String.Empty

L_0000: ldarg.0

L_0001: ldsfld string [mscorlib]

System.String::Empty

L_0006: stfld string Telerik.WebControls.RadTreeView::licenseMessage

Me.licenseMessage = Me.CheckLicenseKeys

L_0007: ldarg.0

L_0008: ldarg.0

L_0009: call instance string Telerik.WebControls

.RadTreeView::CheckLicenseKeys()

L_000e: stfld string Telerik.WebControls.RadTreeView::

licenseMessage

现在,再次用记事本打开RadTreeView.IL ,找到OnPreRender方法, 根据上面的代码对应关系,将Me.licenseMessage = Me.CheckLicenseKeys 的IL代码改为 Me.licenseMessage = String.Empty 的IL代码后存盘,并再次编译,测试结果表明,破解成功。

趁热打铁,最后就是解决示例文档与破解空间的完美结合问题。

在Visual Studio .NET中用C#新建一web项目r.a.d.treeview2.5x,并按下图将程序及名称和默认命名空间均设为tree

添加项目对新的RadTreeView.IL的引用后,将r.a.d.treeview2.5原示例站点中的除bin目录的全部目录及文件复制后经过Visual Studio .NET的解决方案资源管理器粘贴到r.a.d.treeview2.5x项目中,设计器会弹出如下对话框,选择“是”,建立一个关联的类文件。

用Reflector打开原示例站点bin目录中的tree.dll,反汇编出Tree.WebForm1的Page_Load的C#代码

private void Page_Load(object sender, EventArgs e)

{

string text2;

int num1 = 1;

string text1 = "Welcome";

if ((text2 = base.Request.QueryString.Get("Tab")) == null)

{

goto Label_009D;

}

text2 = string.IsInterned(text2);

if (text2 != "Quickstart")

{

if (text2 == "Examples")

{

goto Label_0077;

}

if (text2 == "Help")

{

goto Label_0081;

}

if (text2 == "Support")

{

goto Label_008B;

}

if (text2 == "Purchase")

{

goto Label_0095;

}

goto Label_009D;

}

num1 = 2;

text1 = "Quickstart";

goto Label_009D;

Label_0077:

num1 = 3;

text1 = "Examples";

goto Label_009D;

Label_0081:

num1 = 4;

text1 = "Help";

goto Label_009D;

Label_008B:

num1 = 5;

text1 = "Support";

goto Label_009D;

Label_0095:

num1 = 6;

text1 = "Purchase";

Label_009D:

this.leftNavigation.Controls.Add(base.LoadControl(string.Format("~/Examples/{0}Navigation.ascx", text1)));

this.content.Controls.Add(base.LoadControl(string.Format("~/Examples/{0}.ascx", text1)));

this.tabsImage.Src = string.Format("Img/tab{0}.gif", num1);

}

将上述代码填入Default.aspx.cs的private void Page_Load(object sender, System.EventArgs e)中。

生成这个示例项目后,在浏览器地址栏键入http://您的IP/r.a.d.treeview2.5x/,一个完美的r.a.d.treeview2.5破解版便诞生了。

看看她的全貌吧:

我是边破解边写这篇文档的,用了整整一天的时间。回过头来看,如果不走弯路,两个小时解决战斗是完全有可能的。

(另外,由于篇幅问题,在由WORD向这个WEB在线编辑器贴文章的时候,感觉这里采用的WEB在线编辑器对于图文并茂的文章作者时间十分痛苦的事,是在不如我破解的DotNetTextBox1.3。设置的编辑幅面太小,版面调整太困难,还不能会表格,急死人了。还有其他事,谁有什么好的控件请推荐给我,发到我的邮箱aspdotnet@yeah.net即可)

三君DotNet工作室 君仁

2004年9月17日星期五23时于 大连 旅顺

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有