您的位置:首页 > 编程语言

.NET程序集强命名删除与再签名技术 源代码剖析

2015-08-15 13:41 429 查看
如果你想去除一个程序集的强签名(strongname),目前为止可以有两个途径

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。

程序中的代码流程分析

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

this.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函数一样,使用StrongNameErrorInfo()方法来截获错误,

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

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

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

http://www.reteam.org/index.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: