zoukankan      html  css  js  c++  java
  • .NET程序集强命名删除与再签名技术 源代码剖析

    如果你想去除一个程序集的强签名(strong name),目前为止可以有两个途径

    1  反编译为IL代码,删除签名部分,再编译为程序集

    2  应用Re-Sign程序,直接对一个程序集再签名

    image

    生成和读取强命名

    先来看,如何生成.NET的签名文件,调用命令SN传入参数。

    image

    下面的代码读取该文件,

    FileStream keyPairFile = File.OpenRead(“key.sn”);
    this.byte_2 = new StrongNameKeyPair(keyPairFile).PublicKey;
    keyPairFile.Close();
    

    再深究一下,BCL中原来还有一个StrongNameKeyPair的类型,它的构造方法如下

    [SecuritySafeCritical, SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
    public StrongNameKeyPair(FileStream keyPairFile)
    {
        if (keyPairFile == null)
        {
            throw new ArgumentNullException("keyPairFile");
        }
        int length = (int) keyPairFile.Length;
        this._keyPairArray = new byte[length];
        keyPairFile.Read(this._keyPairArray, 0, length);
        this._keyPairExported = true;
    }
    

    这个类型中的方法,用调用BCL的内部帮助函数StrongNameHelpers

    namespace Microsoft.Runtime.Hosting
    {
        [ComImport, SecurityCritical, Guid("9FD93CCF-3280-4391-B3A9-96E1CDE77C8D"), ComConversionLoss, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        internal interface IClrStrongName
    
        [ComImport, Guid("9FD93CCF-3280-4391-B3A9-96E1CDE77C8D"), SecurityCritical, ComConversionLoss, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        internal interface IClrStrongNameUsingIntPtr
    
        internal static class StrongNameHelpers
    }
     

    .NET 框架对Strong Name的支持

    关于strong name的创建,生成与验证,可以参考StrongNameHelpers的源代码。

    为了完成这个任务,先参考几个不常见的BLC中的API

    [DllImport("mscoree.dll", CharSet=CharSet.Auto)]
    private static extern bool StrongNameKeyInstall([MarshalAs(UnmanagedType.LPWStr)] string wszKeyContainer, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)] byte[] pbKeyBlob, int int_1);
    

    向容器中导入一个公钥/私钥对, 如果成功完成,则为 true;否则为 false。

    [DllImport("mscoree.dll", CharSet=CharSet.Auto)]
    private static extern bool StrongNameKeyDelete(string string_3);
     
    

    删除指定的密钥容器。如果成功完成,则为 true;否则为 false。

    [DllImport("mscoree.dll", CharSet=CharSet.Auto)]
    private static extern bool StrongNameSignatureGeneration(string string_3, string string_4, int int_1, int int_2, int int_3, int int_4);
    

    生成指定程序集的强名称签名。如果成功完成,则为 true;否则为 false。

    [DllImport("mscoree.dll", CharSet=CharSet.Auto)]
    private static extern bool StrongNameTokenFromAssemblyEx([MarshalAs(UnmanagedType.LPWStr)] string wszFilePath, ref IntPtr intptr_0, [MarshalAs(UnmanagedType.U4)] out int pcbStrongNameToken, ref IntPtr intptr_1, [MarshalAs(UnmanagedType.U4)] out int pcbPublicKeyBlob);
    

    从指定的程序集文件创建强名称标记,并返回标记代表的公钥。强名称标记是公钥的缩写形式。该标记是依据用于对程序集进行签名的公钥创建的 64 位哈希。该标记是程序集的强名称的一部分,并且可以从程序集元数据中读取。

    [DllImport("mscoree.dll", CharSet=CharSet.Auto)]
    private static extern void StrongNameFreeBuffer(IntPtr intptr_0);
    

    释放上一次调用强名称函数(如 StrongNameGetPublicKey、StrongNameTokenFromPublicKey 或 StrongNameSignatureGeneration)时分配的内存。

    [DllImport("mscoree.dll", CharSet=CharSet.Auto)]
    private static extern uint StrongNameErrorInfo();
    

    获取由某个强名称函数引发的上一个错误代码。由某一个强名称函数设置的上一个 COM 错误代码。

    大部分强名称方法返回简单的 true 或 false 以指示是否成功完成。使用 StrongNameErrorInfo 函数检索指定由强名称函数生成的上一个错误的 HRESULT。

     

    程序中的代码流程分析

    先用代码读取一个程序集的strong name

    this.byte_1 = AssemblyName.GetAssemblyName("Test.dll").GetPublicKey();
    

    再把整个程序集读取内存中

    using (FileStream stream2 = File.OpenRead(“Test.dll"))
    {
           this.byte_3 = new byte[stream2.Length];
           stream2.Read(this.byte_3, 0, (int) stream2.Length);
    }
    

    下面的代码获取已经签名的程序集的签名信息

    int num;
    int num2;
    StrongNameTokenFromAssemblyEx(string_3, ref ptr2, out num2, ref zero, out num);
    byte[] destination = new byte[num2];
    Marshal.Copy(ptr2, destination, 0, num2);
    

    读取签名文件的长度,它将是要写入到程序集中的签名

    FileStream input = new FileStream(“sn.key”, FileMode.OpenOrCreate, FileAccess.Read);
    BinaryReader reader = new BinaryReader(input);
    byte[] buffer2 = new byte[(int) reader.BaseStream.Length];
    reader.BaseStream.Seek(0L, SeekOrigin.Begin);
    reader.Read(buffer2, 0, (int) reader.BaseStream.Length);
    int length = (int) reader.BaseStream.Length;
    reader.Close();
    input.Close();
     

    最后调用方法,添加和生成签名

    StrongNameKeyInstall("Test.dll", buffer, length))
    StrongNameSignatureGeneration("Test.dll", snKey, 0, 0, 0, 0))
    

    因为这几个方法的调用不会抛出异常,所以要用Win32式的GetLastError函数一样,使用StrongNameErrorInfo()方法来截获错误,

    整个过程几乎就是对BCL的API调用,全部代码在百行以内。我在想,Visual Studio内置的给程序集签名的方式,也应该与此有相似之处,毕竟核心的API都已经被

    微软封装进BCL类库,只需要调用即可。

    这个工具来源于一家专门研究逆向工程的研究小组,你可以通过下面的网址找到他们发布的研究成果。

    http://www.reteam.org/index.html

     
    
    
    
     
  • 相关阅读:
    91. 最短Hamilton路径【状压DP】
    EF框架使用
    html文本转化为html格式显示的问题
    遇到的错误及解决方式总结
    快速上手一个第三方控件,工具等
    提高窗体加载效率
    个人的一些技巧总结
    一些调试程序的小技巧
    Git原理基础(版本控制机制)
    版本控制介绍
  • 原文地址:https://www.cnblogs.com/JamesLi2015/p/3177153.html
Copyright © 2011-2022 走看看