熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

深入解析.NET 許可證編譯器 (Lc.exe) 的原理與源代碼剖析

2013-11-13 10:43:04  來源: .NET編程 
許可證編譯器 (Lcexe) 的作用是讀取包含授權信息的文本文件並產生一個可作為資源嵌入到公用語言運行庫可執行文件中的 licenses 文件  

  在使用第三方類庫時經常會看到它自帶的演示程序中包含有這樣的Demo許可文件

復制代碼 代碼如下:
InfragisticsWinMiscUltraButton InfragisticsWinMiscv Version= Culture=neutral PublicKeyToken=fbbbfdf
InfragisticsWinMiscUltraLabel InfragisticsWinMiscv Version= Culture=neutral PublicKeyToken=fbbbfdf
InfragisticsWinPrintingUltraPrintPreviewDialog InfragisticsWinUltraWinPrintPreviewDialogv Version= Culture=neutral PublicKeyToken=fbbbfdf
InfragisticsWinUltraWinDataSourceUltraDataSource InfragisticsWinUltraWinDataSourcev Version= Culture=neutral PublicKeyToken=fbbbfdf

  
這個文件的格式是文本文件但要按照它的格式要求來寫

  控件名稱 程序集全名稱

  首先根據需要寫一個需要被授權的控件列表格式如上所示例如HostAppexe 的應用程序要引用SamplesDLL 中的授權控件 MyCompanySamplesLicControl則可以創建包含以下內容的 HostAppLictxt MyCompanySamplesLicControl SamplesDLL

  再調用下面的命令創建名為 HostAppexelicenses 的 licenses 文件 lc /target:HostAppexe /complist:hostapplictxt /i:SamplesDLL /outdir:c:bindir

  生成將 licenses 文件作為資源嵌入在HostAppexe的資源中如果生成的是 C# 應用程序則應使用下面的命令生成應用程序

  csc /res:HostAppexelicenses /out:HostAppexe *cs

  NET Framework SDK目錄中的LCEXE文件是由NET語言編寫的它的功能就是為了根據許可文件的內容生成資源文件在編譯的最後時刻由CSC編譯器把生成的資源文件嵌入到執行文件中

  NET Reflector載入LCEXE開始源代碼分析之旅

  image

程序的入口處先是分析命令行參數根據參數的不同來執行指定的功能先看一個完整的參數列表代碼是下面三行

復制代碼 代碼如下:
if (!ProcessArgs(args))
 {
     return num;
 }

  
image

MSDN有完整的解釋拷貝到下面方便您參考以減少因查找MSDN引起思路中斷
/complist:filename   指定包含授權組件列表的文件名這些授權組件要包括到 licenses 文件中每個組件用它的全名引用並且每行只有一個組件命令行用戶可為項目中的每個窗體指定一個單獨的文件Lcexe 接受多個輸入文件並產生一個 licenses 文件
/h[elp]     顯示該工具的命令語法和選項
/i:module   指定模塊這些模塊包含文件 /complist 中列出的組件若要指定多個模塊請使用多個 /i 標志
/nologo  取消顯示 Microsoft 啟動標題
/outdir:path  指定用來放置輸出 licenses 文件的目錄
/target:targetPE   指定為其生成 licenses 文件的可執行文件
/v   指定詳細模式顯示編譯進度信息
/?  顯示該工具的命令語法和選項
ProcessArgs方法的關鍵作用是分析出組件列表程序集列表如下面的代碼所示

復制代碼 代碼如下:
  if ((!flag && (strLength > )) && strSubstring( )ToUpper(CultureInfoInvariantCulture)Equals("TARGET:"))
 {
       targetPE = strSubstring();
       flag = true;
 }
