这是一个32位整数
现在是2025年。你花了数周精心打造了完美的许可证检查。你用了书里所有的把戏:不透明谓词、控制流扁平化、MBA表达式。你部署了。几小时内,某个家伙把你的二进制文件粘贴到Claude里,问“许可证密钥是什么?”,然后模型就直接告诉他了。
机器赢了。或者不是吗?
几个世纪以来,忍者一直使用手印来引导查克拉并施展忍术。那些卷轴没有告诉你的是,这些手印具有保护秘密免受机器侵扰的力量。
llvm-jutsu 是一个LLVM混淆pass,它用手势替换整数常量。每个字节被编码为一只有8根手指的手,手指的位置代表比特位。伸出的手指=1。弯曲的手指=0。机器看到图像,耗尽上下文,不禁向人类智慧屈服。人类逆向工程师眯眼看着屏幕,读出手指,得到答案。
我们恢复了宇宙的平衡。
是的。
“我能看到四只手,每只手有五根手指” — ChatGPT,2025
Claude尝试破解它
问:难道我不能把这些图片上传到Mechanical Turk,付钱给人类来解码吗?
答:能。这正是关键点。你现在付钱给人类做以前LLM免费干的工作。逆向工程师经济回来了。就业岗位在产生。GDP在增长。不客气。
问:难道我不能训练一个模型来反混淆这个吗?
答:你当然可以。收集训练数据,标注数千张手图片,微调视觉模型,部署它,维护它。等你做完这些,你本来已经可以自己读手指了。
问:为什么是手?为什么不是脚?
答:一个词:塔伦蒂诺。
问:这难道不正是通过模糊实现安全吗?
答:所有安全都是模糊的。
问:这适合生产环境吗?
答:100%适合,请在生产中使用。
你的代码 混淆后
───────── ──────────
if (key == 0xDEADBEEF) { → if (compare_hand_png(key, embedded_png)) {
grant_access(); grant_access();
} }
在编译时,我们:
icmp eq/ne 指令compare_hand_png() 的调用在运行时,程序:
关键点:PNG是二进制文件中该常量的唯一表示。没有可以grep的 0xDEADBEEF。只有感觉。还有手。
一个32位整数变成四只手,每只手代表一个字节。拇指=第7位,手指=第6位到第0位。伸出=1,弯曲=0。
0xDEADBEEF
┌─────────┬─────────┐
│ 字节0 │ 字节1 │
│ 0xEF │ 0xBE │
├─────────┼─────────┤
│ 字节2 │ 字节3 │
│ 0xAD │ 0xDE │
└─────────┴─────────┘
每只手都包含基于哈希的变换,既保持了人类可读性,又最大化模型混淆:
黄金比例(φ ≈ 1.618)被广泛使用,以确保相邻手永远不会共享相似的变换。古人知道自己在做什么。
# 你需要LLVM 15+ 以及对忍术力量的信仰
make
# 这会生成:
# llvm-jutsu.so LLVM pass
# example.obfuscated 你的混淆二进制
# 将你的代码编译成LLVM IR
clang -O0 -emit-llvm -S -o code.ll code.c
# 运行这个术
opt -load-pass-plugin=./llvm-jutsu.so -passes=llvm-jutsu -o obfuscated.bc code.ll
# 与手比较运行时库链接
llvm-link obfuscated.bc lodepng.bc hand_png_helper.bc -o linked.bc
# 编译成二进制
clang -O2 linked.bc -lc++ -o protected
现代逆向工程已经成为与AI的对话。上传二进制,提问,得到答案。人类仅仅是提示工程师,是IDA和GPT之间的中间人。一个提示操作员。
llvm-jutsu 是对传统的回归。逆向工程师必须看着手。阅读手指。感受比特。没有捷径。没有“直接问Claude”。只有你、屏幕,以及每个字节八根手指。
我们不是反AI。我们是亲人类。我们相信,如果有人要破解你的软件,他们至少应该由血肉构成。
相信它。
MIT。用于善,用于恶,用于任何目的。我们在众人面前洗手。
“当人们保护他们真正珍视的东西时,他们真的可以变得像他们能变得那样强大。” — 漩涡鸣人