有的人能把代码写成推理小说。需要一个临时变量的时候就叫 temp,需要多个就叫 var1,var2。甚至用拼音缩写当函数名,比如查询订单就叫 cxdd。
要想看懂这样的代码,得联系上下文反复推敲,还原每个部分的真实作用。
这个过程叫做反混淆 (Deobfuscation)。麻烦,着实麻烦。就没有省事儿点的办法吗?
让 AI 来啊!
最近,Facebook 就出了这样一个语言模型 DOBF,专治代码混淆。像下图这种,所有不影响运行的变量名、函数名、类名,都被替换成无意义的符号,AI 都能作出猜测并尝试还原。
来看看和正确答案的对比,虽然不是完全一样,但 AI 的改法也大大提高了代码的可读性。
像 FUNC_0,源代码中是“重置参数”,AI 改成“初始化权重”,也完全说得通。
DOBF 模型目前除了 Python 还支持 C++ 和 Java。
编码不规范的人毕竟是少数,这个模型更广泛的用途是恢复故意做混淆以保护知识产权的代码,比如这种:
代码写好后,把不影响编译运行的部分,批量替换成人类难以分辨的符号,给破译增加难度。
在这之前也有掩码语言模型 (Masked Language Model) 用于恢复被遮蔽的文本。
用于恢复代码的有哈工大 & 微软开发的 CodeBERT 和 Facebook 之前开发的 TransCoder,但效果都不如最新的 DOBF。
DOBF 超过它们靠的不是模型架构上的创新或数据集的完善,而是提出了新的预训练任务。
合理的任务指导 AI 学习
之前的掩码语言模型多是随机选择要掩蔽的部分,经常会选到括号逗号这种对 AI 来说没什么难度的。
DOBF 的做法是指定遮蔽变量名、函数名和类名并让 AI 去恢复,这个任务难度更大,能迫使 AI 学到更深层的规律。
另外还用相同的符号替代多次出现的同一名称,这样可以防止 AI 发现有的名字可以复制粘贴之后学会偷懒走捷径。
像上图中的变量 V3,AI 从第 3 行的定义可以看出这个变量是 List 类型,再一看第 5 行调用的是 pop (0)。
这不是先进先出嘛,AI 就会命名成 queue (队列) 而不是 stack (堆栈) 了。
更厉害的还在后面,DOBF 通过代码内容甚至能判断出相应函数是生成斐波那契数列和做向量点积的。
DOBF 在架构上其实没有特别的设计,只是为了公平对比分别训练了两个和 CodeBERT、TransCoder 层数一样的模型。
成功的关键之处就在于合理的训练任务。
微调一下能完成更多任务
验证了这个方法有效后,Facebook 把这个训练任务提取出来称为 DOBF 任务,还可以用于训练其他语言模型。
比如在 TransCoder 模型上把 DOBF 作为预训练任务,再用 CodeXGLUE 基准测试中的下游任务进行微调。
结果在代码抄袭检测、总结代码生成文档、和自然语言搜索代码片段这 3 个任务上,使用 DOBF 或 MLM+DOBF 预训练都取得了更好的成绩。
Facebook 下一步还要以 DOBF 作为指导,看看能不能为自然语言设计更好的预训练目标。
不过代码上的事还不算完,人类在混淆代码上可是无所不用其极的。
期待着有一天,AI 连国际 C 语言混乱代码大赛上的变态代码也能看懂。
Github 地址:
https://github.com/facebookresearch/CodeGen/blob/master/docs/dobf.md
论文地址:
https://arxiv.org/abs/2102.07492
国际 C 语言混乱代码大赛:
http://www.ioccc.org/