Xmind Pro 激活 mac 系统

在 大佬的基础上调整了一下,在mac 系统上激活成功,详细可以看这篇帖子

部分代码根据mac 系统做了调整, 具体内容可以看看注释

破解完成之后会提示软件包被破坏, 可以运行这个命令:

sudo xattr -rd com.apple.quarantine /Applications/Xmind.app
import os
import pathlib
import shutil
from base64 import b64decode, b64encode

from asarPy import extract_asar, pack_asar
from crypto_plus import CryptoPlus
from crypto_plus.encrypt import decrypt_by_key, encrypt_by_key

from crack.base import KeyGen


class XmindKeyGen(KeyGen):

    def __init__(self):
        # tmp_path = os.environ['TMP']
        # mac 软件路径不一样,可以自己看着修改
        asar_path = pathlib.Path('/Applications/Xmind.app/Contents/Resources')
        self.asar_file = asar_path.joinpath('app.asar')
        self.asar_file_bak = asar_path.joinpath('app.asar.bak')
        self.crack_asar_dir = asar_path.joinpath('ext')
        self.main_dir = self.crack_asar_dir.joinpath("main")
        self.renderer_dir = self.crack_asar_dir.joinpath("renderer")
        self.private_key = None
        self.public_key = None
        self.old_public_key = open('old.pem').read()

    def generate(self):
        if os.path.isfile('key.pem'):
            rsa = CryptoPlus.load('key.pem')
        else:
            rsa = CryptoPlus.generate_rsa(1024)
            rsa.dump("key.pem", "new_public_key.pem")
        license_info = '{"status": "sub", "expireTime": 4093057076000, "ss": "", "deviceId": "AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA"}'
        self.public_key = rsa.public_key
        self.private_key = rsa.private_key
        self.license_data = b64encode(encrypt_by_key(rsa.private_key, license_info.encode()))
        return self.license_data

    def parse(self, licenses):
        return decrypt_by_key(self.public_key, b64decode(licenses))

    def patch(self):
        # 先删除接包的内容,防止已经存在报错
        shutil.rmtree(self.crack_asar_dir)
        # 解包
        extract_asar(str(self.asar_file), str(self.crack_asar_dir))
        shutil.copytree('crack', self.main_dir, dirs_exist_ok=True)
        # 注入
        # 看了一下mac最新版本的源代码只有一行,这里采用插入首行
        with open(self.main_dir.joinpath('main.js'), 'rb') as f:
            lines = f.readlines()
            # lines[5] = b'require("./hook")\n'
        lines.insert(0, b'require("./hook");\n')
        with open(self.main_dir.joinpath('main.js'), 'wb') as f:
            f.writelines(lines)
        # 替换密钥
        old_key = f"String.fromCharCode({','.join([str(i) for i in self.old_public_key.encode()])})".encode()
        new_key = f"String.fromCharCode({','.join([str(i) for i in self.public_key.export_key()])})".encode()
        for js_file in self.renderer_dir.rglob("*.js"):
            with open(js_file, 'rb') as f:
                byte_str = f.read()
                index = byte_str.find(old_key)
                if index != -1:
                    byte_str.replace(old_key, new_key)
                    with open(js_file, 'wb') as _f:
                        _f.write(byte_str.replace(old_key, new_key))
                    print(js_file)
                    break
        # 手动搜索发现 main.js 里面也有公钥信息,一起替换掉
        for js_file in self.main_dir.rglob("*.js"):
            with open(js_file, 'rb') as f:
                byte_str = f.read()
                index = byte_str.find(old_key)
                if index != -1:
                    byte_str.replace(old_key, new_key)
                    with open(js_file, 'wb') as _f:
                        _f.write(byte_str.replace(old_key, new_key))
                    print(js_file)
                    break
        # 占位符填充
        with open(self.main_dir.joinpath('hook.js'), 'r', encoding='u8') as f:
            content = f.read()
            content = content.replace("{{license_data}}", self.license_data.decode())
        with open(self.main_dir.joinpath('hook.js'), 'w', encoding='u8') as f:
            f.write(content)
        with open(self.main_dir.joinpath('hook').joinpath('crypto.js'), 'r', encoding='u8') as f:
            content = f.read()
            content = content.replace("{{old_public_key}}", self.old_public_key.replace("\n", "\\n"))
            content = content.replace("{{new_public_key}}", self.public_key.export_key().decode().replace("\n", "\\n"))
        with open(self.main_dir.joinpath('hook').joinpath('crypto.js'), 'w', encoding='u8') as f:
            f.write(content)
        # 封包
        os.remove(self.asar_file)
        pack_asar(self.crack_asar_dir, self.asar_file)
        shutil.rmtree(self.crack_asar_dir)


