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

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


0x00:分析

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

0x01:爆破

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

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函数证实了我们的判断:

private void CheckRegistration()
{
    ......
    RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("Software\\Sec4App\\WebCruiser", true);
    if (registryKey == null)
    {
        ......
    }
    ......
}

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

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函数,跟进去看看

private static ulong Hash2UInt64(string Str)
{
    ulong result;
    try
    {
        ulong num = ulong.Parse(Str, NumberStyles.HexNumber);
        result = num;
    }
    catch
    {
        result = 0UL;
    }
    return result;
}

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

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:

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(真大的一个数……)
然后注册机就出来了!

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

最后修改:2019 年 04 月 04 日 11 : 04 PM
如果觉得我的文章对你有用,请随意赞赏