C#编写的DLL如何加密?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#编写的DLL如何加密?相关的知识,希望对你有一定的参考价值。

C#编写的DLL文件都可以通过reflector反编译,
如何才能解决这个问题呢?
VS 自带的Dotfuscator用过了,只是对属性方法的名称进行了混淆,代码丝毫没有改变,不够理想。

c# dll 加密最快的方法使用加壳工具Virbox Protector,直接加密,Virbox Protectorke可以对dll进行性能分析,分析每个函数的调用次数,对每个函数选择保护方式如:混淆/虚拟化/碎片化/代码加密等;每种加密方法的特点是什么呢?

代码加密(X86):

针对X86汇编代码:一种代码自修改技术(SMC)保护代码。把当前代码加密存储为密文,存储起来,当程序运行到被保护函数时候自动解密并且执行,执行之后再擦除代码,运行到哪里才解密哪里的代码,黑客无法获得原始机器指令和内存完整性的代码,由于是纯内存操作所以运行速度快, 性价高的保护手段,建议全加

代码加密(IL)

针对dotNet程序,保护IL代码:一种动态运行方法解密被保护代码。把当前代码加密存储为密文,存储起来,当程序运行到被保护函数时候自动解密并且执行,执行之后再擦除代码,执行之后再擦除代码,运行到哪里才解密哪里的代码,黑客无法获得原始的中间语言的指令和内存完整性的代码,由于是纯内存操作所以运行速度快, 性价高的保护手段,建议全加

压缩

类似zip等压缩软件把代码和数据段压缩,由于带有动态密码,没有任何工具可以自动脱壳,是防止反编译和反汇编关键手段。

代码混淆(IL):

将代码中的各种元素,如变量,函数,类的名字改写成无意义的名字。比如改写成单个字母,或是简短的无意义字母组合,甚至改写成“__”这样的符号,使得阅读的人无法根据名字猜测其用途。

a)重写代码中的部分逻辑,将其变成功能上等价,但是更难理解的形式。比如将for循环改写成while循环,将循环改写成递归,精简中间变量,等等。

b) 打乱代码的格式。比如删除空格,将多行代码挤到一行中,或者将一行代码断成多行等等。

c) 添加花指令,通过特殊构造的指令来使得反汇编器出错,进而干扰反编译工作的进行。

代码混淆器也会带来一些问题。主要的问题包括:· 被混淆的代码难于理解,因此调试除错也变得困难起来。开发人员通常需要保留原始的未混淆的代码用于调试。· 对于支持反射的语言,代码混淆有可能与反射发生冲突。· 代码混淆并不能真正阻止反向工程,只能增大其难度。因此,对于对安全性要求很高的场合,仅仅使用代码混淆并不能保证源代码的安全。

代码混淆的特点是安全度低、不会影响效率。

代码虚拟化:

针对X86代码: 是指将机器代码翻译为机器和人都无法识别的一串伪代码字节流;在具体执行时再对这些伪代码进行一一翻译解释,逐步还原为原始代码并执行。 这段用于翻译伪代码并负责具体执行的子程序就叫作虚拟机VM(好似一个抽象的CPU)。它以一个函数的形式存在,函数的参数就是字节码的内存地址。 由于虚拟机代码和虚拟机CPU的实现可以做到每次都是随机设计和随机执行 并且代码每次可以随机变化,包括一些逻辑上的等价变化可以参考硬件N个与非门NOT-AND实现各种逻辑门,算法和访问内存形式的变化,包括数学上的非等价变化,代码体积几乎可以膨胀达到100到10000倍,造成机器无法做算法还原到原有逻辑。

代码虚拟化的特点是:安全度中、不会影响效率。

代码碎片化:

深思自主知识产权的最新技术:基于 LLVM 和 ARM 虚拟机技术,自动抽取海量代码移入 SS 内核态模块,极大的降低了使用门槛, 不再需要手动移植算法,可移植的算法从有限的几个增长到几乎无限多,支持的语言也不再限于 C, 这是加密技术的一次综合应用,效果上类似于将软件打散执行,让破解者无从下手。

安全度高、建议关键函数或调用加密锁方法;使用太多会影响效率

参考技术A   可以利用CPUid,硬盘串号,网卡MAC和当时授权的时间生成一串机器码,然后传到网上和你的当时注册的相比对就好了,到期自动无法使用。
  如果该dll一定要在联网的情况下使用,完全可以在服务端存储客户端dll验证状态,每次使用的时候联网查询服务器,判断该用户是否授权、是否试用期、是否已过期等等,然后决定该客户端dll是否可用,这样的话,完全不用在客户端(注册表)存储任何信息, 授权的方式 也就更新一下服务端数据库中的信息。
参考技术B 可以使用C#混淆器来防止被别人反编辑。
两款很强的混淆器:
国产的MaxToCode,内核级保护,非常强大
国外的Themida,经常更新,一有人破解马上能升级阻止本回答被提问者和网友采纳
参考技术C 通常用的方法就是“混淆”了

不用别的软件,你装了vs2005/2008/2010之后到开始菜单里找vs下面的Visual Studio Tools里有一个“Dotfuscator Software Services”,打开,就可以用它来混淆你的代码,具体过程很简单,你试试就知道了