if __name__ == '__main__':
    XmindKeyGen().run()


18 个赞

我也改过脚本 但是是本地没有 old.pem 啊.我全局搜也没找到…

1 个赞

old.pem 不是在压缩包( crack_xmind.zip )里面吗?

1 个赞

我c,我以为直接跑脚本就行,没下载…

发出来的都是部分脚本,具体使用要是用完整的,里面还有hack 相关的js文件

python3 xmind.py
Traceback (most recent call last):
File “/Users/dongdongguo/Downloads/crack_xmind-1/xmind.py”, line 10, in
from crack.base import KeyGen
ModuleNotFoundError: No module named ‘crack.base’

我这边提示这个问题是怎么回事呢, 已经按照 .bat脚本里面去install requirement.txt里面的依赖了

对应的修改一下, 我这个是使用大佬的github 项目改的 , 如果使用的是压缩包可以把红框里面的删除,然后把下面截图这块代码复制回来即可。
image

class KeyGen(metaclass=ABCMeta):
    @abstractmethod
    def generate(self):
        pass

    @abstractmethod
    def parse(self, licenses):
        pass

    @abstractmethod
    def patch(self):
        return ""

    def run(self, patch=True):
        ciphertext_licenses = self.generate()
        print(f"ciphertext_licenses: \n{ciphertext_licenses}")
        if patch:
            patch_info = self.patch()
            if patch_info:
                print(f"patch: \n{patch_info}")
        plaintext_licenses = self.parse(ciphertext_licenses)
        print(f'plaintext_licenses: \n{plaintext_licenses}')

2024-04-11 更新
新版本的系统可能会提示不允许修改软件,可以在安全和隐私里面打开对应程序的开关

运行成功了,补充一下 在这些代码上面还需要再加一行
from abc import ABCMeta, abstractmethod
另外在运行脚本的时候提示在/Applications/Xmind.app/Contents/Resources/路径下不存在ext文件夹,我手动创建了ext文件夹似乎就可以了
最后右上角还是有立即订阅的按钮,但是似乎不影响这个软件继续使用,我这边现在运行的就是最新版本的xmind

之前本地多次运行,如果存在文件夹会报错,所有添加了一个删除,未考虑首次运行文件夹不存在会报错的问题,然后 添加 ignore_errors=True 即可

    def patch(self):
        #先删除接包的内容,防止已经存在报错,
        shutil.rmtree(self.crack_asar_dir, ignore_errors=True)

今天也发现了,订阅按钮不会消失,整体看起来未破解成功,最终和大佬的github项目对比了一下,使用poetry 安装 crypto_plus 是1.0.0 版本的,而是用pip3 安装的是1.0.2 版本的,两个版本计算出来的授权是不一致的,所以这里锁定一下版本即可破解成功

 -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
crypto_plus==1.0.0
asarpy
2 个赞

终于成功了

成功了,感谢

下载包运行成功,但是未成功激活。稍后再研究下

收藏一下

感谢大佬!

谢谢楼楼 成功了 :yum: :yum:


提示错误且无法登陆

端口呗占用了,可以考虑自己换一个,或者关闭本地占用的程序

感谢大佬,之前52的教程,mac都只能维持在23的某一个版本~windows又没问题,这下可以愉快的升级了

mark一下