首页
论坛
课程
招聘
雪    币: 12159
活跃值: 活跃值 (217)
能力值: ( LV9,RANK:166 )
在线值:
发帖
回帖
粉丝

[原创]Axure RP9 认证分析

2020-1-7 11:48 1323

[原创]Axure RP9 认证分析

2020-1-7 11:48
1323

0x01前言

新版本出来后,本来想找个可用的“和谐”版本,仍然并没有找到keygen或者Key,只能自己动手了。

  • 版本信息:9.0.0.3675

0x02切入分析

  1. 从x32dbg附加进程后,发现是.net程序:
    图片描述
  2. dnspy分析:
    图片描述
    通过字符串查找"The licensee or key is not valid.",定位到代码:
             if (true)
             {
             }
             return Local.GetString("The licensee or key is not valid.");        
         IL_80:
    

但是分析代码的时候,有特征的switch语句,应该是有控制流混淆,先去混淆:

λ "D:\Program Files\de4dot\de4dot.exe" -r . -ru -ro "E:\XXX\AxureRP\Axure-rp9\out"

de4dot v3.1.41592.3405 Copyright (C) 2011-2014 de4dot@gmail.com
Latest version and source code: https://github.com/0xd4d/de4dot

Detected Dotfuscator 19310:1:0:4.9.2500.21407 (D:\Program Files (x86)\Axure\Axure RP 9\AxDoc.dll)
Detected Dotfuscator 19310:1:0:4.9.2500.21407 (D:\Program Files (x86)\Axure\Axure RP 9\AxureRP9.exe)
Detected Dotfuscator 19310:1:0:4.9.2500.21407 (D:\Program Files (x86)\Axure\Axure RP 9\AxureRPUpdater.exe)
Detected Dotfuscator 19310:1:0:4.9.2500.21407 (D:\Program Files (x86)\Axure\Axure RP 9\Client.dll)
Detected Dotfuscator 19310:1:0:4.9.2500.21407 (D:\Program Files (x86)\Axure\Axure RP 9\Client.Mac.exe)
Detected Dotfuscator 19310:1:0:4.9.2500.21407 (D:\Program Files (x86)\Axure\Axure RP 9\Client.Win32.dll)
Detected Dotfuscator 19310:1:0:4.9.2500.21407 (D:\Program Files (x86)\Axure\Axure RP 9\Component.dll)
Detected Dotfuscator 19310:1:0:4.9.2500.21407 (D:\Program Files (x86)\Axure\Axure RP 9\Core.dll)
Detected Dotfuscator 19310:1:0:4.9.2500.21407 (D:\Program Files (x86)\Axure\Axure RP 9\FPRPC.dll)
Detected Dotfuscator 19310:1:0:4.9.2500.21407 (D:\Program Files (x86)\Axure\Axure RP 9\Generators.dll)
Detected Dotfuscator 19310:1:0:4.9.2500.21407 (D:\Program Files (x86)\Axure\Axure RP 9\ImportVectorShapes.dll)
Detected Dotfuscator 19310:1:0:4.9.2500.21407 (D:\Program Files (x86)\Axure\Axure RP 9\Model.dll)
Detected Dotfuscator 19310:1:0:4.9.2500.21407 (D:\Program Files (x86)\Axure\Axure RP 9\Platform.dll)
Detected Dotfuscator 19310:1:0:4.9.2500.21407 (D:\Program Files (x86)\Axure\Axure RP 9\Platform.Mac.dll)
Detected Dotfuscator 19310:1:0:4.9.2500.21407 (D:\Program Files (x86)\Axure\Axure RP 9\Platform.Win32.dll)
Detected Dotfuscator 19310:1:0:4.9.2500.21407 (D:\Program Files (x86)\Axure\Axure RP 9\Win32Wrapper.dll)

从结果看混淆都成功了,这里可见软件处理的并不强,工具直接处理了!
将输出的文件替换到安装目录后,再dyspy调试:
图片描述

 

从代码中可以看到语句都正常了,混淆后的变量不可恢复,这个不太影响分析。

0x3认证过程分析

