LHL's Blog

Typecho Mirages 主题破解思路

本文介绍的方法涉及关闭域名授权码的校验流程,直接通过离线算法生成密钥(Token)。
该做法可能绕过官方授权验证机制,仅供学习、测试或特殊场景下使用,
请确保您拥有相关软件或服务的合法使用权。
非法使用或未经授权的操作可能导致服务异常或法律风险,使用前请充分评估相关责任。
本文主要目的是分享技术实现思路和代码示范,欢迎交流和探讨,严禁用于侵犯版权或违规用途。

授权 Key 生成器

[collapse title="展开使用"]

仅能保证前台校验,后台调用api无法跳过,请看下面
A
(尚未生成)

B
(尚未生成)

原文
(尚未生成)
计算细节

[/collapse]

前台校验逻辑

尝试找到校验文件

dashboard.settings.min.js中找到如下:
[hide]

try {
  n.getJSON("https://store.get233.com/api/mirages/verifyDomainToken", h, function(e) {
    if (true) # 已经修改为true了
     if (true)  {  # 这里也修改为true了
      l(a, "域名授权码校验通过", "hint-success");
      } else {
......

[/hide]
将里面的两个if条件改为true,仅使在后台输入校验码后能够提示校验码有效,但是前台还是不会生效。且前台并没有引入这个JS文件。翻看PHP后并没有相关的校验代码,于是我们把目光放到
[hide]

<script src="https://blog.lhl.one/usr/themes/Mirages/js/7.10.6/mirages.main.min.js" type="text/javascript"></script>

[/hide]

分析校验逻辑

校验码在Base64解码后有如下格式
[hide]

domain/a:b:c

[/hide]
初始分析可能是密钥加密,但是经过一系列的尝试之后发现并不可能。
后面查找代码
代码片段1

try {
    for (var a = A.call(h.k, x(2, 35, 3)), b = 0; b < a.length; b++) try {
        var c = A.call(a[b], p(37)),
            f = c[0],
            e = p(38),
            g;
        if (!(g = t === f)) {
            var m = e + f;
            g = null === m || "" === m || 0 === t.length ||
                m.length > t.length ? !1 : t.substr(t.length - m.length, m.length) === m
        }
        if (g) {
            h[x(6, -55, 4)] += 2;
            h.D = c[0];
            h.K = c[1];
            break
        }
    } catch (r) {}
    return h
} catch (r$2) {
    h.k = null
}

a = A.call(h.k, x(...))本质是a = h.k.split(某个分隔符),得到的是 Key 列表数组
c = A.call(a[b], p(37))本质是c = a[b].split(":")
[hide]

c[0] = 域名/A
c[1] = B
c[2] = C   (注意:这里根本没用到 C)

[/hide]
域名匹配逻辑则是顶级域名匹配即可。那么接下来我们寻找C在哪里出现,注意h.Dh.K这两个变量,寻找h.k发现
代码片段2

h.k = R[p(15, 6, 19, 18, 8, 15, -11, 1, 0, 19, 0, 15)];

在h.k赋值代码后添加console.log输出,得到h.k就是校验码(base64编码)

代码片段3

try {
            var a = A.call(h.K, p(26)),
                b = parseInt(a[0], 16),
                c = parseInt(a[1], 16);
            if (a[2]) {
                for (var f = h.D, e = a = 0; e < f.length; e++) {
                    var g = P.call(f, e) << e + 1;
                    if (20 < e || 1E7 < g || 0 > g) g = 0;
                    a += g;
                    1E7 < a && (a %= 1E7)
                }
                a ^ b + h.r + 1E7 === c && (h[ba(3, 4, 17)] += 4)
            }
            return h
        } catch (m) {}

去混淆后是
[hide]

try {
    var parts = h.K.split(p(26));   // p(26) 基本就是 ":"
    var b = parseInt(parts[0], 16); // A(16进制)
    var c = parseInt(parts[1], 16); // B(16进制)

    if (parts[2]) {
        var f = h.D; // 域名/A
        var sum = 0;

        for (var i = 0; i < f.length; i++) {
            var g = f.charCodeAt(i) << (i + 1);

            if (i > 20 || g > 1e7 || g < 0) g = 0;

            sum += g;
            if (sum > 1e7) sum %= 1e7;
        }

        if ( (sum ^ (b + h.r + 10000000)) === c ) {
            h[ba(...)] += 4; // 校验通过
        }
    }

    return h;
} catch (e) {}

[/hide]
也就是有公式
[hide]

B = hash(domain) ^ (A + h.r + 10000000)

[/hide]
经过寻找后h.r10018218
而C则是一个MD5的值。得出最终规则:
[hide]

B = hash(domain) ^ (A + 20018218)
C = md5(domain/A:B)

[/hide]
那么,只需要有domain和A的值就行了,A可以随机取一个8位16进制的值,通过上方的公式计算出B和C,然后Base64编码就可以得到我们需要的校验码了。
我写了一个生成器,可以通过A生成B的值,放在了文章开头

后台校验逻辑

相信聪明的你已经掌握了阅读混淆JS代码的能力。
后台校验代码在dashboard.settings.min.js中,将校验失败逻辑代码注释即可

写在最后

原创不易,希望各位能够支持正版!
正版购买入口:点我前往

当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »