我把 claude code 的宠物从企鹅 reroll 成了龙
前两天 claude code 更新到 v2.1.89,社区发现了一个隐藏命令:/buddy。敲下去,输入框旁边会蹦出来一只小动物,虚拟宠物,在你写代码的时候陪着你。18 个物种,5 个稀有度,从 Common 到 Legendary,每只还有独立的 1% 闪光概率。愚人节彩蛋,挺可爱的,做得还挺全的。
这个宠物是由你的账号 ID 哈希出来的,不能选,也不能换。我敲了 /buddy,出来一只企鹅,Rare,稀有。行吧,企鹅也不是不能接受,至少是个蓝色品质。然后我手贱,用另一个账号又敲了一次,还是企鹅,这次是 Common,蓝色品质都没了。讲道理,两个账号同一个物种,稀有度还往下掉一档,这个就挺离谱的了。不能忍。
得先交代一下背景。我是那种在每一个抽卡游戏里都要 reroll 到 SSR 才开始玩的人:原神首抽没出五星,删号重来;崩铁没保底到限定,删号重来;FGO 初始池没出孔明,删号重来。所以当我发现这个宠物系统本质上就是个抽卡机制,而且我连抽两个号都是企鹅,接下来要干的事情就很清楚了:reroll。
这个想法不是我一个人有。linux.do 上已经有人在逆向了,哈希算法的大致逻辑翻出来了,salt 的格式也猜得差不多了,还有人做了个开源工具直接遍历宠物池。另一个帖子把稀有度分布和闪光判定机制拆得更细。不过我想再往前走一步。
这件事我觉得最有意思的地方在于:我是直接打开 claude code,跟它说,帮我逆向你自己的 /buddy 系统。它就真去干了。claude code 的二进制是用 Bun 编译的,claude 把编译后的代码拆出来,找到了哈希函数:FNV-1a 做初始散列,喂进 Mulberry32 这个 PRNG 生成伪随机数,salt 是 friend-2026-401。整个宠物分配逻辑就这么点东西:
账号 userID 经 FNV-1a 哈希喂进 Mulberry32 伪随机数,确定性地算出一只不能换的企鹅
hash = FNV-1a(userID + "friend-2026-401")
rng = Mulberry32(hash)
species = rng() → 映射到 18 个物种(按稀有度加权)
shiny = rng() < 0.01 → 1% 闪光
看到这个逻辑就知道可以暴力破解了。userID 就是个字符串,遍历足够多的字符串,总能撞出一个 hash 到 Shiny Legendary 的。而且 FNV-1a 又不是密码学哈希,这种暴力遍历连 GPU 都不需要,/buddy 大概是有史以来最好破解的抽卡系统。
让 claude 写了个暴力搜索脚本,逻辑很简单:生成随机 userID,跑一遍 FNV-1a + Mulberry32,看输出是不是 Legendary + Shiny + Dragon,不是就换下一个接着跑。跑起来,0.2 秒就命中了,一条 Shiny Legendary Dragon,金色传说。
不停生成随机 userID、算哈希、检查是不是金龙,不是就重试,直到 0.2 秒命中
不过这个脚本有个限制:只能搜物种、稀有度、闪光这三样,帽子和眼睛选不了。龙是出来了,长什么样全凭天意。
然后我去看了社区那个 cc-buddy,这个工具是全定制的,物种、稀有度、闪光、帽子、眼睛,全都能指定。我要的配置:龙,传说,闪光,皇冠,特定眼型。搜索范围大了自然就慢一些,最后停在第 4,547,133 次迭代,9.75 秒,命中,终端蹦出一行「★★★★★ legendary dragon ✦」。
cc-buddy 暴力搜索过程
这次不只是金色传说了,是一条头戴皇冠、双眼发光的金色传说龙,每一个细节都是我自己挑的。
闪光传说龙——Murmux
本来以为换上新 userID 就完事了,结果还有一个坑。claude max 订阅用户每次启动的时候,系统会拿你账号的 accountUuid 把本地的 userID 覆盖回去,改了也白改,一登录就被刷回企鹅。解法也简单粗暴:写一个 shell wrapper,每次启动 claude code 之前先把 accountUuid 从配置里 strip 掉。有效。
最后留下来的就是这条龙,Shiny Legendary Dragon,头戴皇冠,双眼发光,系统给它取名 Murmux。最搞笑的是性格描述:"A perpetually unimpressed penguin who delivers brutally accurate code critiques"——它还以为自己是企鹅。原因是这套宠物系统分骨骼和灵魂两层,"灵魂"那一层是我还是企鹅的时候生成的,换 userID 只换掉了骨骼,灵魂没跟着换。
宠物分骨骼和灵魂两层,换 userID 只换了骨骼变成龙,灵魂那层还记得自己是企鹅
说实话,这一通折腾没有任何实际产出。一个愚人节彩蛋,一只虚拟宠物,纯 cosmetic 的东西,我花了半个多小时逆向、破解、绕账号绑定,就为了把两只企鹅换成一条金色的龙。但我觉得这事挺值的,原因大概有两个。
一是 Anthropic 一个做专业开发者命令行工具的团队,在里面认认真真做了一套没什么用的抽卡系统,18 个物种、5 个稀有度、闪光、帽子、眼睛、五维属性,还分骨骼和灵魂两层,讲道理这个真的很可爱。写代码的时候输入框旁边有只小动物待着,挺好的。二是整个过程全是 claude code 自己干的:逆向它自己的代码,破解它自己的随机系统,绕过它自己产品的账号绑定,连分析它自己这一步也是它干的。
跟概率较劲这个事本身也挺有意思,明明知道期望值是多少,还是想试试运气,运气不行就上手段,数学的、工程的、暴力破解的。脚本蹦出命中那一下确实爽,跟抽到 SSR 一个感觉,虽然我很清楚背后就是一行确定性的数学运算。反正龙已经换上了,Murmux 到现在还觉得自己是企鹅,就先这样吧。
感谢 linux.do 社区的逆向工程先驱们,以及 fengshao1227 的开源工具。也感谢 claude code 团队把这个愚人节彩蛋做得这么用心——藏得够深,又刚好能被找到。