目錄
NLog日志框架使用探究-1
NLog日志框架使用探究-2
科學使用Log4View2
前言
這個標題很低調吧,但是既然你點進來,那么接下來的干貨是屬於你的。
不想成為黑客的程序員不是好程序員。在上一篇《NLog日志框架使用探究-2》文章提到了Log4View2工具有30天的試用期,超過試用期許多功能就被限制,比如不能使用數據庫加載。那么我們如何科學使用它呢?
本篇文章涉及到反編譯技術、對稱加密技術、IL中間語言等技術。掌握了這些技術之后你會發現原來自己也能更加科學的使用軟件。
接下來的內容僅供個人學習使用,任何人不得用於商業用途或用於非法途徑,一切后果本人概不負責。
科學使用
我們可以使用dnspy、ilspy以及reflector對.net程序進行反編譯。Log4View2就是純.net開發的項目。
reflector是收費的,也需要科學使用。
ILSpy是開源的.NET程序集瀏覽器和編譯器。
dnSpy是一個調試器和.NET程序集編輯器。即使沒有任何可用的源代碼,也可以使用它來編輯和調試程序集。
dnspy也是基於ILSpy的反編譯引擎,在它基礎上增加了豐富的功能,甚至可以直接修改源代碼。首先我們通過dyspy看看相關注冊的源碼,直接在安裝路徑找到Log4View.exe文件拖入到dbSpy內。
找到licensing相關的模塊(命名很友好)
在LicenseMgr可以找到ApplyLicense
方法,它會調用CheckForTrial();
檢查過期時間。
在檢查過期時間后回調用SetLicenseInformation()
和SetLicensedFeatures()
SetLicenseInformation
方法是用於從License中獲取一些注冊信息。
Ctrl+鼠標左鍵可以跳轉到方法
private void SetLicenseInformation()
{
base.LicensedTo = null;
if (this.License == null)
{
return;
}
Log4ViewProductProvider log4ViewProductProvider = this.ProductProvider as Log4ViewProductProvider;
this.ProductInfo = ((log4ViewProductProvider != null) ? log4ViewProductProvider.GetProductName(this.License.ProductReferenceId) : null);
if (!this.License.RegisteredName.IsNullOrEmpty() && !this.License.RegisteredCompany.IsNullOrEmpty())
{
base.LicensedTo = this.License.RegisteredName + "\n" + this.License.RegisteredCompany;
return;
}
if (!this.License.RegisteredName.IsNullOrEmpty())
{
base.LicensedTo = this.License.RegisteredName;
return;
}
if (!this.License.RegisteredCompany.IsNullOrEmpty())
{
base.LicensedTo = this.License.RegisteredCompany;
}
}
SetLicensedFeatures
則是根據是否注冊,是否試用等信息決定產品功能限制。若注冊則根據注冊的信息取配置,若是試用,則最大限度開放使用,否則只允許一個接收器,比如你使用網絡接收器就不能使用文件接收器,且一些功能會被限制使用。
如圖Logboxx和Database功能被禁用。
private void SetLicensedFeatures()
{
if (base.IsRegistered)
{
LicenseMgr.Logger.Info(string.Format("Log4View is licensed with {0}", this.License.LicenseKey));
Log4ViewFeatureAdapter log4ViewFeatureAdapter = new Log4ViewFeatureAdapter(this.License.Features);
this.MultipleInstances = log4ViewFeatureAdapter.MultipleInstances;
this.MaxReceivers = log4ViewFeatureAdapter.MaxReceivers;
this.FileReadFilterEnabled = log4ViewFeatureAdapter.FileReadFilterEnabled;
this.DatabaseReceiverEnabled = log4ViewFeatureAdapter.DatabaseReceiverEnabled;
this.ExportEnabled = log4ViewFeatureAdapter.ExportEnabled;
this.AnnotationsEnabled = log4ViewFeatureAdapter.AnnotationsEnabled;
this.ChartEnabled = log4ViewFeatureAdapter.ChartEnabled;
return;
}
if (this.IsTrial)
{
this.MaxReceivers = 250;
this.FileReadFilterEnabled = (this.MultipleInstances = (this.DatabaseReceiverEnabled = (this.ExportEnabled = (this.AnnotationsEnabled = (this.ChartEnabled = true)))));
return;
}
this.MaxReceivers = 1;
this.FileReadFilterEnabled = (this.MultipleInstances = (this.DatabaseReceiverEnabled = (this.ExportEnabled = (this.AnnotationsEnabled = (this.ChartEnabled = false)))));
}
我們知道了試用所有功能都可以使用,試用又是有試用期的,那么只要我們調大試用期即可。
IsTrial
是否試用。
private void CheckForTrial()
{
this.IsTrial = false;
if (this.License != null)
{
return;
}
DateTime? dateTime = base.CheckTrialDate();
if (dateTime != null && dateTime.Value > DateTime.Now)
{
this.TrialExpireTime = dateTime.Value;
LicenseMgr.Logger.Info(string.Format("Log4View License expires on {0}", this.TrialExpireTime));
this.IsTrial = true;
}
}
試用期判斷,首先從_licenseStore
讀取日期參數,然后進行校驗。
protected DateTime? CheckTrialDate()
{
Tuple<DateTime, DateTime> tuple = this._licenseStore.CheckTrialDate();
if (tuple == null)
{
return null;
}
DateTime item = tuple.Item1;
DateTime dateTime = tuple.Item2;
if (item > DateTime.Now)
{
return null;
}
if (dateTime < new DateTime(2007, 8, 15, 16, 58, 0))
{
dateTime = DateTime.Now.AddDays(30.0);
}
this._licenseStore.SaveTrialDate(dateTime);
return new DateTime?(dateTime);
}
我們可以直接看保存的時間存放路徑。首先將當前時間和過期時間拼湊后加密,然后存儲到文件名為FodszqufeUsjbmEbuf
的文件中。文件路徑則存到了_storagePath
字段中
public void SaveTrialDate(DateTime expireDate)
{
string value = LicenseStore.EncryptTrialDate(string.Format(CultureInfo.InvariantCulture, "{0}#{1}", DateTime.Now.ToString(this._trialFormat), expireDate.ToString(this._trialFormat)));
using (StreamWriter streamWriter = new StreamWriter(Path.Combine(this._storagePath, "FodszqufeUsjbmEbuf"), false))
{
streamWriter.Write(value);
}
}
直接Ctrl+F
查找一下該變量,可以看到在LicenseStore
初始化時會賦值。
public LicenseStore(string productFamilyId, SigningSerializer serializer)
{
this._serializer = serializer;
string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
this._storagePath = Path.Combine(folderPath, "Prolic", productFamilyId);
}
Environment.SpecialFolder.CommonApplicationData
指向的是系統盤的ProgramData
目錄下,我的系統盤是C盤,則為C:\ProgramData\
,在該目錄下可以找到Log4View的日期保存的文件。
我們獲取到了文件內容,可以看下NLog是如何加解密的。
protected DateTime? CheckTrialDate()
{
Tuple<DateTime, DateTime> tuple = this._licenseStore.CheckTrialDate();
...
}
public Tuple<DateTime, DateTime> CheckTrialDate()
{
string text = this.ReadTrialDate();
if (string.IsNullOrEmpty(text))
{
return null;
}
string text2 = LicenseStore.DecryptTrialDate(text);
...
}
private static string DecryptTrialDate(string cip)
{
if (cip == null)
{
return null;
}
RijndaelManaged rijndaelManaged = null;
MemoryStream memoryStream = null;
CryptoStream cryptoStream = null;
StreamReader streamReader = null;
string result = null;
try
{
rijndaelManaged = new RijndaelManaged
{
IV = Convert.FromBase64String("X9w3vURHpNUhpU+kICttoQ=="),
Key = Convert.FromBase64String("vhMit23SLc56FN8oylrOUy8trs0I2z7piFrh4vnfx+s=")
};
ICryptoTransform transform = rijndaelManaged.CreateDecryptor(rijndaelManaged.Key, rijndaelManaged.IV);
memoryStream = new MemoryStream(Convert.FromBase64String(cip));
cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Read);
streamReader = new StreamReader(cryptoStream);
result = streamReader.ReadToEnd();
}
...
return result;
}
可以看出來它使用的是3DES算法。Key和IV都有了。對於RijndaelManaged
我個人不是很了解它,因此還需要看以下它默認的分組模式和填充模式。
public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV)
{
return this.NewEncryptor(rgbKey, this.ModeValue, rgbIV, this.FeedbackSizeValue, RijndaelManagedTransformMode.Encrypt);
}
private ICryptoTransform NewEncryptor(byte[] rgbKey, CipherMode mode, byte[] rgbIV, int feedbackSize, RijndaelManagedTransformMode encryptMode)
{
if (rgbKey == null)
{
rgbKey = Utils.GenerateRandom(this.KeySizeValue / 8);
}
if (rgbIV == null)
{
rgbIV = Utils.GenerateRandom(this.BlockSizeValue / 8);
}
return new RijndaelManagedTransform(rgbKey, mode, rgbIV, this.BlockSizeValue, feedbackSize, this.PaddingValue, encryptMode);
}
查找一下ModeValue是哪里賦值的,選中this.ModeValue
右鍵點擊分析
看下哪里被賦值的
protected SymmetricAlgorithm()
{
this.ModeValue = CipherMode.CBC;
this.PaddingValue = PaddingMode.PKCS7;
}
那么聰明的你知道怎么做了嗎?比如把超時時間定義到2999年,這是不是很科學呢?
將加密后的文件替換原文件后重啟,可以看到過期時間變為了2999年
什么?你懶得加解密,想讓我直接給?
拿去吧Rtii82/K20ex7W41cuLLTHBq9qGA/VrVEf/zv7IoPUQL8ZUA8fikC3Saeh5oZUwcTUI+0xdX08OXGXqQwJP+eA==
替換后
想知道為什么?自己去解密一下吧。
編輯和調試程序集
本篇文章實際已經結束了,但是上一篇有人感謝我如此熱心還教人破解。
我可不會破解!!!
但是為了讓大家學到更多的使用技能,還是在講一些干貨吧。
前面提到了DnSpy是一個調試器和.NET程序集編輯器。即使沒有任何可用的源代碼,也可以使用它來編輯和調試程序集。
調試程序集
眼尖的同學可能一開始就看到第一張圖綠色的啟動按鈕。
就像在VS中調試一下,我們打上斷點直接啟動。
調試方法和在VS中一樣,快捷鍵也一樣,F10
逐過程或F11
逐語句。
編輯程序集
前面我們科學使用還是挺麻煩的,找了半天代碼,還要了解加密解密算法。
我們知道只要我們是試用,就可以最大程度的使用軟件。那我們直接可以修改源碼this.IsTrial = false
改為this.IsTrial = true
然后就返回即可。
private void CheckForTrial()
{
this.IsTrial = false;
if (this.License != null)
{
return;
}
DateTime? dateTime = base.CheckTrialDate();
if (dateTime != null && dateTime.Value > DateTime.Now)
{
this.TrialExpireTime = dateTime.Value;
LicenseMgr.Logger.Info(string.Format("Log4View License expires on {0}", this.TrialExpireTime));
this.IsTrial = true;
}
}
直接在需要修改源碼的地方右鍵選擇編輯IL指令。
可以看到首先通過ldc.i4.0
將0(false)加載到棧,然后調用set_IsTrial
賦值。
我們可以將ldc.i4.0
改為ldc.i4.1
賦值為true。然后將ldarg.0
改為ret
返回。我們也可以直接新增指令。
本篇的重點不是講如何學習IL,大家可以到網上搜一下,一搜一大把。
然后點擊右下角確定保存,可以發現編譯器自動優化了代碼。
剛才只是保存到內存中,最后需要保存到文件中。
需要以管理員權限運行DnSpy,否則無法保存。
DnSpy還可以編輯方法。
但是我自己試了下無法編譯保存,感興趣的同學可以自己試試。
結語
本篇文章涉及到了反編譯、3DES對稱加密、IL語言等技術。同時使用DnSpy可以非常方便的修改IL,修改之后能干什么呢?大家自己發揮吧。
實際上DnSpy修改IL背后幫我們做了許多事情。這些后面的原理都需要我們花更多的時間去學習。最后還是呼吁大家尊重版權,不要傳播盜版軟件,不要用於非法用途。
最后的最后如果此文對你有幫助的話微信掃一掃關注訂閱號傑哥技術分享
推薦文獻
微信掃一掃二維碼關注訂閱號傑哥技術分享
出處:本文地址:https://www.cnblogs.com/Jack-Blog/p/11976252.html
作者:傑哥很忙
本文使用「CC BY 4.0」創作共享協議。歡迎轉載,請在明顯位置給出出處及鏈接。