本帖所包含的内容仅限技术交流和学习研究使用,禁止用于其他用途!因使用不当造成的一切后果与本人无关!

WebCruiserWVS是一个不错的漏洞检测工具,然而,它却需要注册才能正常使用= =
软件官网:http://www.janusec.com/


0x00:分析

首先输个假码,弹窗Invalid RegCode,自然是不通过……
1.png

0x01:爆破

查壳发现是C#的无壳程序,真是良心啊:-D
不废话直接拖入dnspy搜索字符串”Invalid RegCode”,找到了唯一的一个包含的函数”btnReg_Click”,看名字就知道是这个了,函数代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
private void btnReg_Click(object sender, EventArgs e)
{
string text = this.txtRegUsername.Text.Trim();
if (string.IsNullOrEmpty(text) || text.Length < 2)
{
MessageBox.Show("Username should has at least 2 letters!");
return;
}
string text2 = this.txtRegCode.Text;
if (string.IsNullOrEmpty(text2))
{
MessageBox.Show("RegCode can not be null!");
return;
}
if (Reg.ValidateRegCode(text, text2) || Reg.ValidateRegCode2(text, text2))
{
RegistryKey registryKey = Registry.CurrentUser.CreateSubKey("Software\\Sec4App\\WebCruiser");
registryKey.SetValue("Username", text);
registryKey.SetValue("RegCode", text2);
string text3 = DateTime.Now.ToString("yyyy-MM-dd");
text3 = Reg.Encrypt(text3);
registryKey.SetValue("InitDate", text3);
this.lblRegInfo.Text = "This copy of WebCruiser is licensed to: " + text;
MessageBox.Show("Thank You For Registration!", "Registration OK!");
this.lblRegUsername.Visible = false;
this.lblRegCode.Visible = false;
this.txtRegUsername.Visible = false;
this.txtRegCode.Visible = false;
this.btnReg.Visible = false;
this.linkLblBuy.Visible = false;
this.linkAvangate.Visible = false;
Reg.A1K3 = true;
Reg.RegUser = text;
return;
}
MessageBox.Show("Invalid RegCode !");
}

从17行可以看到这个程序会在HKCU的Software\Sec4App\WebCruiser下写入相关的注册信息,方便后来判断,程序入口中的CheckRegistration函数证实了我们的判断:

1
2
3
4
5
6
7
8
9
10
11
private void CheckRegistration()
{
......
RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("Software\\Sec4App\\WebCruiser", true);
if (registryKey == null)
{
......
}
......
}

