[C#] [安全] [加密解密] 逆向某GIS軟體驗證函式後生成的加密解密演算法
目錄
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