解析.NET 许可证编译器 (Lc.exe) 的原理与源代码剖析
来源:互联网 发布:手机号绑定软件查询 编辑:程序博客网 时间:2024/06/06 12:52
许可证编译器 (Lc.exe) 的作用是读取包含授权信息的文本文件,并产生一个可作为资源嵌入到公用语言运行库可执行文件中的 .licenses 文件。
在使用第三方类库时,经常会看到它自带的演示程序中,包含有这样的Demo许可文件
Infragistics.Win.Misc.UltraButton, Infragistics2.Win.Misc.v11.1, Version=11.1.20111.2009, Culture=neutral, PublicKeyToken=f8b58b62b52fdf31Infragistics.Win.Misc.UltraLabel, Infragistics2.Win.Misc.v11.1, Version=11.1.20111.2009, Culture=neutral, PublicKeyToken=f8b58b62b52fdf31Infragistics.Win.Printing.UltraPrintPreviewDialog, Infragistics2.Win.UltraWinPrintPreviewDialog.v11.1, Version=11.1.20111.2009, Culture=neutral, PublicKeyToken=f8b58b62b52fdf31Infragistics.Win.UltraWinDataSource.UltraDataSource, Infragistics2.Win.UltraWinDataSource.v11.1, Version=11.1.20111.2009, Culture=neutral, PublicKeyToken=f8b58b62b52fdf31
这个文件的格式是文本文件,但要按照它的格式要求来写:
控件名称, 程序集全名称
首先根据需要,写一个需要被授权的控件列表,格式如上所示。例如,HostApp.exe 的应用程序要引用Samples.DLL 中的授权控件 MyCompany.Samples.LicControl1,则可以创建包含以下内容的 HostAppLic.txt。 MyCompany.Samples.LicControl1, Samples.DLL。
再调用下面的命令创建名为 HostApp.exe.licenses 的 .licenses 文件。 lc /target:HostApp.exe /complist:hostapplic.txt /i:Samples.DLL /outdir:c:\bindir
生成将 .licenses 文件作为资源嵌入在HostApp.exe的资源中。如果生成的是 C# 应用程序,则应使用下面的命令生成应用程序。
csc /res:HostApp.exe.licenses /out:HostApp.exe *.cs
.NET Framework SDK目录中的LC.EXE文件是由.NET语言编写的,它的功能就是为了根据许可文件的内容,生成资源文件。在编译的最后时刻,由CSC编译器把生成的资源文件嵌入到执行文件中。
用.NET Reflector载入LC.EXE,开始源代码分析之旅。
程序的入口处先是分析命令行参数,根据参数的不同来执行指定的功能。先看一个完整的参数列表。代码是下面三行
if (!ProcessArgs(args)) { return num; }.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }
MSDN有完整的解释,拷贝到下面方便您参考,以减少因查找MSDN引起思路中断。
/complist:filename 指定包含授权组件列表的文件名,这些授权组件要包括到 .licenses 文件中。每个组件用它的全名引用,并且每行只有一个组件。命令行用户可为项目中的每个窗体指定一个单独的文件。Lc.exe 接受多个输入文件并产生一个 .licenses 文件。
/h[elp] 显示该工具的命令语法和选项。
/i:module 指定模块,这些模块包含文件 /complist 中列出的组件。若要指定多个模块,请使用多个 /i 标志。
/nologo 取消显示 Microsoft 启动标题。
/outdir:path 指定用来放置输出 .licenses 文件的目录。
/target:targetPE 指定为其生成 .licenses 文件的可执行文件。
/v 指定详细模式;显示编译进度信息。
/? 显示该工具的命令语法和选项。
ProcessArgs方法的关键作用是分析出组件列表,程序集列表,如下面的代码所示
if ((!flag3 && (str2.Length > 7)) && str2.Substring(0, 7).ToUpper(CultureInfo.InvariantCulture).Equals("TARGET:")) { targetPE = str2.Substring(7); flag3 = true; }if ((!flag3 && (str2.Length > 8)) && str2.Substring(0, 9).ToUpper(CultureInfo.InvariantCulture).Equals("COMPLIST:")) { string str3 = str2.Substring(9); if ((str3 != null) && (str3.Length > 1)) { if (compLists == null) { compLists = new ArrayList(); } compLists.Add(str3); flag3 = true; }}if ((!flag3 && (str2.Length > 2)) && str2.Substring(0, 2).ToUpper(CultureInfo.InvariantCulture).Equals("I:")) { string str4 = str2.Substring(2); if (str4.Length > 0) { if (assemblies == null) { assemblies = new ArrayList(); } assemblies.Add(str4); } flag3 = true;}
分析出组件和程序集之后,再来ResolveEventHandler 委托的含义。如果运行库类加载程序无法解析对程序集、类型或资源的引用,则将引发相应的事件,从而使回调有机会通知运行库引用的程序集、类型或资源位于哪个程序集中。ResolveEventHandler 负责返回解析类型、程序集或资源的程序集。
ResolveEventHandler handler = new ResolveEventHandler(LicenseCompiler.OnAssemblyResolve);AppDomain.CurrentDomain.AssemblyResolve += handler;
.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; } 对第一部参数分析出来的组件列表,依次循环,为它们产生授权许可
DesigntimeLicenseContext creationContext = new DesigntimeLicenseContext();foreach (string str in compLists){ key = reader.ReadLine();
hashtable[key] = Type.GetType(key);
LicenseManager.CreateWithContext((Type) hashtable[key], creationContext);}
.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; } .csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }
最后,生成许可文件并保存到磁盘中,等待CSC编译器将它编译成资源文件,嵌入到程序集中。
string path = null;if (outputDir != null) { path = outputDir + @"\" + targetPE.ToLower(CultureInfo.InvariantCulture) + ".licenses"; }else { path = targetPE.ToLower(CultureInfo.InvariantCulture) + ".licenses"; } Stream o = null; try { o = File.Create(path); DesigntimeLicenseContextSerializer.Serialize(o, targetPE.ToUpper(CultureInfo.InvariantCulture), creationContext); } finally { if (o != null) { o.Flush(); o.Close(); } }
这种方式是.NET Framework推荐的保护组件的方式,与我们平时所讨论的输入序列号,RSA签名不同。
来看一下,商业的组件是如何应用这种技术保护组件的。
using System;using System.Web;using System.Web.UI;using System.Web.UI.WebControls;using System.ComponentModel;namespace ComponentArt.Licensing.Providers{ #region RedistributableLicenseProvider public class RedistributableLicenseProvider : System.ComponentModel.LicenseProvider { const string strAppKey = "This edition of ComponentArt Web.UI is licensed for XYZ application only."; public override System.ComponentModel.License GetLicense(LicenseContext context, Type type, object instance, bool allowExceptions) { if (context.UsageMode == LicenseUsageMode.Designtime) { // We are not going to worry about design time Issue a license return new ComponentArt.Licensing.Providers.RedistributableLicense(this, "The App"); } else { string strFoundAppKey; // During runtime, we only want this control to run in the application // that it was packaged with. HttpContext ctx = HttpContext.Current; strFoundAppKey = (string)ctx.Application["ComponentArtWebUI_AppKey"]; if(strAppKey == strFoundAppKey) return new ComponentArt.Licensing.Providers.RedistributableLicense(this, "The App"); else return null; } } } #endregion #region RedistributableLicense Class public class RedistributableLicense : System.ComponentModel.License { private ComponentArt.Licensing.Providers.RedistributableLicenseProvider owner; private string key; public RedistributableLicense(ComponentArt.Licensing.Providers.RedistributableLicenseProvider owner, string key) { this.owner = owner; this.key = key; } public override string LicenseKey { get { return key; } } public override void Dispose() { } } #endregion }
首先要创建一个类型,继承于License类型,再创建一个继承于LicenseProvider的类型,用于颁发许可证,包含在设计时许可和运行时许可,从上面的例子中可以看到,设计时没有限制,可以运行,但是到运行时,你必须有序列号,它才会生成许可对象,而不是返回null给.NET Framework类型。整个验证过程由.NET完成。
你只需要像下面这样,应用这个许可保护机制:
[LicenseProvider(typeof(RedistributableLicenseProvider))]public class MyControl : Control { // Insert code here. protected override void Dispose(bool disposing) { /* All components must dispose of the licenses they grant. * Insert code here to dispose of the license. */ }}
控件许可的验证代码(RedistributableLicenseProvider)与控件本身的逻辑完全分离,分工协作保护组件的知识产权。
.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }<script type="text/javascript"><!--google_ad_client = "ca-pub-1944176156128447";/* cnblogs 首页横幅 */google_ad_slot = "5419468456";google_ad_width = 728;google_ad_height = 90;//--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
- 解析.NET 许可证编译器 (Lc.exe) 的原理与源代码剖析
- 解析.NET 许可证编译器 (Lc.exe) 的原理与源代码剖析
- 从google的源代码剖析word2vec原理
- VS2008未能找到LC.exe的解决
- LC.exe” exited with code -1 错误解析
- ActiveReports .NET 引发 VS2008 LC.exe已退出,代码-1
- asp.net LC.exe已退出代码为-1
- C编译器剖析_源代码说明
- hr与lc的对比
- 微软开放.net的部分源代码(c#编译器等)
- 深入剖析ASP.NET的编译原理
- LC并联谐振电路的原理
- Lc.exe已退出
- LC.exe -1
- c编译器自动测试工具的剖析与移植
- LC.EXE 已退出,代码为-1的问题
- "lc.exe"已退出 代码为-1 的解决方法
- lc.exe已退出 代码为-1 问题的解决
- 创建守护进程
- Spring Batch Framework– introduction chapter(上)
- 增强无线路由器信号的方法与技巧
- Node.js and the JavaScript Age
- 如何判断cpu是否支持二级地址转换SLAT(EPT)
- 解析.NET 许可证编译器 (Lc.exe) 的原理与源代码剖析
- 位操作技巧和总结
- 如何设置无线路由器实现wifi连接
- 码分多址(CDMA)的本质-正交之美
- 基于ASIHTTPRequest的图片cache组件
- 【变形Floyd】HDU-1217 Arbitrage
- 路由器的基本配置及公用命令
- 解决网络不通数据只有发送不接收的问题
- linux路由内核实现分析(一)----邻居子节点(1)