可以看到程序调用了ValidateRegCode和ValidateRegCode2(正确一个即可)来计算KEY是否正确,为了省事,懒得再改启动时的KEY校验了,直接对Reg.ValidateRegCode分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public static bool ValidateRegCode(string Username, string RegCode)
{
bool result;
try
{
if (RegCode.Length != 19) //Key必须是19位
{
result = false;
}
else
{
char[] array = RegCode.ToCharArray();
if (array[4] != '-') //判断-符号
{
result = false;
}
else if (array[9] != '-') //判断-符号
{
result = false;
}
else if (array[14] != '-') //判断-符号
{
result = false;
}
else
{
RegCode = RegCode.Replace("-", ""); //去掉-符号
ulong num = Reg.Hash2UInt64(RegCode);
string hash = Reg.GetHash(Username);
ulong num2 = Reg.Hash2UInt64(hash);
string source = (num - num2).ToString();
string hash2 = Reg.GetHash(source);
if (hash2.Equals("1FEDF23C6CB786AA")) //关键判断
{
Reg._RegOK = true;
Reg.RegUser = Username;
result = true;
}
else
{
result = false;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
result = false;
}
return result;
}

可以看到在【关键判断】处就是看是否正确了,破解很简单,if (hash2.Equals("1FEDF23C6CB786AA")) 改成 if (!hash2.Equals("1FEDF23C6CB786AA")) 即可。
保存运行,可以看到随便输入就注册成功了哦~
2.png
可以看到此软件的破解还是比较简单的,没有网络验证……

0x02:追码

还是从ValidateRegCode函数入手,其中看到了Hash2UInt64和GetHash函数,跟进去看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private static ulong Hash2UInt64(string Str)
{
ulong result;
try
{
ulong num = ulong.Parse(Str, NumberStyles.HexNumber);
result = num;
}
catch
{
result = 0UL;
}
return result;
}

这个函数就是把字符串转成16进制,没什么东西。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private static string GetHash(string Source)
{
byte[] bytes = Encoding.UTF8.GetBytes(Source);
SHA512 sha = new SHA512Managed();
byte[] value = sha.ComputeHash(bytes);
string text = BitConverter.ToString(value).Replace("-", "");
char[] array = text.ToCharArray();
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 128; i++)
{
if (i % 8 == 0)
{
stringBuilder.Append(array[i].ToString());
}
}
return stringBuilder.ToString();
}

这个函数看到了SHA512,结合下面的for循环看出是一个128位字符串,估计就是标准的SHA512哈希,然后if (i % 8 == 0)stringBuilder.Append(array.ToString());一句看出是从第一位开始,每8位取一位,总共16位作为返回值。

现在我们发现了:
Hash2UInt64就是将数字字符串变为16进制
GetHash就是返回字符串的SHA512每8位取一位的值(共16位)
然后再看ValidateRegCode:

1
2
3
4
5
6
7
RegCode = RegCode.Replace("-", "");  		//去掉KEY中的-
ulong num = Reg.Hash2UInt64(RegCode); //将KEY转成16进制
string hash = Reg.GetHash(Username); //将用户名哈希运算
ulong num2 = Reg.Hash2UInt64(hash); //将用户名哈希运算的值转成16进制
string source = (num - num2).ToString(); //将16进制的KEY减去16进制的用户名哈希
string hash2 = Reg.GetHash(source); //将上面的结果哈希
if (hash2.Equals("1FEDF23C6CB786AA")) //哈希值为1FEDF23C6CB786AA则正确。

这就是它的KEY算法了……如果我们要弄出注册机,由于哈希函数不可逆,我们必须碰撞出哈希值为1FEDF23C6CB786AA的一个密钥,而这个密钥作者似乎并没有放到程序里面……由于GETHASH参数要是数字字符串,必须要碰撞出一个数字组成的PRIVATEKEY(长度未知),使其哈希函数值为1FEDF23C6CB786AA,这样便可以通过用户名逆推得到注册机,而这个工程量是极大的……
不过好消息是之前流出来了一个有效KEY:dayeve C467-1E8B-B74F-7808,我们可以用正确的注册码推出PRIVATEKEY!只需要按算法走,在string source = (num - num2).ToString();后面输出source的值,就可以得到PRIVATEKEY了!
通过实验发现其值为9196707196805196908(真大的一个数……)
然后注册机就出来了!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using System;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;

namespace crack
{
class Program
{
//HASH算法
private static string GetHash(string Source)
{
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(Source);
SHA512 sHA = new SHA512Managed();
byte[] value = sHA.ComputeHash(bytes);
string text = BitConverter.ToString(value).Replace("-", "");
char[] array = text.ToCharArray();
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 128; i++)
if (i % 8 == 0)
stringBuilder.Append(array[i].ToString());
return stringBuilder.ToString();
}
//16位转换
private static ulong Hash2UInt64(string Str)
{
ulong result;
try
{
ulong num = ulong.Parse(Str, NumberStyles.HexNumber);
result = num;
}
catch
{
result = 0uL;
}
return result;
}
//注册码生成
private static string Generate(ulong num2)
{
ulong key = 9196707196805196908; //privatekey
key += num2;
string res = key.ToString("x");
res = res.ToUpper();
res = res.Insert(4, "-");
res = res.Insert(9, "-");
res = res.Insert(14, "-");
return res;
}
static void Main(string[] args)
{
string a = Console.ReadLine();
ulong num = Hash2UInt64(GetHash(a));
Console.WriteLine(Generate(num));
Console.ReadKey();
}
}
}

3.png

0x03:下载地址

注册表破解文件:crack.zip
注册机:Keygen.zip