记录下Apache Logs Viewer的破解笔记

拿到软件先查壳,发现是.net的,混淆过

de4dot去混淆后

打开看看限制的功能和输入注册码那提示什么

随便输个,看看报错

关键词unlock code

去混淆后的软件载入dnspy,全局搜下看看

搜到了2个主窗体的,直接看unlockCodeToolStripMenuItem_Click方法

// Token: 0x060001E4 RID: 484 RVA: 0x0001E230 File Offset: 0x0001C430
private void unlockCodeToolStripMenuItem_Click(object sender, EventArgs e)
{
string text = this.prefs_0.Key;
if (!InputForm.smethod_3("Apache Logs Viewer | " + Class96.smethod_264(), Class96.smethod_143(), ref text))
{
return;
}
if (text != null)
{
text = text.Trim();
}
if (string.IsNullOrEmpty(text))//判断是否为空
{
this.prefs_0.Key = string.Empty;
this.bool_0 = false;
Prefs.Save(Prefs.Filename, this.prefs_0);
this.method_2(this.bool_0);
return;
}
try
{
this.Cursor = Cursors.WaitCursor;
if (text.Length < 22)//判断输入的字符串长度
{
throw new ApplicationException("Failed");
}
if (Class2.smethod_1(Class2.smethod_0(text)))//判断注册码的关键点
{
this.prefs_0.Key = text;
this.method_23();//联网返回信息
Prefs.Save(Prefs.Filename, this.prefs_0);//保存注册码为文件
this.Cursor = Cursors.Default;
this.lbStatusStripNotify.Text = Class96.smethod_253() + " Apache Logs Viewer.";
MessageBox.Show(this, Class96.smethod_253() + " Apache Logs Viewer.", "Apache Logs Viewer", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);//返回感谢注册
this.bool_0 = true;//返回真
}
else
{
MessageBox.Show(this, Class96.smethod_117(), "Apache Logs Viewer | " + Class96.smethod_264(), MessageBoxButtons.OK, MessageBoxIcon.Hand);//返回激活码错误
this.bool_0 = false;//返回假
}
}
catch (Exception)
{
this.Cursor = Cursors.Default;
MessageBox.Show(this, Class96.smethod_90(), "Apache Logs Viewer | " + Class96.smethod_264(), MessageBoxButtons.OK, MessageBoxIcon.Hand);
this.bool_0 = false;
}
finally
{
this.Cursor = Cursors.Default;
}
this.method_2(this.bool_0);
}

暴力破解

直接将代码修改为