想要更多信息,搜“.NET 混淆”即可有大量信息
参考技术D 可以考虑使用 Xenocode 混淆
这软件是外国的,可以找到破解的版本下载
腾讯的QQ概念版(C#开发)就是用这软件混淆的

PB调用C#编写的DLL

C#以其简单易用,功能强大深受大家喜爱.PowerBuilder作为C/S的MIS开发工具,十分简单灵活,开发时间短,开发及维护成本低,一直是中小企业信息管理系统的首选开发工具.但是PB的局限性限制了它进一步的发展,这个就不多说了,玩PB的朋友都清楚.PB如何调用C#写的DLL,这个兴趣一上来,就忍不住要解决它.经过多方查找资料加上自己写代码测试,算是解决这个难题.下面列出开发步骤及各种设置选项(开发工具VS2008SP1+PB9.0-8836)

     首先我们打开VS2008,新建一个项目,如图

接着我们双击解决方案下面的属性文件夹[Properties],系统将打开类型的属性设置窗口,选择[应用程序]

点击程序集信息按钮,弹出信息窗口,选中[使程序集COM可见],如图

接下来选择[生成]标签 ,选中[为COM互操作注册]

选择[签名]标签,选中[为程序集签名]-->[选择强名称密钥文件]-->[新建],输入你的密钥名称,去掉[使用密码保护密钥文件],如图

OK,到这里配置完成,下面给出代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Security.Cryptography;
using System.IO;
using System.Web.SessionState;
using System.Runtime.InteropServices;

namespace encry
{
    [Guid("FF6B4D57-F34E-49ec-9A3B-D0A17B59F78A")]
    public interface IEncryption
    {
        [DispId(1)]
        string EncryptString(string encryptString, string encryptKey);
        [DispId(2)]
        string DecryptString(string decryptString, string decryptKey);
        [DispId(3)]
        string md5(string str, int code);
    }

    [Guid("531D2D13-11DE-41a8-A788-CB51B5642CCE"), ClassInterface(ClassInterfaceType.None), ComSourceInterfaces(typeof(IEncryption))]
    public class encryption : IEncryption
    {
        #region "3des加密字符串"
        /// <summary>
        /// DES加密字符串
        /// </summary>
        /// <param name="encryptString">待加密的字符串</param>
        /// <param name="encryptKey">加密密钥,要求为8位</param>
        /// <returns>加密成功返回加密后的字符串,失败返回源串</returns>
        public string EncryptString(string encryptString, string encryptKey)
        {
            try
            {
                byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8));
                byte[] rgbIV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
                byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
                DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider();
                MemoryStream mStream = new MemoryStream();
                CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
                cStream.Write(inputByteArray, 0, inputByteArray.Length);
                cStream.FlushFinalBlock();
                return Convert.ToBase64String(mStream.ToArray());
            }
            catch
             {
                return encryptString;
            }
        }
        #endregion

        #region "3des解密字符串"
        /// <summary>
        /// DES解密字符串
        /// </summary>
        /// <param name="decryptString">待解密的字符串</param>
        /// <param name="decryptKey">解密密钥,要求为8位,和加密密钥相同</param>
        /// <returns>解密成功返回解密后的字符串,失败返源串</returns>
        public string DecryptString(string decryptString, string decryptKey)
        {
            try
            {
                byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey.Substring(0, 8));
                byte[] rgbIV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
                byte[] inputByteArray = Convert.FromBase64String(decryptString);
                DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider();
                MemoryStream mStream = new MemoryStream();
                CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
                cStream.Write(inputByteArray, 0, inputByteArray.Length);
                cStream.FlushFinalBlock();
                return Encoding.UTF8.GetString(mStream.ToArray());
            }
            catch
            {
                return decryptString;
            }
        }

        #endregion

        #region "MD5加密"
        /// <summary>
        /// MD5加密
        /// </summary>
        /// <param name="str">加密字符</param>
        /// <param name="code">加密位数16/32</param>
        /// <returns></returns>
        public string md5(string str, int code)
        {
            string strEncrypt = string.Empty;
            if (code == 16)
            {
                strEncrypt = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, "MD5").Substring(8, 16);
            }

            if (code == 32)
            {
                strEncrypt = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, "MD5");
            }

            return strEncrypt;
        }
        #endregion
    }
}

生成一下,在你的程序目录下面bin文件夹下有一个debug文件夹,生成的DLL就在里面.这个时候pb还不能调用这个DLL.

在这里说明一下,代码里面的GUID是怎样生成的.

打开你的VS2008命令提示,如图

输入[guidgen],按下回车

选着选项4,注册格式,点击[New GUID],将生成新的序列号,点击[Copy]复制序列号,粘贴的时候记得将前后的花括号去掉

要想pb能够调用这个DLL,关键在于要注册这个DLL,注册过程如下,打开VS2008命令提示,打开你的DLL所在的路径,然后输入如下命令

regasm 你的DLL名称.DLL /tlb:你的DLL名称.tlb,看图

如果成功注册将会出现上面的画面.

接上来是我们PB如何调用这个DLL了.看下图(调用方式为OLE)

 

 

增加一个实例变量

OLEObject encryption

在窗体的Open()事件里面写下以下代码

encryption = Create OLEObject
encryption.ConnectToNewObject("encry.encryption")

"encry" 是你C#写的DLL的命名空间的名称

"encryption"是你的DLL的类名称.别搞错了.

在[执行MD5加密]的按钮脚本写如下代码

long  ll_status
string ls_text
string ls_dotext

ls_text = sle_1.Text
ls_dotext = encryption.md5(ls_text,32)
sle_2.Text = ls_dotext

如果一切OK的话,会出现下面的画面

至此,程序结束.可以跟大家共同参考,学习.

以上是关于C#编写的DLL如何加密?的主要内容,如果未能解决你的问题,请参考以下文章

使用Dotfuscator加密混淆程序以及如何脱壳反编译

使用Dotfuscator加密混淆程序以及如何脱壳反编译

c#怎么加密 防止被破解

c#调用C、C++编写的dll

c#编程添加引用dll文件后怎样调用

C#调用C++编写的DLL(非托管)