对错误结果设置断点后,通过查看“调用堆栈”直接定位到关键处理函数:

    private bool method_39(out string string_2, bool bool_1, bool bool_2)
    {
        this.method_26(); // 清空变量
        string_2 = this.method_35(); // 获取输入Key值 
        int i = this.method_35().Length % 4; // 进行
        if (i != 0)
        {
            while (i < 4)
            {
                string_2 += "=";   // 长度不为4的倍数,补==,这个字符串是base64编码???
                i++;
            }
        }
        LicenseErrorType licenseErrorType;
        if (!GClass403.smethod_2(this.method_34(),  // 验证, method_34()获取用户名
                                 string_2,          // Key
                                 out licenseErrorType, bool_1)) 
        {
            string @string = Errors.GetString(licenseErrorType, Configurations.ProductName(true, false));
            if (licenseErrorType != LicenseErrorType.IncorrectLicensee)
            {
                if (licenseErrorType - LicenseErrorType.InvalidKeyForProduct > 1)
                {
                    this.axLabel_5.TextColorProp = "WarningColor";
                    this.axLabel_5.Text = @string;
                }
                else
                {
                    this.axLabel_5.TextColorProp = "PrimaryTextColor";
                    this.axLabel_5.SetTextAndParseTaggedLinks(@string, null, null);
                }
            }
            else
            {
                this.axLabel_6.Text = @string;
            }
            return false;
        }
        if (this.method_34().Any() && bool_2)
        {
            this.axLabel_5.TextColorProp = "SuccessColor";
            this.axLabel_5.Text = Local.GetString("This is a valid license.");
        }
        return true;
    }
    private static GClass738 smethod_63(string string_6, string string_7)
    {
        if (string_7.Length == 0)
        {
            return null;
        }
        if (GClass739.smethod_61(string_7))  // 内置了一个黑名单,进行判断Key是不是在
        {
            GClass738 gclass = new GClass738();
            gclass.method_1(LicenseExpirationState.Blocked);  // debug enter here .
            return gclass;
        }
        byte[] byte_;
        try
        {
            byte_ = Convert.FromBase64String(string_7);  // base64解码成byte
        }
        catch (FormatException)
        {
            GClass738 gclass2 = new GClass738();
            gclass2.method_1(LicenseExpirationState.None);
            return gclass2;
        }
        // GClass739.list_0 版本信息:Team, Pro, Enterprise,
        using (List<AxPair<RpEdition, GClass736>>.Enumerator enumerator = GClass739.list_0.GetEnumerator())
        {
            while (enumerator.MoveNext())
            {
                AxPair<RpEdition, GClass736> axPair = enumerator.Current; 
                RpEdition first = axPair.First;  // 证书类型信息
                byte[] array = axPair.Second.vmethod_3(byte_); // 解密信息,AES算法???。
                if (array != null)
                {
                    DateTime dateTime_;
                    try
                    {
                      //将解码后数据的array[16, 23]的8字节转成Int64的日期信息。
                        DateTime dateTime = new DateTime(BitConverter.ToInt64(array, 16)); 
                        if (!(dateTime < new DateTime(2002, 1, 1)) && !(dateTime > new DateTime(2050, 12, 31)))
                        {
                            dateTime_ = dateTime;
                            goto IL_C9;
                        }
                    }
                    catch (ArgumentOutOfRangeException exception_)
                    {
                        Logging.LogException(exception_);
                    }
                    continue;
                    IL_C9:
                    byte[] array2 = new byte[2];
                    Array.Copy(array, 24, array2, 0, 2);
                    Term term = (Term)array[26];
                    if (!term.Subscription())
                    {
                        term = Term.Perpetual;
                    }
                    GClass738 gclass3 = new GClass738();
                    gclass3.method_11(first);
                    // 
                    gclass3.method_1(GClass739.smethod_64(string_6, array, term, dateTime_)); // 过期校验。
                    gclass3.method_7(dateTime_);
                    gclass3.method_5(string_7);
                    gclass3.method_3(string_6);
                    gclass3.method_9(array2);
                    gclass3.method_13(term);
                    return gclass3;
                }
            }
            goto IL_14A;
        }
        GClass738 result;
        return result;
        IL_14A:
        GClass738 gclass4 = new GClass738();
        gclass4.method_1(LicenseExpirationState.None);
        return gclass4;
    }

