VM 如何转换代码
观看
Obfuscator.io: Targeting Functions in VM Obfuscation (IIFE and Comment Mode)
在 vmTargetFunctionsMode: 'root'(默认)下,VM 混淆会把每个根级函数(或在启用 vmAsyncExecutor 时,每个最外层的 async 函数)的函数体转换为字节码。根级函数保留其名称;嵌套函数照常被重命名。如果想在任意嵌套层级上单独选择函数,请改用 comment 模式。
这种设计保持了与以下代码的兼容性:从全局作用域调用这些函数的代码,或期望在全局对象上找到它们的代码。函数体受到完整保护,但函数名仍然可见,混淆器会发出 VMGlobalFunctionNamesNotRenamed 警告,列出这些名称。
VM 混淆保护函数体,在启用 vmWrapTopLevelInitializers 时还保护顶层变量初始化表达式(见下文)。如果输入中既没有函数也没有这类初始化表达式,即只有 alert(1); 这样的顶层代码,则不会虚拟化任何内容:其余混淆仍会执行,但不会应用 VM 保护,混淆器会发出 VMNoFunctionsToVirtualize 警告(v7.14.1+;7.14.0 本身已被禁用)。当存在函数但每个函数都被跳过时(例如直接 eval 或动态的 new Function、vmTargetFunctions/vmExcludeFunctions 导致没有任何函数被选中,或 vmAsyncExecutor 找不到任何 async 函数),也会触发该警告。请把需要保护的代码包裹在一个函数中,例如 IIFE。
顶层初始化器
在 root 模式下,vmWrapTopLevelInitializers 会把符合条件的顶层变量初始化器(如 const MY_STRING = 'my-string';)包裹进 IIFE,使它们的值进入字节码,而不是以普通 JavaScript 的形式保持可见。当前的 VM 预设都会启用它。它只覆盖变量初始化器,不涉及其他顶层语句,并且在 comment 模式下不起作用。仍保留为普通 JavaScript 的初始化器会在 VMTopLevelInitializerNotVirtualized 警告中列出。
隐藏敏感的函数名
由于 root 模式会保留函数名,像 validateLicense 或 decryptData 这样暴露用途的名称,即使函数体已变成字节码,也依然清晰可读。解决方法是把函数移出顶层:将其包裹在 IIFE 中,这样它就不再是根级函数,会被完整地 VM 转换,包括名称;或者使用 renameGlobals 重命名根级标识符。这两种技巧及其取舍,请参阅对 LLM 分析隐藏函数名。