// Token: 0x060001E4 RID: 484 RVA: 0x0001E230 File Offset: 0x0001C430
private void unlockCodeToolStripMenuItem_Click(object sender, EventArgs e)
{
string text = this.prefs_0.Key;
if (!InputForm.smethod_3("Apache Logs Viewer | " + Class96.smethod_264(), Class96.smethod_143(), ref text))
{
return;
}
this.prefs_0.Key = text;
Prefs.Save(Prefs.Filename, this.prefs_0);
this.Cursor = Cursors.Default;
this.lbStatusStripNotify.Text = Class96.smethod_253() + " Apache Logs Viewer.";
MessageBox.Show(this, Class96.smethod_253() + " Apache Logs Viewer.", "Apache Logs Viewer", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
this.bool_0 = true;
this.method_2(this.bool_0);
}

然后保存,这样不输入或输入任意字符都能注册了

但是这样有个问题,下次再重开还得再注册遍,推测有个重启校验的暗桩

重启软件后

再看看软件启动时的动作,定位到MainForm_Load方法

其中发现bool_0这个变量是用来对注册进行校验的,细看这个方法后找到了重启校验的地方

private void MainForm_Load(object sender, EventArgs e)
{
try
{
if (Class95.bool_2)
{
Prefs.DeletePrefs();
}
ALV.Common.Debug.Info("Started..");
Prefs prefs = Prefs.Load(Prefs.Filename);
if (string.IsNullOrEmpty(prefs.InstallID))
{
prefs.InstallID = Guid.NewGuid().ToString();
}
if (prefs.sizex > 10)
{
base.Width = prefs.sizex;
}
if (prefs.sizey > 10)
{
base.Height = prefs.sizey;
}
if (prefs.maximised)
{
base.WindowState = FormWindowState.Maximized;
}
if (prefs.x >= 0 && prefs.y >= 0)
{
base.Location = new Point(prefs.x, prefs.y);
}
this.prefs_0 = prefs;
if (this.prefs_0.logColumns == null || this.prefs_0.logColumns.Count <= 0)
{
this.prefs_0.logColumns = LogColumn.ResetLogColumns();
}
ALV.Common.Debug.Info("Loading Custom Columns");
this.prefsColumns_0 = PrefsColumns.Load(PrefsColumns.Filename);
this.method_42();
DummyListView.prefs = prefs;
ALV.Common.Debug.Info("Loading IP DB");
this.ip2Country_0 = new IP2Country(true, this.prefs_0.useCity);
this.parser_0 = new Parser(this.ip2Country_0);
this.parser_0.ParseCustomColumns = this.prefs_0.parseCustomColumns;
Statistics.int_0 = this.prefs_0.topNumber;
try
{
if (prefs.monitorAuto)
{
ALV.Common.Debug.Info("Opening Logs...");
foreach (LoggerInfo loggerInfo in prefs.logsToView)
{
if (loggerInfo.Highlight != null)
{
this.method_48(loggerInfo.Highlight, true);
}
try
{
this.method_6(loggerInfo);
if (Class95.bool_0)
{
GC.Collect();
}
}
catch
{
}
}
}
if (Class95.list_0 != null)
{
foreach (string text in Class95.list_0)
{
try
{
bool flag = this.parser_0.IsErrorLog(text);
this.method_4(text, !flag, false);
if (Class95.bool_0)
{
GC.Collect();
}
}
catch
{
}
}
}
}
catch (Exception)
{
MessageBox.Show(Class96.smethod_247());
}
if (this.prefs_0.selTab >= 0 && this.tabControl1.TabPages.Count > this.prefs_0.selTab)
{
this.tabControl1.SelectedTabPageIndex = this.prefs_0.selTab;
}
try
{
if (!string.IsNullOrEmpty(this.prefs_0.Key))//判断本地保存的激活码是否为空
{
string string_ = Class2.smethod_0(this.prefs_0.Key);
this.bool_0 = Class2.smethod_1(string_);
}
}
catch (Exception)
{
this.bool_0 = false;
}
try
{
if (IsStoreApp.IsWindowsStoreApp)//判断是否为winstore下载的,如果是就免去验证
{
this.bool_0 = true;
this.bool_1 = true;
this.method_0();
}
}
catch
{
}
if (!this.bool_0)//bool_0这个变量很重要
{
this.lbStatusStripNotify.Text = Class96.smethod_270() + " Apache Logs Viewer..." + Class96.smethod_67();
this.method_2(false);
}
else
{
this.lbStatusStripNotify.Text = Class96.smethod_270() + " Apache Logs Viewer";
this.method_2(true);
}
ALV.Common.Debug.Info("Apply L...");
this.method_44(false);
this.method_1();
ALV.Common.Debug.Info("Apply L Done");
}
catch (Exception ex)
{
ALV.Common.Debug.Error("Error Load: " + ex.Message);
if (this.prefs_0 == null)
{
this.prefs_0 = new Prefs();
}
}
finally
{
LoadForm.smethod_1();
}
if (this.prefs_0.checkupdates)
{
new Thread(new ThreadStart(this.method_25)).Start();
}
if (!this.bool_1)
{
if (File.Exists(Prefs.Filename + ".chk"))
{
ALV.Common.Debug.Info("Config Check");
if (File.ReadAllText(Prefs.Filename + ".chk") == "0")
{
MessageBox.Show(this, Class96.smethod_53(), "Apache Logs Viewer", MessageBoxButtons.OK, MessageBoxIcon.Hand);
this.prefs_0.Key = string.Empty;
this.unlockCodeToolStripMenuItem_Click(this, null);
if (File.Exists(Prefs.Filename + ".chk") && this.bool_0)
{
Application.Exit();
}
}
else if (this.bool_0)
{
new Thread(new ThreadStart(this.method_23)).Start();
}
}
}
else if (this.bool_0)
{
new Thread(new ThreadStart(this.method_23)).Start();
}
this.timer_0.Interval = this.prefs_0.refreshtimeout * 1000;
this.timer_0.Enabled = true;
this.timer_0.Start();
GC.Collect();
if (base.Width <= 10)
{
base.Width = 668;
}
if (base.Height <= 10)
{
base.Height = 460;
}
this.menuStrip1.Visible = true;
this.toolStripBtnScroll.CheckState = (this.prefs_0.scroll_last ? CheckState.Checked : CheckState.Unchecked);
this.toolStripBtnRefresh.CheckState = (this.prefs_0.refreshAuto ? CheckState.Checked : CheckState.Unchecked);
ALV.Common.Debug.Info("Started..OK");
}

method_23method_24方法用作反馈winstore版本

public void method_23()
{
if (this.bool_1)
{
this.method_24("winStore");
return;
}
this.method_24(this.prefs_0.Key);
}
public void method_24(string string_0)
{
try
{
WebClient webClient = new WebClient();
try
{
if (webClient.DownloadString("http://www.apacheviewer.com/k/c5.php?k=" + string_0 + "&id=" + this.prefs_0.InstallID).StartsWith("failed", StringComparison.OrdinalIgnoreCase))
{
try
{
using (StreamWriter streamWriter = File.CreateText(Prefs.Filename + ".chk"))
{
streamWriter.Write("0");
}
}
catch
{
}
base.Invoke(new MainForm.Delegate0(this.method_26), new object[]
{
5,
string.Empty
});
}
else
{
try
{
if (File.Exists(Prefs.Filename + ".chk"))
{
File.Delete(Prefs.Filename + ".chk");
}
}
catch
{
}
}
}
finally
{
((IDisposable)webClient).Dispose();
}
}
catch (Exception)
{
}
}

method_25method_26用作检测更新

public void method_25()
{
try
{
string text = null;
WebClient webClient = new WebClient();
try
{
if (this.bool_0)
{
text = webClient.DownloadString(string.Concat(new object[]
{
"http://www.apacheviewer.com/currentver5.php?v=",
About.double_0,
"&r1=U&id=",
this.prefs_0.InstallID
}));
}
else
{
text = webClient.DownloadString(string.Concat(new object[]
{
"http://www.apacheviewer.com/currentver5.php?v=",
About.double_0,
"&r1=F&id=",
this.prefs_0.InstallID
}));
}
}
finally
{
((IDisposable)webClient).Dispose();
}
if (!string.IsNullOrEmpty(text))
{
double num = 0.0;
double.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out num);
if (num > 0.0)
{
if (num > About.double_0)
{
if (num >= (double)About.int_0)
{
WebClient webClient2 = new WebClient();
try
{
text = webClient2.DownloadString("http://www.apacheviewer.com/upgrademsg.php");
}
finally
{
((IDisposable)webClient2).Dispose();
}
base.Invoke(new MainForm.Delegate0(this.method_26), new object[]
{
2,
text.Trim()
});
}
else
{
base.Invoke(new MainForm.Delegate0(this.method_26), new object[]
{
1,
text.Trim()
});
}
}
}
}
}
catch (Exception)
{
}
}
private void method_26(int int_0, string string_0)
{
switch (int_0)
{
case 1:
if (MessageBox.Show(string.Concat(new string[]
{
Class96.smethod_42(),
" v",
string_0,
" ",
Class96.smethod_93(),
".\r\n ",
Class96.smethod_66()
}), "Apache Logs Viewer " + Class96.smethod_265(), MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk) == DialogResult.Yes)
{
Process.Start("http://www.apacheviewer.com/download.php?up=1");
return;
}
break;
case 2:
if (MessageBox.Show(string_0 + "\r\n" + Class96.smethod_66(), "Apache Logs Viewer " + Class96.smethod_265(), MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk) == DialogResult.Yes)
{
Process.Start("http://www.apacheviewer.com/download.php?up=1");
return;
}
break;
case 3:
case 4:
goto IL_BD;
case 5:
MessageBox.Show(Class96.smethod_123(), "Apache Logs Viewer", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
Process.Start("http://www.apacheviewer.com");
Application.Exit();
return;
default:
goto IL_BD;
}
return;
IL_BD:
throw new ApplicationException("Unknown Update UI Command");
}

所以把MainForm_Load方法直接修改为如下即可跳过验证和更新

private void MainForm_Load(object sender, EventArgs e)
{
try
{
if (Class95.bool_2)
{
Prefs.DeletePrefs();
}
ALV.Common.Debug.Info("Started..");
Prefs prefs = Prefs.Load(Prefs.Filename);
if (string.IsNullOrEmpty(prefs.InstallID))
{
prefs.InstallID = Guid.NewGuid().ToString();
}
if (prefs.sizex > 10)
{
base.Width = prefs.sizex;
}
if (prefs.sizey > 10)
{
base.Height = prefs.sizey;
}
if (prefs.maximised)
{
base.WindowState = FormWindowState.Maximized;
}
if (prefs.x >= 0 && prefs.y >= 0)
{
base.Location = new Point(prefs.x, prefs.y);
}
this.prefs_0 = prefs;
if (this.prefs_0.logColumns == null || this.prefs_0.logColumns.Count <= 0)
{
this.prefs_0.logColumns = LogColumn.ResetLogColumns();
}
ALV.Common.Debug.Info("Loading Custom Columns");
this.prefsColumns_0 = PrefsColumns.Load(PrefsColumns.Filename);
this.method_42();
DummyListView.prefs = prefs;
ALV.Common.Debug.Info("Loading IP DB");
this.ip2Country_0 = new IP2Country(true, this.prefs_0.useCity);
this.parser_0 = new Parser(this.ip2Country_0);
this.parser_0.ParseCustomColumns = this.prefs_0.parseCustomColumns;
Statistics.int_0 = this.prefs_0.topNumber;
try
{
if (prefs.monitorAuto)
{
ALV.Common.Debug.Info("Opening Logs...");
foreach (LoggerInfo loggerInfo in prefs.logsToView)
{
if (loggerInfo.Highlight != null)
{
this.method_48(loggerInfo.Highlight, true);
}
try
{
this.method_6(loggerInfo);
if (Class95.bool_0)
{
GC.Collect();
}
}
catch
{
}
}
}
if (Class95.list_0 != null)
{
foreach (string text in Class95.list_0)
{
try
{
bool flag = this.parser_0.IsErrorLog(text);
this.method_4(text, !flag, false);
if (Class95.bool_0)
{
GC.Collect();
}
}
catch
{
}
}
}
}
catch (Exception)
{
MessageBox.Show(Class96.smethod_247());
}
if (this.prefs_0.selTab >= 0 && this.tabControl1.TabPages.Count > this.prefs_0.selTab)
{
this.tabControl1.SelectedTabPageIndex = this.prefs_0.selTab;
}
try
{
if (!string.IsNullOrEmpty(this.prefs_0.Key))
{
string string_ = Class2.smethod_0(this.prefs_0.Key);
this.bool_0 = true;
}
}
catch (Exception)
{
this.bool_0 = true;
}
try
{
if (IsStoreApp.IsWindowsStoreApp)
{
this.bool_0 = true;
this.bool_1 = true;
this.method_0();
}
}
catch
{
}
if (!this.bool_0)
{
this.lbStatusStripNotify.Text = Class96.smethod_270() + " Apache Logs Viewer..." + Class96.smethod_67();
this.method_2(true);
}
else
{
this.lbStatusStripNotify.Text = Class96.smethod_270() + " Apache Logs Viewer";
this.method_2(true);
}
ALV.Common.Debug.Info("Apply L...");
this.method_44(true);
this.method_1();
ALV.Common.Debug.Info("Apply L Done");
}
catch (Exception ex)
{
ALV.Common.Debug.Error("Error Load: " + ex.Message);
if (this.prefs_0 == null)
{
this.prefs_0 = new Prefs();
}
}
finally
{
LoadForm.smethod_1();
}
if (this.prefs_0.checkupdates)
{
new Thread(new ThreadStart(this.method_25)).Start();
}
this.timer_0.Interval = this.prefs_0.refreshtimeout * 1000;
this.timer_0.Enabled = true;
this.timer_0.Start();
GC.Collect();
if (base.Width <= 10)
{
base.Width = 668;
}
if (base.Height <= 10)
{
base.Height = 460;
}
this.menuStrip1.Visible = true;
this.toolStripBtnScroll.CheckState = (this.prefs_0.scroll_last ? CheckState.Checked : CheckState.Unchecked);
this.toolStripBtnRefresh.CheckState = (this.prefs_0.refreshAuto ? CheckState.Checked : CheckState.Unchecked);
ALV.Common.Debug.Info("Started..OK");
}

重新打开后,显示为已注册,所有功能已解锁

1563952799941

注册算法

该软件的注册算法如下

using System;
using System.Globalization;
using System.Text;

// Token: 0x02000017 RID: 23
internal static class Class2
{
// Token: 0x0600008E RID: 142 RVA: 0x0000C090 File Offset: 0x0000A290
public static string smethod_0(string string_0)
{
if (string_0.IndexOf('-') < 0)
{
return string_0;
}
string str = "DBV";
string_0 = string_0.Replace("-", string.Empty); //把-置换为空
string_0 = string_0.Replace('Q', '4'); //把Q置换为4
string_0 = string_0.Replace('G', '4'); //把G置换为4
string_0 = string_0.Replace('V', '0'); //把V置换为0
string_0 = string_0.Replace('N', '3'); //把N置换为3
str + string_0; //DBV+置换后的
byte[] array = new byte[string_0.Length / 2];//新建个数组,长度是传入的字符串的一半
for (int i = 0; i < string_0.Length; i += 2)//步长2
{
byte b;
byte.TryParse(new string(new char[]{string_0[i],string_0[i + 1]}),NumberStyles.HexNumber, CultureInfo.InvariantCulture, out b);
array[i / 2] = b;
}
string text = Encoding.ASCII.GetString(array);
text = text.Insert(1, ":");//在第1个字符后插入:
text = text.Insert(5, ":");//在第5个字符后插入:
text = text.Insert(9, ":");//在第9个字符后插入:
if (text.Length > 13)//如果长度超过13,在第14个字符后插入:
{
text = text.Insert(13, ":");
}
return text;
}

// Token: 0x0600008F RID: 143 RVA: 0x0000C1A0 File Offset: 0x0000A3A0

// HexNumber = 515
public static bool smethod_1(string string_0)
{
bool flag = true;
string a = string_0.Substring(4, 5);//第5位开始截取5个字符
if (a == "IALV")//如果5~9的字符为IALV flag为假
{
flag = false;
}
if (string_0[0] != 'F')//如果输入的第一个字符不为F,返回假
{
flag = false;
}
int num = int.Parse(string_0[2].ToString(), NumberStyles.HexNumber);
if (num > 16)
{
flag = false;
}
if (a != "I:ALV")//如果5~9的字符不为I:ALV 返回假
{
flag = false;
}
num = int.Parse(string_0[3].ToString(), NumberStyles.HexNumber);
if (num > 16)
{
flag = false;
}
if (!int.TryParse(string_0.Substring(10, 3), out num))
{
flag = false;
}
if (string_0.Length <= 14) //长度小于14 返回假
{
throw new ApplicationException("Invalid Unlock Code");
}
int num2 = int.Parse(string_0.Substring(15, 1));
if (num2 != 2 && num2 != 3) //第16位不等于2或3,返回假
{
throw new ApplicationException("Incorrect Code for Version");
}
string s = string_0.Substring(0, 16); //从第1位开始取16位
string b = string_0.Substring(16);//17位开始取后面的
int num3 = 0;
byte[] bytes = Encoding.ASCII.GetBytes(s);
for (int i = 0; i < bytes.Length; i++)
{
if (bytes[i] % 2 == 0)
{
num3++;
}
}
return !(num3.ToString("00") != b) && flag;
}
}