从上面的分析可以发现,解密居然用的是AES(对称加密),这样就比较低端了,Keygen是妥妥的。

  // Key黑名单。
     private static readonly string[] string_5 = new string[]
    {
        "dcENpZgjsYDoFPNYx9JMm77TfrzIMlv5iXfdwturL4pDe7DEHjEfjvfCodDKdjLr",
        "FiCGEezgdGoYILo8U/2MFyCWj0jZoJc/sziRRj2/ENvtEq+7w1RH97k5MWctqVHA",
        "ogj1xp3rOKIyiMCh0w9ZIlujXKeBOE0CeuEjX2yNfDnO1IsJd3xdd7jMSe/iO2Ly",
        "pxZdYswBY1nPcIbP0iaLzNW2FGmLZBMIAgJKPeIxJL39FlKh0QwMhZ1Q/H15U8fT",
        ...
    }

    private static bool smethod_65(string string_6, byte[] byte_0)
    {
        GClass737 gclass = new GClass737(GClass737.GEnum51.const_4); //MD5
        gclass.method_3("sa;jl02 34oja a 9es8r23j4k@#%%^9345jfsd");
        byte[] bytes = Encoding.UTF8.GetBytes(string_6.Trim().ToLowerInvariant());
        byte[] array = new byte[bytes.Length + byte_0.Length - 16];
        Array.Copy(bytes, 0, array, 0, bytes.Length);
        // 把byte_0[16, ...] copy 到 array[16, ...]
        Array.Copy(byte_0, // sourceArray
                   16,     // sourceIndex
                   array,  // destinationArray
                   bytes.Length, // destinationIndex
                   byte_0.Length - 16); // length
        byte[] array2 = gclass.method_0(array); // Md5,也就是说把用户名作为MD5的密钥对数据进行了加密。
        for (int i = 0; i < 16; i++)  // 前16位比较。
        {
            if (array2[i] != byte_0[i])
            {
                return false;  // 输入的Licensee不对。
            }
        }
        return true;
    }

从上面的过程,基本上把一个解密后的Key的组成做了分析,以一个过期的Key为例:
'licensee' : 'Koshy',
'key' : "wTADPqxn3KChzJxLmUr5jTTitCgsfRkftQQ1yIG9HmK83MYSm7GPxLREGn+Ii6xY",

解密结果:
\x36\xBC\x2A\x31\x06\x29\xBC\xC9 // md5 encrypted hash  
\xF4\xC5\xFA\x7B\x26\xAD\x06\xE3 //
\xFB\xD7\xE9\xF0\xA1\x6D\xD5\x08 // DateTime
\x00\x00 // [24:25] Term bytes:
\x00 // Term:[0:Perpetual, 1:Monthly, 2:Annual]
\x77\x6A\xD8\x59\xB2 // ?
\xFB\xD5\x04\x58\x4E\x47\x45\x4E // ?

1. 解密共40位,前16位为后面Bytes + licensee 的Md5结果。
2. [16, 23]位为过期时间的ticsk编码(C#有点坑,它的时间居然不是1970开妈的,是从01.01.01的ticks)
3. [24,25]位为二进制Term
4. [26]为数值Term信息。
5. 剩下的没找到代码分析,不清楚是不是随机值,作为padding部分吧。

0x04 Kengen

Demo Key:
Licensee : test
Key : b'1PIJJuSV4jEqGezB9qMKhuiniCU+NeezfRehr7cjTBAzSVUr9HGMyrUxPeuvmN6o'
图片描述

05其它

网络验证? 目前没有找到,找到再看看。然后就没有然后了,感觉功能挺强大,但是授权做的太弱了!!!



[公告]看雪论坛2020激励机制上线了!多多参与讨论可以获得积分快速升级?

最后于 2020-1-9 14:50 被nevinhappy编辑 ,原因: 上传附件。
最新回复 (1)
雪    币: 4788
活跃值: 活跃值 (2638)
能力值: (RANK:65 )
在线值:
发帖
回帖
粉丝
Editor 活跃值 2020-1-11 18:40
2
0
感谢分享!
游客
登录 | 注册 方可回帖
返回