if ((!flag && (strLength > )) && strSubstring( )ToUpper(CultureInfoInvariantCulture)Equals("COMPLIST:"))
 {
      string str = strSubstring();
      if ((str != null) && (strLength > ))
        {
                    if (compLists == null)
                    {
                        compLists = new ArrayList();
                    }
                    compListsAdd(str);
                    flag = true;
       }
}
if ((!flag && (strLength > )) && strSubstring( )ToUpper(CultureInfoInvariantCulture)Equals("I:"))
 {
       string str = strSubstring();
       if (strLength > )
        {
                    if (assemblies == null)
                    {
                        assemblies = new ArrayList();
                    }
                    assembliesAdd(str);
        }
        flag = true;
}

  
分 析出組件和程序集之後再來ResolveEventHandler 委托的含義如果運行庫類加載程序無法解析對程序集類型或資源的引用則將引發相應的事件從而使回調有機會通知運行庫引用的程序集類型或資源位於哪 個程序集中ResolveEventHandler 負責返回解析類型程序集或資源的程序集

復制代碼 代碼如下:
ResolveEventHandler handler = new ResolveEventHandler(LicenseCompilerOnAssemblyResolve);
AppDomainCurrentDomainAssemblyResolve += handler;

  
對第一部參數分析出來的組件列表依次循環為它們產生授權許可

復制代碼 代碼如下:
DesigntimeLicenseContext creationContext = new DesigntimeLicenseContext();
foreach (string str in compLists)
{
   key = readerReadLine();    hashtable[key] = TypeGetType(key);        LicenseManagerCreateWithContext((Type) hashtable[key] creationContext);
}

  
最後生成許可文件並保存到磁盤中等待CSC編譯器將它編譯成資源文件嵌入到程序集中

復制代碼 代碼如下:
string path = null;
if (outputDir != null)
 {
    path = outputDir + @"" + targetPEToLower(CultureInfoInvariantCulture) + "licenses";
 }
else
 {
      path = targetPEToLower(CultureInfoInvariantCulture) + "licenses";
 }
 Stream o = null;
 try
     {
            o = FileCreate(path);
           DesigntimeLicenseContextSerializerSerialize(o targetPEToUpper(CultureInfoInvariantCulture) creationContext);
     }
     finally
     {
            if (o != null)
            {
                oFlush();
                oClose();
            }
     }

  
這種方式是NET Framework推薦的保護組件的方式與我們平時所討論的輸入序列號RSA簽名不同
來看一下商業的組件是如何應用這種技術保護組件的

復制代碼 代碼如下:
using System;
using SystemWeb;
using SystemWebUI;
using SystemWebUIWebControls;
using SystemComponentModel;
namespace ComponentArtLicensingProviders
{
  #region RedistributableLicenseProvider
    public class RedistributableLicenseProvider : SystemComponentModelLicenseProvider
    {
    const string strAppKey = "This edition of ComponentArt WebUI is licensed for XYZ application only";   

    public override SystemComponentModelLicense GetLicense(LicenseContext context Type type object instance bool allowExceptions)
    {
      if (contextUsageMode == LicenseUsageModeDesigntime)
      {
        // We are not going to worry about design time Issue a license
        return new ComponentArtLicensingProvidersRedistributableLicense(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 = HttpContextCurrent;
        strFoundAppKey = (string)ctxApplication["ComponentArtWebUI_AppKey"];
        if(strAppKey == strFoundAppKey)
          return new ComponentArtLicensingProvidersRedistributableLicense(this "The App");
        else
          return null;
      }
    }
  }
  #endregion
  #region RedistributableLicense Class
  public class RedistributableLicense : SystemComponentModelLicense
  {
    private ComponentArtLicensingProvidersRedistributableLicenseProvider owner;
    private string key;
    public RedistributableLicense(ComponentArtLicensingProvidersRedistributableLicenseProvider owner string key)
    {
      thisowner = owner;
      thiskey = 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)與控件本身的邏輯完全分離分工協作保護組件的知識產權


From:http://tw.wingwit.com/Article/program/net/201311/14366.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.