吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1123|回复: 12
收起左侧

[原创] Typora v1.12.4 -多次启动掉激活状态分析

[复制链接]
ty2018op 发表于 2026-1-6 16:29
本帖最后由 ty2018op 于 2026-1-6 19:04 编辑

基于steven026 大佬文章分析https://www.52pojie.cn/thread-2084047-1-1.html 和 Typora 1.10.8公钥替换,发现多次启动会掉激活状态,在想有没有能解决多次启动掉激活状态问题!第一次发帖,大佬勿喷
先看结果,看撒花很舒服  哈哈:
1.gif
2.gif

多次掉激活状态原因是软件存在多次验证,之前拦截部分不完整,是因为没有增加另一个域名拦截,导致有有玄学,其实不是,就是换域名请求而已!
有几个域名typora.cn  这个域名没有抓到,可能还会有,欢迎补充把
'https://store.typora.io/api/client/renew','https://dian.typora.com.cn/api/client/renew'

下面是拦截请求完整内容:  版本更新也拦截了、取消激活 也拦截了,加上后面的注册拦截就是完美激活状态
感慨!设计如此复杂保护流程,感觉还是需要c++编程 实现才可以增加点难度。

还有注册表不让其更新,因为软件判断如何是过期或者无效激活码会自动清空注册slicense值,所有劫持注册表
代码如下:附件代码

附件 完整代码.txt (15.04 KB, 下载次数: 74) 有完整代码,替换app/launch.dist.js 内容 就可以解决多次启动没有激活问题了

免费评分

参与人数 2吾爱币 +2 热心值 +2 收起 理由
max2012 + 1 + 1 谢谢@Thanks!
damocles1985 + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

m1y3ll0w 发表于 2026-1-6 18:19
本帖最后由 m1y3ll0w 于 2026-1-6 18:30 编辑

应该不只是域名匹配不全的问题,还可能跟 renew 接口返回信息关联,比如:code、msg,msg 对应的是 Base64 格式的 License,代码中可能会判断 code、msg 是否正确,不符合要求可能直接走激活失败的业务逻辑。

分享一下个人的修改代码:

// 激活关联字段
// Machine Code Base64 解码// 推测:v 对应 version,i 对应 fingerprint,l对应 deviceId
const ACT_ENTITY = {
    deviceId: 'xxxx | xxxx | Windows',
    fingerprint: 'xxxx', // ✔
    email: 'mxxxx@162.cn', // ✔
    license: 'xxxx-xxxx-xxxx-xxxx', // ✔
    version: 'win|1.12.4',
    date: '01/05/2026',
    type: 'xxxx'
};

// RSA 公钥解密,劫持返回值
const crypto = require('crypto');
const originalPublicDecrypt = crypto.publicDecrypt;
// Base64 格式激活许可信息
// 存入注册表 SLicense 第一个#之前的内容
// 解码后内容:CRACKED_BY_DIAMOND_HUNTERS{"fingerprint":"Tsxxxxxxxxp","email":"mxxxx@162.cn","license":"xxxxxx-xxxxxx-xxxxxx-xxxxxx","type":""} 
// License 加入前缀是为了避免所有返回信息都被劫持修改,只修改需要的接口,其他的保持原有逻辑,以免产生不可预估的问题
let License = Buffer.from("CRACKED_BY_DIAMOND_HUNTERS" + JSON.stringify(ACT_ENTITY)).toString('base64');
crypto.publicDecrypt = function (key, buffer) {
    writeLog('-------------------------------------------');
    writeLog('【👀 监控】 crypto.publicDecrypt 被调用');
    writeLog('Key:', key);
    //writeLog('Buffer (Hex):', buffer.toString('hex'));
    writeLog('Buffer content:', buffer.toString('base64'));

        if (buffer.slice(0, 26).compare(Buffer.from("CRACKED_BY_DIAMOND_HUNTERS")) == 0) {
        let ret = buffer.toString().replace("CRACKED_BY_DIAMOND_HUNTERS", "");
                writeLog('License content:', ret);
        return Buffer.from(ret);
    }

    return originalPublicDecrypt.call(this, key, buffer);
};

// 劫持联网验证
electron.app.whenReady().then(() => {
    electron.protocol.handle('https', async (request) => {
        writeLog(`[👀electron.net Request] ${request.method} ${request.url}`);

        // 拦截目标请求,伪造响应
        //if (request.url == 'https://store.typora.io/api/client/renew' || request.url == 'https://dian.typora.com.cn/api/client/renew') {
        // 在线激活
                if (request.url.includes('api/client/activate')) {
            return new Response(JSON.stringify({
                                code: 0,
                                retry: true,
                                msg: License
                        }),
                        {
                status: 200,
                headers: { 'content-type': 'application/json' },
            });
        }

                // 定期12h联网校验
                if (request.url.includes('api/client/renew')) {
            return new Response(JSON.stringify({ success: true, code: 0, retry: true, msg: License }), {
                status: 200,
                headers: { 'content-type': 'application/json' },
            });
        }

        // 尝试打印 Request Body
        try {
            const reqClone = request.clone();
            const reqBody = await reqClone.text();
            if (reqBody) {
                writeLog('[electron.net Request Body]:', reqBody);
            }
        } catch {}

        const response = await electron.net.fetch(request, { bypassCustomProtocolHandlers: true });

        // 克隆响应用于劫持 原始响应后续直接转发
        const resClone = response.clone();
        resClone
            .text()
            .then((resText) => {
                writeLog(`[👀electron.net Response] ${response.status} ${request.url}`);
                writeLog('[electron.net Response Body]:', resText.substring(0, 500));
            })
            .catch((err) => {
                console.error('[electron.net Response Error]:', err);
            });

        // 转发原始响应
        return response;
    });
});
炫迈 发表于 2026-1-9 08:56
老哥你这帖子发的很到位啊,我之前也遇到过Typora反复掉激活的烦人问题,折腾了好久,看到你的分析恍然大悟,原来typora.cn这个域名没拦住,难怪有时候好有时候坏,跟抽风一样,你这思路很清晰,两个关键域名都找到了,store.typora.io和dian.typora.com.cn,这两个确实容易漏掉,我之前只拦了主域名,难怪总翻车,注册表劫持这招也很关键,软件检测到过期就会自动清空slicense值,防不胜防,你提供的launch.dist.js替换方案我试了,确实稳了,启动十几次都没掉激活
justfly99 发表于 2026-1-6 17:26
注册后,把注册表改成只读呢?是否就不会掉注册了
 楼主| ty2018op 发表于 2026-1-6 17:31
justfly99 发表于 2026-1-6 17:26
注册后,把注册表改成只读呢?是否就不会掉注册了

也可以 就麻烦了,用代码拦截就行,js 很容易的
adx123456 发表于 2026-1-8 18:20
那怎么搞


最好的办法是typora激活补丁dll可以随着软件更新而更新
snakegao 发表于 2026-1-8 19:55

赞同,俺是普通人,破解是学不会了
heiyemohe 发表于 2026-1-8 20:10
vs + 插件,挺好用!
adx123456 发表于 2026-1-9 07:10
heiyemohe 发表于 2026-1-8 20:10
vs + 插件,挺好用!

详细说说
NorthEgg 发表于 2026-1-15 09:35
如果通过代码拦截请求的话匹配到 /api/client/renew 这个就行了吧,无所谓用了什么域名。这个api后面这段应该不会变吧。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-1-24 06:21

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表