1. 程式人生 > >[C#] [安全] [加密解密] 逆向某GIS軟體驗證函式後生成的加密解密演算法

[C#] [安全] [加密解密] 逆向某GIS軟體驗證函式後生成的加密解密演算法

目錄

1.Intro

2.Details

3.Theory

4.Environment 

5.Source

註冊機概覽:

註冊碼生成(加密模組):

註冊碼驗證(解密模組):

許可呼叫的功能模組:

6.Conclusion


1.Intro

爬蟲在耳邊縈繞,傾聽著瀏覽器的呢喃,從urllib2到selenium,飛向scrapy,直至穿越伺服器的心間,一切都只不過是Mongo下的微粒... 正當做著白日夢的時候,一聲聽起來無力又有點腎虛的呼喚攪屎了我的詩作:“猿兒!你快過來下!”

他撅起屁股,哦不,是張開嘴,我就知道絕逼沒有比如請我吃飯的好事:“ ***那個軟體太貴了!買不起啊兄弟!我看你一表人才,給破解下唄~”

一表人才還行,但我是一個罕見的十分正直的人:“淦!我們搞GIS的,又不是黑帽,不要再蹦逼了,整不來整不來”

X:“那個新來女同事的微信...”

我:“你我都是兄弟,凡事好商量”

就這樣,繼做爬蟲之後,又從一個搞地信開發的變成了搞破解的,天天不務正業說的就是本猿。


2.Details

說起來這個軟體,在GIS業內倒也不是很出名,只是有很多滿足一些國土和地理資訊生產業務的功能,而且做的也比較成熟,所以說不得不用,但是授權方式是每人一套,一套的價格大概是1w+,本著能用破解版就絕壁不買的原則(深受ArcGIS的影響,一套正版的高階版ArcGIS桌面產品大概是149000.....),就反編譯了一下解密模組,值得慶幸的是這個軟體廠商並沒有加殼和進行原始碼混淆,所以基本上所有的解密模組程式碼就都搞出來了....如果問為什麼不直接Copy他的核心功能函式,因為功能比較多,類庫依賴關係和動態連結庫配置比較複雜,而且我又懶(主要原因),所以還不如逆向一下解密模組算求了。

逆向了一下這個軟體的解密過程,大概就用到兩種加密演算法,Base64和RSA(比較雞賊,居然用RSA)。

加密資訊是獲取CPU序列號、主機板序列號、硬碟序列號轉成大寫後用字元 “_” 連線(就是一般的獲取硬體序列號方法)。

加密方法是將加密資訊先通過RSA不對稱加密,再通過Base64對稱加密,然後將許可時間寫入到登錄檔,在把許可時間組合通過Base64加密,最後生成兩行許可資訊(具體內容在程式碼註釋中可以找到)。

由於對方使用了RSA,所以沒辦法生成註冊機,原因為RSA是對資訊進行私(公)鑰加密,然後用公(私)鑰去驗證,私鑰只被加密方持有,我這隻持有公鑰,所以只能揮淚咒罵,這下好了,美女同事的微信也沒了。但是這個加密解密的方法還是值得學習的,整理下,自己生成一個RSA金鑰對,可以用在以後軟體的加密模組上,倒也算一個收穫。


3.Theory

網上找了幾張圖,圖解一下兩種加密方式的原理,具體的演算法原理可以上別處找去,嘖。

對稱加密(Base64):具體來說,就是金鑰是同一把,可以加密可以解密。

不對稱加密(RSA):兩把不同的金鑰,一把加密,一把解密。

 


4.Environment 

Environment:Windows All

Language:C#

IDE:Visual Studio 2012


5.Source

註冊機概覽:

註冊碼生成(加密模組):

using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Management;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;

namespace KeyGen
{
    public class LicGenerate
    {
        private string _sysinfo = "";

        public LicGenerate(string sysInfo)
        {
            this._sysinfo = sysInfo;
        }

        #region 許可引數
        //許可時間資訊
        private string _fromDateTime = "";
        private string _toDateTime = "";

        //機器序列號
        private static string _systemInfo = string.Empty;

        //許可檔案內容
        private string keyLicenseCode = "";
        private string timeLicenseCode = "";

        /// <summary>
        /// 許可開始時間
        /// </summary>
        public string fromDateTime
        {
            set { _fromDateTime = value; }
            get { return _fromDateTime; }
        }

        /// <summary>
        /// 許可結束時間
        /// </summary>
        public string toDateTime
        {
            set { _toDateTime = value; }
            get { return _toDateTime; }
        }

        /// <summary>
        /// 私鑰
        /// </summary>
        private const string privateKey = "<RSAKeyValue><Modulus>r+Fknz/UEsPyB+rOJpRt6BLPUnPvYFEAuXFtL6x23NI7LrUf+Xvcfo1iPMMJruOdNPs+wYNpxNy1166n5mRuSLn7EPbt1aumfCmtgq150NDWWdmx1y5rHNGFu9sUSUm+EgNEgVNbrjTTq8ru7ZJU2X5CLuLMYevuXwBaLZoS8kk=</Modulus><Exponent>AQAB</Exponent><P>6UVOdO86q+jMO8pdQGivk1EW2AnO3LRzkULvKcsXhqXXlQAjDhjPEF192osfmmnLXiqMkYd9DxcVb9oa5sLxXw==</P><Q>wQSLzXpqLsdb2lExGRx2iNEGZvxgjQxIkgb21DLrzgKSu6dTUzhxnZ2Iag4XcB5AWedseqRVvcGEkPmchQ31Vw==</Q><DP>kS/X0yQKqnCsnRIo1CvUC6bOxwvjuq59t42neaW0MNQLx+tb5iw+xHrMGDe7JcpvD18AOpvPlJLTftiLIdF3lQ==</DP><DQ>C5YYRkdY5GH3M424IsfAncneVoRDz3OzT4C3hFliKkWhRT5wFAjJWSrBq4wZABPwzPTFYD9JHlDlgkZZjOsflQ==</DQ><InverseQ>hnXlKRysPRroqHNd8SlzAcEPnWpgExIxLU2McE6slDO0DrABEyb/LHG6BTc8eBvzO6G+JiaKddTVKhHCLVU/rA==</InverseQ><D>Vo6JU6o494dBTM4s6GWx9T2UlJKD4xXaUmlU/9pToPdBswnmk4R2jj2MdDTURiK0kod3agr/eafZQi0takBQ2V4Kq86JI/Ei2VvMP781sPE/pnfENMufwfbdcbHdrU4heyd3DBT0NtTfOA71jeAlVbvMrCJVYDo/H3VVukGntUU=</D></RSAKeyValue>";

        /// <summary>
        /// 第一行的許可資訊
        /// </summary>
        public string KeyLicenseCode
        {
            set{ keyLicenseCode = value; }
            get{ return keyLicenseCode; }
        }

        /// <summary>
        /// 第二行的許可資訊
        /// </summary>
        public string TimeLicenseCode
        {
            set{ timeLicenseCode = value; }
            get{ return timeLicenseCode; }
        }

        /// <summary>
        /// SHA1(Secure Hash Algorithm)安全雜湊演算法的雜湊值,主要用於數字簽名驗證
        /// </summary>
        private static HashAlgorithm DefaultHashAlgorithm
        {
            get
            {
                return (HashAlgorithm)new SHA1CryptoServiceProvider();
            }
        }

        /// <summary>
        /// 預設位元組順序編碼為UTF-16編碼
        /// </summary>
        private static Encoding ByteConvertor
        {
            get
            {
                return Encoding.Unicode;
            }
        }
        #endregion

        #region 逆向許可方法
        #region 生成許可檔案
        /// <summary>
        /// 許可檔案儲存
        /// </summary>
        /// <returns>返回許可檔案路徑</returns>
        private string licenseFileSave()
        {
            try
            {
                string licenseFilePath;
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.InitialDirectory = "D:\\";
                saveFileDialog.Filter = "許可檔案(*.lic)|*.lic";
                saveFileDialog.RestoreDirectory = true;
                DialogResult dr = saveFileDialog.ShowDialog();
                if (dr == DialogResult.OK && saveFileDialog.FileName.Length > 0)
                {
                    licenseFilePath = saveFileDialog.FileName;
                }
                else
                {
                    return null;
                }
                return licenseFilePath;
            }
            catch
            {
                MessageBox.Show("許可檔案儲存失敗!");
                return null;
            }        
        }
        #endregion

        #region 註冊碼生成
        /// <summary>
        /// 時間許可
        /// </summary>
        /// <returns>返回加密的時間許可程式碼</returns>
        private string timeLicense()
        {
            try
            {
                DateTime fromDate;
                DateTime toDate;

                fromDate = DateTime.Parse(fromDateTime);
                toDate = DateTime.Parse(toDateTime);

                DateTime nowDate = DateTime.Now;

                string str = Convert.ToBase64String(Encoding.Default.GetBytes(fromDate.ToString() + (object)"$" + toDate.ToShortDateString() + "$" + (object)nowDate.ToString()));
                return str;
            }
            catch
            {
                MessageBox.Show("時間許可生成失敗!");
                return null;
            }
            
        }

        /// <summary>
        /// 私鑰簽名
        /// </summary>
        /// <param name="licenseFilePath">許可路徑</param>
        /// <param name="signatureData">需要簽名的資料(機器碼)</param>
        /// <param name="privateKey">私鑰</param>
        /// <returns></returns>
        private string privateKeySignature(byte[] signatureData, string privateKey)
        {
            try 
            {
                //私鑰簽名
                RSACryptoServiceProvider cryptoServiceProvider = new RSACryptoServiceProvider();
                cryptoServiceProvider.FromXmlString(privateKey);

                //用SHA1的雜湊演算法指定位元組陣列的雜湊值,並對計算所得的雜湊值進行簽名,得到加密後的位元組陣列
                byte[] signature = cryptoServiceProvider.SignData(signatureData, (object)DefaultHashAlgorithm);

                //簽名資料用Base64演算法進行加密
                string keyCode = Convert.ToBase64String(signature);
                return keyCode;
            }        
            catch
            {
                MessageBox.Show("許可簽名失敗!");
                return null;
            }
        }
        #endregion

        //#region 系統資訊
        ///// <summary>
        ///// 獲得機器碼資訊
        ///// </summary>
        //private static string SystemInfo
        //{
        //    get
        //    {
        //        try
        //        {
        //            //如果字串系統資訊為空值
        //            if (string.IsNullOrEmpty(_systemInfo))
        //            {
        //                /*
        //                 * 1.GetCpuId().ToUpper():獲取CPU的ID資訊(序列號),並轉成大寫
        //                 * 2.GetMotherBoardId().ToUpper():獲取主機板的ID資訊(序列號),並轉成大寫
        //                 * 3.GetHarDiskId().ToUpper():獲取硬碟的ID資訊(序列號),並轉成大寫
        //                 * 兩個資訊用"_"相連線,返回系統資訊字串。
        //                 */
        //                _systemInfo = GetCpuId().ToUpper() + "_" + GetMotherBoardId().ToUpper() + "_" + GetHardDiskId().ToUpper();
        //            }
        //            return _systemInfo;
        //        }
        //        catch
        //        {
        //            MessageBox.Show("機器碼序列號獲取失敗!");
        //            return null;
        //        }
                
        //    }
        //}

        ///// <summary>
        ///// 獲取CPU ID資訊
        ///// </summary>
        ///// <returns>返回獲取CPU ID</returns>
        //private static string GetCpuId()
        //{
        //    //傳入"Win32_Processor"可獲得CPU處理器資訊
        //    ManagementObjectCollection instances = new ManagementClass("Win32_Processor").GetInstances();

        //    string str = (string)null;

        //    //
        //    using (ManagementObjectCollection.ManagementObjectEnumerator enumerator = instances.GetEnumerator())
        //    {
        //        if (enumerator.MoveNext())
        //            str = enumerator.Current.Properties["ProcessorId"].Value.ToString();
        //    }
        //    return str;
        //}

        ///// <summary>
        ///// 獲取硬碟ID資訊
        ///// </summary>
        ///// <returns>返回硬碟ID資訊</returns>
        //private static string GetHardDiskId()
        //{
        //    ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia");
        //    string str = (string)null;
        //    foreach (ManagementBaseObject managementBaseObject in managementObjectSearcher.Get())
        //        str = managementBaseObject["SerialNumber"].ToString().Trim();
        //    return str;
        //}

        ///// <summary>
        ///// 獲取主機板資訊
        ///// </summary>
        ///// <returns>返回主機板資訊</returns>
        //private static string GetMotherBoardId()
        //{
        //    //
        //    ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher("SELECT SerialNumber FROM Win32_BaseBoard");
        //    string str = string.Empty;
        //    using (ManagementObjectCollection.ManagementObjectEnumerator enumerator = managementObjectSearcher.Get().GetEnumerator())
        //    {
        //        if (enumerator.MoveNext())
        //        {
        //            object obj = enumerator.Current["SerialNumber"];
        //            if (obj != null)
        //                str = obj.ToString();
        //        }
        //    }
        //    return str;
        //}
        //#endregion

        #region 登錄檔清理
        /// <summary>
        /// 登錄檔清理
        /// </summary>
        /// <returns>返回登錄檔清理結果</returns>
        private bool regeditWrite()
        {
            DateTime fromDate;
            DateTime toDate;

            fromDate = DateTime.Parse(fromDateTime);
            toDate = DateTime.Parse(toDateTime);

            try
            {
                using (RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("SOFTWARE\\PrivateCMW\\TimeLimitKey", true))
                {
                    //如果登錄檔存在,就刪除登錄檔
                    if (registryKey != null)
                    {
                        //using (RegistryKey registryCreate = Registry.CurrentUser.CreateSubKey("SOFTWARE\\PrivateCMW\\TimeLimitKey"))
                        //{
                        //    //寫入許可開始時間
                        //    registryCreate.SetValue("Start", (object)fromDate.ToString());
                        //    //寫入許可結束時間
                        //    registryCreate.SetValue("End", (object)toDate.ToShortDateString());
                        //}
                        //return true;
                        try
                        {
                            RegistryKey registryDelete = Registry.CurrentUser;
                            registryDelete.DeleteSubKey("SOFTWARE\\PrivateCMW\\TimeLimitKey", true);
                            registryDelete.Close();
                        }
                        catch
                        {
                            MessageBox.Show("登錄檔清理失敗!");
                            return false;
                        }
                        //using (RegistryKey registryCreate = Registry.CurrentUser.CreateSubKey("SOFTWARE\\PrivateCMW\\TimeLimitKey"))
                        //{
                        //    //寫入許可開始時間
                        //    registryCreate.SetValue("Start", (object)fromDate.ToString());
                        //    //寫入許可結束時間
                        //    registryCreate.SetValue("End", (object)toDate.ToShortDateString());
                        //}
                    }

                    ////如果存在就清理並建立新的登錄檔
                    //else
                    //{
                        
                    //}
                }
                return true;
            }
            catch
            {
                MessageBox.Show("登錄檔清理失敗!");
                return false;
            }
        }
        #endregion

        #region 許可檔案寫入
        /// <summary>
        /// 許可檔案寫入
        /// </summary>
        /// <param name="licenseFilePath">許可檔案路徑</param>
        /// <param name="keyCode">金鑰許可</param>
        /// <param name="timeCode">時間許可</param>
        /// <returns>返回許可檔案寫入結果</returns>
        private bool licenseWrite(string licenseFilePath, string keyCode, string timeCode)
        {
            try
            {
                if (!File.Exists(licenseFilePath))
                {
                    using (FileStream fileStream = new FileStream(licenseFilePath, FileMode.Create, FileAccess.Write))
                    {
                        using (StreamWriter streamWriter = new StreamWriter((Stream)fileStream, Encoding.Default))
                        {
                            streamWriter.WriteLine(keyCode);
                            streamWriter.WriteLine(timeCode);
                        }
                    }
                    return true;
                }
                else
                {
                    using (FileStream fileStream = new FileStream(licenseFilePath, FileMode.Open, FileAccess.Write))
                    {
                        using (StreamWriter streamWriter = new StreamWriter((Stream)fileStream, Encoding.Default))
                        {
                            streamWriter.WriteLine(keyCode);
                            streamWriter.WriteLine(timeCode);
                        }
                    }
                    return true;
                }
            }
            catch
            {
                MessageBox.Show("許可檔案寫入失敗!");
                return false;
            }
        }
        #endregion
        #endregion

        #region 執行生成許可檔案
        /// <summary>
        /// 生成註冊碼
        /// </summary>
        public void hackExcute()
        {
            /* 許可驗證步驟:
             *  1.許可檔案過濾
             *  2.許可檔案讀取
             *  3.登錄檔驗證(許可時間)
             *  4.加密演算法驗證許可檔案
             */

            //反向生成註冊碼
            // 1.許可過濾(存在、合法[.lic結尾]、不為空[文字內容])
            if (fromDateTime == "" || toDateTime == "" || (fromDateTime == "" && toDateTime == ""))
            {
                MessageBox.Show("時間許可不能為空!");
                return;
            }
            // 2.許可寫入
            //需要進行私鑰簽名的機器序列號資料
            //byte[] signature = ByteConvertor.GetBytes(SystemInfo);

            byte[] sys = Convert.FromBase64String(_sysinfo);

            //獲得第一行的許可註冊碼(經過RSA不對稱演算法私鑰簽名和Base64加密的機器碼資訊)
            keyLicenseCode = privateKeySignature(sys, privateKey);
            //獲得第二行的許可註冊嗎(經過Base64加密的時間組合資訊)
            timeLicenseCode = timeLicense();

            // 3.註冊許可
            //對登錄檔進行清理,並註冊新的許可
            bool regeditControllder = regeditWrite();

            //返回結果
            //if (regeditControllder)
            //    MessageBox.Show("登錄檔清理成功!");
        }

        /// <summary>
        /// 生成許可檔案
        /// </summary>
        /// <returns>返回生成結果</returns>
        public bool licenseFileGenerate()
        {
            try 
            {
                string licenseFilePath = licenseFileSave();
                //寫入許可檔案,返回結果
                bool licenseController = licenseWrite(licenseFilePath, keyLicenseCode, timeLicenseCode);
                return licenseController;
            }
            catch 
            {
                MessageBox.Show("寫入檔案失敗!");
                return false;
            }    
        }
        #endregion
    }
}

註冊碼驗證(解密模組):

using LicenseCommonUtil;
using Microsoft.Win32;
using System;
using System.IO;
using System.Security.Cryptography;

namespace LicenseClient
{
  public sealed class LicenseClient
  {
    public static bool CheckLicense(string licenseFilePath, out string message)
    {
        const string PublicKey = "<RSAKeyValue><Modulus>r+Fknz/UEsPyB+rOJpRt6BLPUnPvYFEAuXFtL6x23NI7LrUf+Xvcfo1iPMMJruOdNPs+wYNpxNy1166n5mRuSLn7EPbt1aumfCmtgq150NDWWdmx1y5rHNGFu9sUSUm+EgNEgVNbrjTTq8ru7ZJU2X5CLuLMYevuXwBaLZoS8kk=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

        try
        {
            message = "";

            #region 許可過濾(不存在、不合法、空)
            if (!File.Exists(licenseFilePath))
            {
            message = "許可檔案不存在!";
            return false;
            }

            //.lic結尾的檔案
            Path.GetExtension(licenseFilePath).Trim().ToUpper();
            if (!Path.GetExtension(licenseFilePath).Trim().ToUpper().Equals(LicenseUtil.DefaultLicenseFileExtension.ToUpper()))
            {
                message = "指定的許可檔案不合法!";
                return false;
            }

            string s = LicenseUtil.ReadContentFromFile2(licenseFilePath);

            if (string.IsNullOrEmpty(s))
            {
                message = "許可內容為空!";
                return false;
            }
            #endregion

            #region 對許可解密獲取時間資訊(fromDate,toDate,lastDate)
            DateTime fromDate;
            DateTime toDate;
            DateTime lastDate;
            LicenseUtil.ReadDateTiFromFile(licenseFilePath, out fromDate, out toDate, out lastDate);
            #endregion

            #region 許可使用的登錄檔判斷
            bool flag1 = false; //登錄檔資訊控制器
            string str1 = "";
            string str2 = "";
            if (lastDate == fromDate) //如果起始時間等於最後時間
            {
                try
                {
                    //檢索 SOFTWARE\\PrivateCMW\\TimeLimitKey,是否在當前使用者的登錄檔中,不將寫訪問許可權應用於該項。
                    using (RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("SOFTWARE\\PrivateCMW\\TimeLimitKey", false))
                    {
                        //如果是空的話,登錄檔資訊控制值為true
                        if (registryKey == null)
                        {
                            flag1 = true;
                        }
                        else
                        {
                            //如果不為空,則檢索登錄檔中與指定名稱關聯的值
                            str1 = registryKey.GetValue("Start").ToString();
                            str2 = registryKey.GetValue("End").ToString();

                            //判斷兩個值中是否包含 fromDate 和 toDate 兩個值
                            //如果包含了這兩個值,則判斷許可已經使用
                            if (str1.Contains(fromDate.ToString()) && str2.Contains(toDate.ToShortDateString()))
                            {
                                message = "許可已使用!";
                                return false;
                            }
                            //如果不包含 fromDate 和 toDate ,則返回true
                            flag1 = true;
                        }
                    }
                }
                catch (Exception)
                {
                    message = "驗證登錄檔失敗";
                }
            }
            #endregion

            #region 許可使用的時間期限判斷
            /*
            * fromDate(授權許可開始的時間)
            * toDate(授權許可結束的時間)
            * lastDate(授權許可最後一次生效的時間)
            * 
            * DataTime.Now < lastData(現在的時間 小於 授權許可最後一次生效的時間)
            * lastDate < fromDate(授權許可最後一次生效的時間 小於 授權許可開始的時間)
            * lastDate > toDate(授權許可最後一次生效的時間 大於 授權許可結束的時間)
            * DateTime.Now < fromDate(現在的時間 小於 授權許可開始的時間)
            * DateTime.Now > toDate(現在的時間 大於 授權許可結束的時間)
            * 
            */
            if (DateTime.Now < lastDate || lastDate < fromDate || (lastDate > toDate || DateTime.Now < fromDate) || DateTime.Now > toDate)
            {
                message = "許可已經過期!";
                return false;
            }
            #endregion

            #region 加密演算法驗證許可檔案
            //建立一個 RSA不對稱加密解密演算法 物件
            RSACryptoServiceProvider cryptoServiceProvider = new RSACryptoServiceProvider();

            //XML字串中的金鑰資訊(包含公鑰或者包含公鑰和私鑰):
            //<RSAKeyValue><Modulus>uqYMs9AxuAfGsbVvo+ah8Z7c91qbYJ8ARbX/7585ZVH1Jl9V5ebnjUEv+cuMjDEYzMCbJujoKZbqSRD5X5f9I2b9lNhRBhvBNBJj6ntzYKYp7HxYGTOr5NQ+eqNUejPhv9+fGedNa1oe/KyyfvE//NshoUN/oxVvCMlBIgHS98s=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>

            /* PEM格式公鑰
                            -----BEGIN PUBLIC KEY-----
            MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6pgyz0DG4B8axtW+j5qHxntz3
            WptgnwBFtf/vnzllUfUmX1Xl5ueNQS/5y4yMMRjMwJsm6OgplupJEPlfl/0jZv2U
            2FEGG8E0EmPqe3NgpinsfFgZM6vk1D56o1R6M+G/358Z501rWh78rLJ+8T/82yGh
            Q3+jFW8IyUEiAdL3ywIDAQAB
                            -----END PUBLIC KEY-----
            */
            //初始化 RSA不對稱加密解密演算法
            cryptoServiceProvider.FromXmlString(PublicKey);
        
            bool flag2;

            try
            {
                //將字元編碼轉為一個UTF-16格式的位元組序列
                byte[] bytes = LicenseUtil.ByteConvertor.GetBytes(LicenseUtil.SystemInfo);

                //開啟許可檔案,讀取第一行的祕鑰資訊(s),通過Base64演算法解密
                byte[] signature = Convert.FromBase64String(s);

                //傳入字元序列,SHA1加密演算法的雜湊值,Base64的解密資訊進行驗證
               /*
                * VerifyData(buffer, halg, signature)
                * 通過使用提供的公鑰計算簽名中的雜湊值,然後將其與提供的資料的雜湊值進行比較,從而驗證數字簽名是否有效。
                * 
                * 返回值:
                * 如果簽名有效,則為 true;否則為 false。
                * 
                * 引數:
                * buffer
                *    Type: Byte[]
                *     已簽名的資料。
                * 
                * halg
                *    Type: Object
                *    用於建立資料雜湊值的雜湊演算法的名稱。
                * 
                * signature
                *    Type: System.Byte[]
                *    要驗證的簽名資料。
                * 
                */
                flag2 = cryptoServiceProvider.VerifyData(bytes, (object)LicenseUtil.DefaultHashAlgorithm, signature);
            }
            catch
            {
                message = "許可檔案驗證錯誤!";
                return false;
            }
            #endregion

            #region 登錄檔和許可檔案更新
            //加密解密演算法驗證通過
            if (flag2)
            {
                //登錄檔驗證通過
                if (flag1)
                {
                    //檢索登錄檔 SOFTWARE\\PrivateCMW\\TimeLimitKey,並支援寫入操作
                    using (RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("SOFTWARE\\PrivateCMW\\TimeLimitKey", true))
                    {
                        //如果登錄檔為空
                        if (registryKey == null)
                        {
                            //建立登錄檔資訊
                            using (RegistryKey subKey = Registry.CurrentUser.CreateSubKey("SOFTWARE\\PrivateCMW\\TimeLimitKey"))
                            {
                                //寫入許可開始時間
                                subKey.SetValue("Start", (object)fromDate.ToString());
                                //寫入許可結束時間
                                subKey.SetValue("End", (object)toDate.ToShortDateString());
                            }
                        }

                        else
                        {
                            //如果不為空
                            //追加新的許可開始時間和結束時間
                            registryKey.SetValue("Start", (object)(str1 + ";" + fromDate.ToString()));
                            registryKey.SetValue("End", (object)(str2 + ";" + toDate.ToShortDateString()));
                        }
                    }
                }
                //
                LicenseUtil.UpdateDateToFile(licenseFilePath, DateTime.Now);
            }
            else
            {
                message = "許可檔案驗證不通過!";
            }
            return flag2;
            #endregion
        }  
        catch
        {
            message = "許可檔案可能被篡改!";
            return false;
        }
        
    }
  }
}

許可呼叫的功能模組:

using System;
using System.Collections.Generic;
using System.IO;
using System.Management;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;

namespace LicenseCommonUtil
{
  public static class LicenseUtil
  {
    private static string _systemInfo = string.Empty;

    public static Encoding ByteConvertor
    {
      get
      {
        return Encoding.Unicode;
      }
    }

    public static HashAlgorithm DefaultHashAlgorithm
    {
      get
      {
        return (HashAlgorithm) new SHA1CryptoServiceProvider();
      }
    }

    public static string DefaultLicenseFileExtension
    {
      get
      {
        return ".lic";
      }
    }

    public static string SystemInfo
    {
      get
      {
          //如果字串系統資訊為空值
          if (string.IsNullOrEmpty(LicenseUtil._systemInfo))
          {
              /*
               * 1.GetCpuId().ToUpper():獲取CPU的ID資訊(序列號),並轉成大寫
               * 2.GetMotherBoardId().ToUpper():
               * 
               * 
               */

              LicenseUtil._systemInfo = LicenseUtil.GetCpuId().ToUpper() + "_" + LicenseUtil.GetMotherBoardId().ToUpper() + "_" + LicenseUtil.GetHardDiskId().ToUpper();
          }
          return LicenseUtil._systemInfo;
      }
    }

    private static string GetCpuId()
    {
        //傳入"Win32_Processor"可獲得CPU處理器資訊
        ManagementObjectCollection instances = new ManagementClass("Win32_Processor").GetInstances();
        
        string str = (string) null;

        //
        using (ManagementObjectCollection.ManagementObjectEnumerator enumerator = instances.GetEnumerator())
        {
            if (enumerator.MoveNext())
                str = enumerator.Current.Properties["ProcessorId"].Value.ToString();
        }
        return str;
    }

    private static string GetHardDiskId()
    {
      ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia");
      string str = (string) null;
      foreach (ManagementBaseObject managementBaseObject in managementObjectSearcher.Get())
        str = managementBaseObject["SerialNumber"].ToString().Trim();
      return str;
    }

    private static string GetMotherBoardId()
    {
      //
      ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher("SELECT SerialNumber FROM Win32_BaseBoard");
      string str = string.Empty;
      using (ManagementObjectCollection.ManagementObjectEnumerator enumerator = managementObjectSearcher.Get().GetEnumerator())
      {
        if (enumerator.MoveNext())
        {
          object obj = enumerator.Current["SerialNumber"];
          if (obj != null)
            str = obj.ToString();
        }
      }
      return str;
    }

    public static void SaveFile(string fileContent, string defaultExtension, string filter)
    {
      SaveFileDialog saveFileDialog = new SaveFileDialog();
      saveFileDialog.AddExtension = true;
      saveFileDialog.DefaultExt = defaultExtension;
      saveFileDialog.Filter = filter;
      saveFileDialog.FileName = "licenseInfo";
      if (saveFileDialog.ShowDialog() != DialogResult.OK)
        return;
      using (FileStream fileStream = new FileStream(saveFileDialog.FileName, FileMode.Create, FileAccess.Write))
      {
        using (StreamWriter streamWriter = new StreamWriter((Stream) fileStream, Encoding.Default))
        {
          streamWriter.Write(fileContent);
          int num = (int) MessageBox.Show("檔案儲存成功!", "提示");
        }
      }
    }

    public static void SaveFile(string fileContent, string nyr, string defaultExtension, string filter)
    {
      SaveFileDialog saveFileDialog = new SaveFileDialog();
      saveFileDialog.AddExtension = true;
      saveFileDialog.DefaultExt = defaultExtension;
      saveFileDialog.Filter = filter;
      saveFileDialog.FileName = "license.lic";
      if (saveFileDialog.ShowDialog() != DialogResult.OK)
        return;
      using (FileStream fileStream = new FileStream(saveFileDialog.FileName, FileMode.Create, FileAccess.Write))
      {
        using (StreamWriter streamWriter = new StreamWriter((Stream) fileStream, Encoding.Default))
        {
          streamWriter.WriteLine(fileContent);
          streamWriter.WriteLine(nyr);
          int num = (int) MessageBox.Show("檔案儲存成功!", "提示");
        }
      }
    }

    public static void SaveFile(string fileContent, string nyr, string todate, string defaultExtension, string filter)
    {
      SaveFileDialog saveFileDialog = new SaveFileDialog();
      saveFileDialog.AddExtension = true;
      saveFileDialog.DefaultExt = defaultExtension;
      saveFileDialog.Filter = filter;
      saveFileDialog.FileName = "license.lic";
      if (saveFileDialog.ShowDialog() != DialogResult.OK)
        return;
      using (FileStream fileStream = new FileStream(saveFileDialog.FileName, FileMode.Create, FileAccess.Write))
      {
        using (StreamWriter streamWriter = new StreamWriter((Stream) fileStream, Encoding.Default))
        {
          streamWriter.WriteLine(fileContent);
          string str = Convert.ToBase64String(Encoding.Default.GetBytes(nyr + "$" + todate));
          streamWriter.WriteLine(str);
          int num = (int) MessageBox.Show("檔案儲存成功!", "提示");
        }
      }
    }

    public static string ReadContentFromFile(string filePath)
    {
      using (FileStream fileStream = new FileStream(filePath, FileMode.Open))
      {
        using (StreamReader streamReader = new StreamReader((Stream) fileStream, Encoding.Default))
          return streamReader.ReadToEnd();
      }
    }

    public static string ReadContentFromFile2(string filePath)
    {
      using (FileStream fileStream = new FileStream(filePath, FileMode.Open))
      {
        using (StreamReader streamReader = new StreamReader((Stream) fileStream, Encoding.Default))
          //返回第一行的許可資訊
          return streamReader.ReadLine();
      }
    }

    public static DateTime ReadDateTiFromFile(string filePath)
    {
      string s = string.Empty;
      string str1 = string.Empty;
      
      using (FileStream fileStream = new FileStream(filePath, FileMode.Open))
      {
        using (StreamReader streamReader = new StreamReader((Stream) fileStream, Encoding.Default))
        {
          string str2;
          do
          {
            str2 = streamReader.ReadLine();
            s = str2 ?? s;
          }
          while (str2 != null);
        }
      }
      return DateTime.Parse(s);
    }

    /// <summary>
    /// 從許可中讀取時間資訊
    /// </summary>
    /// <param name="filePath"></param>
    /// <param name="fromDate"></param>
    /// <param name="toDate"></param>
    /// <param name="lastDate"></param>
    public static void ReadDateTiFromFile(string filePath, out DateTime fromDate, out DateTime toDate, out DateTime lastDate)
    {
      List<string> list = new List<string>();
      using (FileStream fileStream = new FileStream(filePath, FileMode.Open)) //開啟檔案流
      {
         using (StreamReader streamReader = new StreamReader((Stream) fileStream, Encoding.Default)) //開啟檔案流讀取內容
         {
            //逐行遍歷檔案
            //如果行字串不為空,則繼續遍歷
            //每次讀取新的一行
            for (string str = streamReader.ReadLine(); !string.IsNullOrEmpty(str); str = streamReader.ReadLine())
            {
                //將每行的字串資訊新增到列表中儲存
                list.Add(str);
            }
         }
      }
      
      //將當前計算機的本地時間賦值給三個變數
      fromDate = toDate = lastDate = DateTime.Now;

      //獲取到列表的第二個索引對應的值
      string s = list[1];

      //如果第二個索引對應的值為空,則返回空值
      if (string.IsNullOrEmpty(s))
        return;
      
      //建立字串陣列
      /* 傳入第二行的值
       * 從Base64加密演算法解密再轉換成字串
       * 通過'$'符號對字串進行分割,得到字串陣列,並且返回值不包含空字串
       * 得到的三個值分別為 fromDate、toDate、lastDate(如果字串陣列的長度大於2)
       * 通過out引數傳出
       */
      string[] strArray = Encoding.Default.GetString(Convert.FromBase64String(s)).Split(new char[1]{'$'}, StringSplitOptions.RemoveEmptyEntries);

      //分別對應索引值進行賦值
      fromDate = DateTime.Parse(strArray[0]);
      toDate = DateTime.Parse(strArray[1]);
      if (strArray.Length > 2)
        lastDate = DateTime.Parse(strArray[2]);
      else
        lastDate = fromDate;
    }

    public static void UpdateDateToFile(string filePath, DateTime nowDate)
    {
      List<string> list = new List<string>();
      //只讀
      using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
      {
        using (StreamReader streamReader = new StreamReader((Stream) fileStream, Encoding.Default))
        {
            //如果檔案行不為空,逐行遍歷,並新增到列表中
            for (string str = streamReader.ReadLine(); !string.IsNullOrEmpty(str); str = streamReader.ReadLine())
            {
                list.Add(str);
            }
        }
      }

      
      DateTime dateTime1;
      DateTime dateTime2 = dateTime1 = DateTime.Now;
      
      //許可第二行的內容
      string s = list[1];

      //如果許可第二行不為空
      if (!string.IsNullOrEmpty(s))
      {
        //建立字串陣列
          /* 傳入第二行的值
           * 從Base64加密演算法解密再轉換成字串
           * 通過'$'符號對字串進行分割,得到字串陣列,並且返回值不包含空字串
           */
          string[] strArray = Encoding.Default.GetString(Convert.FromBase64String(s)).Split(new char[1]
        {
          '$'
        }, StringSplitOptions.RemoveEmptyEntries);
          
        //dataTime2是通過Base64解密的通過'$'進行分割得到的第一行時間資料
        dateTime2 = DateTime.Parse(strArray[0]);

        //dataTime1
        dateTime1 = DateTime.Parse(strArray[1]);
      }
    
      //支援寫入
      using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Write))
      {
        using (StreamWriter streamWriter = new StreamWriter((Stream) fileStream, Encoding.Default))
        {
          //寫入許可檔案的第一行內容
          streamWriter.WriteLine(list[0]);

          /* 通過Base64加密演算法進行加密
           * 傳入引數型別:位元組序列
           * 引數:
           *    1.fromDate
           *    2.toDate
           *    3.lastDate
           * 
           */
          string str = Convert.ToBase64String(Encoding.Default.GetBytes(dateTime2.ToString() + (object)"$" + dateTime1.ToShortDateString() + (object)"$" + (object)nowDate.ToString()));
          streamWriter.WriteLine(str);
        }
      }
    }

    public static string GetStringFromByte(byte[] datas)
    {
      if (datas == null)
        return string.Empty;
      string str = string.Empty;
      foreach (byte num in datas)
        str = str + (object) num + "_";
      return str;
    }
  }
}

 


6.Conclusion

 

作為一個GIS開發者,我其實想當個房東,每個月開著瑪莎拉蒂去收收租多好,想著想著,X突然閃現到我身後的絕對領域,準備gank我,然而我根本是毫無破綻,雖然眼神迷離但是手一刻也沒有停歇的敲擊著黑軸機械,大眼珠子已經貼在了螢幕上,隨著指尖的高潮,這個專案破解算是告一段落了,美女新同事的微信也吹了。

GitHub地址:https://github.com/Asada2142/.Net_EncryptionAnddecryption