.NET程序集强命名删除与再签名技术 源代码剖析
2015-08-15 13:41
429 查看
如果你想去除一个程序集的强签名(strongname),目前为止可以有两个途径
1反编译为IL代码,删除签名部分,再编译为程序集
2应用Re-Sign程序,直接对一个程序集再签名
下面的代码读取该文件,
再深究一下,BCL中原来还有一个StrongNameKeyPair的类型,它的构造方法如下
这个类型中的方法,用调用BCL的内部帮助函数StrongNameHelpers
为了完成这个任务,先参考几个不常见的BLC中的API
向容器中导入一个公钥/私钥对,如果成功完成,则为true;否则为false。
删除指定的密钥容器。如果成功完成,则为true;否则为false。
生成指定程序集的强名称签名。如果成功完成,则为true;否则为false。
从指定的程序集文件创建强名称标记,并返回标记代表的公钥。强名称标记是公钥的缩写形式。该标记是依据用于对程序集进行签名的公钥创建的64位哈希。该标记是程序集的强名称的一部分,并且可以从程序集元数据中读取。
释放上一次调用强名称函数(如StrongNameGetPublicKey、StrongNameTokenFromPublicKey或StrongNameSignatureGeneration)时分配的内存。
获取由某个强名称函数引发的上一个错误代码。由某一个强名称函数设置的上一个COM错误代码。
大部分强名称方法返回简单的true或false以指示是否成功完成。使用StrongNameErrorInfo函数检索指定由强名称函数生成的上一个错误的HRESULT。
再把整个程序集读取内存中
下面的代码获取已经签名的程序集的签名信息
读取签名文件的长度,它将是要写入到程序集中的签名
最后调用方法,添加和生成签名
因为这几个方法的调用不会抛出异常,所以要用Win32式的GetLastError函数一样,使用StrongNameErrorInfo()方法来截获错误,
整个过程几乎就是对BCL的API调用,全部代码在百行以内。我在想,VisualStudio内置的给程序集签名的方式,也应该与此有相似之处,毕竟核心的API都已经被
微软封装进BCL类库,只需要调用即可。
这个工具来源于一家专门研究逆向工程的研究小组,你可以通过下面的网址找到他们发布的研究成果。
http://www.reteam.org/index.html
1反编译为IL代码,删除签名部分,再编译为程序集
2应用Re-Sign程序,直接对一个程序集再签名
生成和读取强命名
先来看,如何生成.NET的签名文件,调用命令SN传入参数。下面的代码读取该文件,
FileStreamkeyPairFile=File.OpenRead(“key.sn”); this.byte_2=newStrongNameKeyPair(keyPairFile).PublicKey; keyPairFile.Close();
再深究一下,BCL中原来还有一个StrongNameKeyPair的类型,它的构造方法如下
[SecuritySafeCritical,SecurityPermission(SecurityAction.Demand,Flags=SecurityPermissionFlag.UnmanagedCode)] publicStrongNameKeyPair(FileStreamkeyPairFile) { if(keyPairFile==null) { thrownewArgumentNullException("keyPairFile"); } intlength=(int)keyPairFile.Length; this._keyPairArray=newbyte[length]; keyPairFile.Read(this._keyPairArray,0,length); this._keyPairExported=true; }
这个类型中的方法,用调用BCL的内部帮助函数StrongNameHelpers
namespaceMicrosoft.Runtime.Hosting { [ComImport,SecurityCritical,Guid("9FD93CCF-3280-4391-B3A9-96E1CDE77C8D"),ComConversionLoss,InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internalinterfaceIClrStrongName [ComImport,Guid("9FD93CCF-3280-4391-B3A9-96E1CDE77C8D"),SecurityCritical,ComConversionLoss,InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internalinterfaceIClrStrongNameUsingIntPtr internalstaticclassStrongNameHelpers }
.NET框架对StrongName的支持
关于strongname的创建,生成与验证,可以参考StrongNameHelpers的源代码。为了完成这个任务,先参考几个不常见的BLC中的API
[DllImport("mscoree.dll",CharSet=CharSet.Auto)]
privatestaticexternboolStrongNameKeyInstall([MarshalAs(UnmanagedType.LPWStr)]stringwszKeyContainer,[MarshalAs(UnmanagedType.LPArray,SizeParamIndex=2)]byte[]pbKeyBlob,intint_1);
向容器中导入一个公钥/私钥对,如果成功完成,则为true;否则为false。
[DllImport("mscoree.dll",CharSet=CharSet.Auto)]
privatestaticexternboolStrongNameKeyDelete(stringstring_3);
删除指定的密钥容器。如果成功完成,则为true;否则为false。
[DllImport("mscoree.dll",CharSet=CharSet.Auto)]
privatestaticexternboolStrongNameSignatureGeneration(stringstring_3,stringstring_4,intint_1,intint_2,intint_3,intint_4);
生成指定程序集的强名称签名。如果成功完成,则为true;否则为false。
[DllImport("mscoree.dll",CharSet=CharSet.Auto)]
privatestaticexternboolStrongNameTokenFromAssemblyEx([MarshalAs(UnmanagedType.LPWStr)]stringwszFilePath,refIntPtrintptr_0,[MarshalAs(UnmanagedType.U4)]outintpcbStrongNameToken,refIntPtrintptr_1,[MarshalAs(UnmanagedType.U4)]outintpcbPublicKeyBlob);
从指定的程序集文件创建强名称标记,并返回标记代表的公钥。强名称标记是公钥的缩写形式。该标记是依据用于对程序集进行签名的公钥创建的64位哈希。该标记是程序集的强名称的一部分,并且可以从程序集元数据中读取。
[DllImport("mscoree.dll",CharSet=CharSet.Auto)]
privatestaticexternvoidStrongNameFreeBuffer(IntPtrintptr_0);
释放上一次调用强名称函数(如StrongNameGetPublicKey、StrongNameTokenFromPublicKey或StrongNameSignatureGeneration)时分配的内存。
[DllImport("mscoree.dll",CharSet=CharSet.Auto)]
privatestaticexternuintStrongNameErrorInfo();
获取由某个强名称函数引发的上一个错误代码。由某一个强名称函数设置的上一个COM错误代码。
大部分强名称方法返回简单的true或false以指示是否成功完成。使用StrongNameErrorInfo函数检索指定由强名称函数生成的上一个错误的HRESULT。
程序中的代码流程分析
先用代码读取一个程序集的strongnamethis.byte_1=AssemblyName.GetAssemblyName("Test.dll").GetPublicKey();
再把整个程序集读取内存中
using(FileStreamstream2=File.OpenRead(“Test.dll"))
{
this.byte_3=newbyte[stream2.Length];
stream2.Read(this.byte_3,0,(int)stream2.Length);
}
下面的代码获取已经签名的程序集的签名信息
intnum;
intnum2;
StrongNameTokenFromAssemblyEx(string_3,refptr2,outnum2,refzero,outnum);
byte[]destination=newbyte[num2];
Marshal.Copy(ptr2,destination,0,num2);
读取签名文件的长度,它将是要写入到程序集中的签名
FileStreaminput=newFileStream(“sn.key”,FileMode.OpenOrCreate,FileAccess.Read);
BinaryReaderreader=newBinaryReader(input);
byte[]buffer2=newbyte[(int)reader.BaseStream.Length];
reader.BaseStream.Seek(0L,SeekOrigin.Begin);
reader.Read(buffer2,0,(int)reader.BaseStream.Length);
intlength=(int)reader.BaseStream.Length;
reader.Close();
input.Close();
最后调用方法,添加和生成签名
StrongNameKeyInstall("Test.dll",buffer,length))
StrongNameSignatureGeneration("Test.dll",snKey,0,0,0,0))
因为这几个方法的调用不会抛出异常,所以要用Win32式的GetLastError函数一样,使用
整个过程几乎就是对BCL的API调用,全部代码在百行以内。我在想,VisualStudio内置的给程序集签名的方式,也应该与此有相似之处,毕竟核心的API都已经被
微软封装进BCL类库,只需要调用即可。
这个工具来源于一家专门研究逆向工程的研究小组,你可以通过下面的网址找到他们发布的研究成果。
相关文章推荐
- UTF-8 CPP的使用
- UTF-8 CPP的使用
- 《第一行代码》学习笔记,第一、二章
- Ubuntu Qt5.5 Mysql driver
- PHP 开发环境配置
- Spring入门
- 安装个wampserver 环境 运行php
- [JAVA第二课] java命名规则
- 最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现
- Python练习:优酷评论过滤(抓取当前视频全部评论,并过滤不包括所需关键词的留言)
- wxPython Cookbook (Chatper1)part 3
- java.lang.NullPointerException Exception details are logged in Window > Show View > Error Log 正确解决方法
- 代码规范问题总结(三)
- Java初级培训笔记------容器 (1)
- Java基础06 组合
- C++基础---字符型
- C# 设置线程的默认CultureInfo
- MR案例:多文件输出MultipleOutputs
- C# 逻辑语句
- C++基础---浮点型