.NET程序集强命名删除与再签名技术 源代码剖析
如果你想去除一个程序集的强签名(strong name),目前为止可以有两个途径
1 反编译为IL代码,删除签名部分,再编译为程序集
2 应用Re-Sign程序,直接对一个程序集再签名
生成和读取强命名
先来看,如何生成.NET的签名文件,调用命令SN传入参数。
下面的代码读取该文件,
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);
.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; }
.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; }
删除指定的密钥容器。如果成功完成,则为 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();
.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; }
再把整个程序集读取内存中
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);
.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; }
读取签名文件的长度,它将是要写入到程序集中的签名
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
.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; }
.NET程序集强命名删除与再签名技术 源代码剖析的更多相关文章
- .net程序集强命名(签名)
要想得到强签名的dll有两种情况: 1.给项目添加强命名 在你的项目右键->属性->签名,勾选“为程序集签名”,新建 或 浏览已经新建过的.pfx文件,然后重新build项目,生成的dll ...
- .NET中查看一个强命名程序集(*****.dll)的PublicKeyToken的方法
使用命令行工具SDK Command Prompt,键入:SN -T C:\*****.dll (dll文件所在的路径) 就会显示出该dll具体的PublicKeyToken数值. 如果该程序集没有 ...
- C#程序集使用强名字(Strong Name)签名/强名称签名
强名称签名的方法: 强签名: 1. 可以将强签名的dll注册到GAC,不同的应用程序可以共享同一dll. 2. 强签名的库,或者应用程序只能引用强签名的dll,不能引用未强签名的dll,但是未强签名的 ...
- [.NET] - Enhanced Strong Naming (加强版的强签名程序集) – 如何迁移原有的强命名程序集
依据文档: https://msdn.microsoft.com/en-us/library/hh415055(v=vs.110).aspx 虽然文档上给出了看似完整的步骤,但是如果按照上面的步骤,结 ...
- CLR 关于强命名程序集 .
如何创建强命名程序集(Strong Name Assembly) 创建一个强命名程序集首先需要获得一个用强命名实用工具 (Strong Name Utility,即SN.exe,.NET ...
- C# 强命名程序集,防止dll被修改,混淆下发布
未能加载文件或程序集“Jonckers.Service.RedisCacheEngineExtend, Version=1.0.0.0, Culture=neutral, PublicKeyToken ...
- 第一部分 CLR基础:第3章 共享程序集和强命名程序集
第一部分 CLR基础:第3章 共享程序集和强命名程序集
- 只有ReflectionOnlyLoadFrom才可以拯救与GAC冲突的强命名程序集
先说结论,如果有两个拥有相同程序集名称的强命名程序集,一个在GAC里,一个不在.怎样动态加载那个不在GAC里的程序集?答案就是只有Assembly.ReflectionOnlyLoadFrom才可以加 ...
- membership DB生成 & dll 强命名 & 证书生成
UPD(Membership)数据库安装1.使用 Aspnet_regsql.exe 安装数据库 在 C:\WINDOWS\Microsoft.NET\Framework\\aspnet_regsql ...
随机推荐
- 位图图像处理控件ImageCapture Suite更新至v9.1
概述:Dynamsoft公司旗下非常出名的位图图像处理控件ImageCapture Suite更新至了v9.1,这次新版本为Mac版本和IE 9新增了不少功能,同时还对其他组件的性能进行了质的提高! ...
- HTML URL 编码
转自:http://www.w3school.com.cn/tags/html_ref_urlencode.htmlURL 编码 - 从 %00 到 %8f ASCII Value URL-encod ...
- link2001错误无法解析外部符号metaObject
http://blog.sina.com.cn/s/blog_791f544a0100r01b.html 1>MainWindowBottomWidget.obj : error LNK ...
- android 自定义scrollview 仿QQ空间效果 下拉伸缩顶部图片,上拉回弹 上拉滚动顶部title 颜色渐变
首先要知道 自定义scrollview 仿QQ效果 下拉伸缩放大顶部图片 的原理是监听ontouch事件,在MotionEvent.ACTION_MOVE事件时候,使用不同倍数的系数,重置布局位置[ ...
- 将图片压缩后转Base64函数
function CutImgToBase(fn: string): string; // 压缩图片只能压缩bmp:将jpg转换成bmp再压缩 var m1: TMemoryStream; m2: T ...
- java-IO
框架图 IO(Input Output)流IO流用来处理设备之间的数据传输,Java对数据的操作是通过流的方式,用于操作流的对象都在IO包中. 流按操作数据分为两种:字节流与字符流 .流按流向分为:输 ...
- explode,split,preg_split性能比较
explode,split,preg_split性能比较 分类: php2012-07-12 09:46 1109人阅读 评论(1) 收藏 举报 三个函数都是用来对字符串进行分割,下面分几个实验来 ...
- jquery ajax post 中文乱码解决
jquery ajax post 方式默认传递的是UFT-8字符,即使页面设置了gbk编码也无效.字符传到后台时如果后台设置的gbk或者其他编码,就会出现乱码.解决很容易,将后台页面设置成UTF-8编 ...
- .Net mvc 后台传单引号错误'
今天调试半天程序 结果出现JS 无法eval() 网上找个半天解决办法无果 最后 是因为后台输出单引号’ 到前台为' 解决办法 给一个隐藏文本框或者标签赋值 再取出来就能显示单引号了
- android内存优化
背景 虽然android设备的配置越来越高,但是,由于android系统的机制导致(最主要是app程序的主线程不会真正退出而是在后台常驻内存中) ,这样手机中安装过多的app之后,导致内存被大量占用, ...