Python 爬虫反爬突破:AST 还原混淆 JS 代码实战
前言在现代 Web 反爬体系中前端 JS 代码混淆、变量加密、函数扁平化、字符串乱序、控制流平坦化已成为站点基础防护手段。常规格式化、手动抠代码、正则替换等方式面对高强度混淆 JS 完全失效不仅代码逻辑碎片化严重变量名无规则替换还存在死代码插入、垃圾字符填充、逻辑分支伪造等混淆手段人工逆向耗时漫长且极易出错。AST 抽象语法树作为代码编译与解析的核心底层技术可跳过代码表层混淆直接解析 JS 代码语法结构实现变量重命名、扁平化函数还原、死代码剔除、字符串解密、控制流还原全流程自动化处理是当前批量还原高强度混淆 JS 的最优方案。本文配套所需工具与库官方链接如下estraverse 官方文档AST 节点遍历核心库esprima 解析库JS 代码转 AST 语法树工具babel 官方中文文档前端代码编译与 AST 转换生态pyjsparser PyPI 库Python 端 JS 语法解析库Node.js 官方下载运行 Babel、AST 逆向环境必备文章从 AST 基础原理、JS 主流混淆类型、AST 还原核心流程、PythonNode 双环境实战、通用还原模板、工程化批量处理逐一讲解附带可直接商用的完整代码案例并逐段拆解底层运行原理帮助爬虫开发者彻底摆脱人工逆向混淆 JS 的低效模式。一、AST 抽象语法树基础理论1.1 AST 核心定义AST 全称抽象语法树是将编程语言源代码按照语法规则拆解为树形结构化节点的表现形式。代码不再以字符串文本形式存在而是被拆解为表达式、语句、变量、函数、条件分支、循环等标准化节点节点之间存在层级与关联关系。无论 JS 代码经过怎样的变量混淆、字符加密、格式压缩其语法逻辑结构不会改变这也是 AST 能够无损还原混淆代码的核心底层依据。1.2 AST 关键节点类型JS 代码转换为 AST 后常用核心节点类型如下表表格节点类型英文标识对应代码含义还原中作用变量声明VariableDeclarationvar/let/const 定义变量批量重命名混淆变量函数表达式FunctionExpression自定义函数逻辑还原扁平化嵌套函数字符串字面量StringLiteral普通字符串值解密加密字符串条件语句IfStatementif/else 逻辑分支剔除伪造死代码分支调用表达式CallExpression函数调用执行重构混乱调用关系成员表达式MemberExpression对象属性取值还原混淆对象访问逻辑1.3 AST 还原混淆 JS 核心优势传统手动逆向只能修改代码表层字符串无法触及逻辑结构而 AST 具备三大不可替代优势无视代码格式压缩、换行缺失、空格删减直接解析语法逻辑批量自动重命名 a1、b2、x9 等无意义混淆变量恢复语义化命名自动识别并删除冗余死代码、无效分支、垃圾填充代码精简源码自动化解密数组移位、字符置换、Base64 内嵌加密字符串。二、前端 JS 主流混淆类型识别2.1 变量名混淆将有语义的变量名、函数名替换为单字符、随机无意义字符如getSign替换为a、_0x12abcf增加阅读和逆向难度是最基础的混淆方式。2.2 控制流平坦化把顺序执行的代码拆分为无序分支通过数组索引、随机判断跳转执行逻辑打乱代码执行顺序人工梳理逻辑成本极高。2.3 字符串数组加密将所有明文字符串统一放入全局数组通过下标索引调用数组本身再做移位、异或、Base64 加密隐藏接口密钥、URL、固定参数等核心字符串。2.4 死代码注入插入永远不会执行的 if 分支、空循环、无效函数干扰逆向者判断增加代码冗余度。2.5 函数嵌套扁平化多层函数嵌套、自执行匿名函数堆砌把正常业务逻辑拆分为碎片化小函数割裂代码关联关系。三、AST 逆向环境搭建3.1 环境组成说明AST 还原混淆 JS 分为两套环境Node.js 端 Babel 生态专业级 AST 解析还原、Python 端 pyjsparser轻量级语法解析工程化实战以 NodeBabel 为主Python 做辅助调用与批量处理。3.2 Node 端依赖安装新建项目文件夹执行初始化与依赖安装命令bash运行# 初始化node项目 npm init -y # 安装AST核心依赖 npm install babel/parser babel/traverse babel/generator babel/types3.3 Python 端依赖安装Python 用于读取混淆 JS 文件、调用 Node 脚本、批量处理文件bash运行pip install pyjsparser -i https://pypi.tuna.tsinghua.edu.cn/simple3.4 环境校验代码3.4.1 Node 端 AST 基础解析校验新建ast_check.jsjavascript运行const parser require(babel/parser); const traverse require(babel/traverse).default; const generate require(babel/generator).default; // 测试混淆JS代码 const jsCode var ahello;function b(){console.log(a);}; // 转为AST语法树 const ast parser.parse(jsCode); // 遍历AST节点 traverse(ast, { VariableDeclaration(path){ console.log(检测到变量声明节点); } }); // 重新生成还原后代码 const {code} generate(ast); console.log(还原后代码,code);运行命令node ast_check.js输出节点检测信息与格式化代码即代表环境正常。3.4.2 代码原理babel/parser将 JS 字符串解析为标准 AST 语法树babel/traverse遍历树上所有节点可精准匹配变量、函数、字符串节点babel/generator将修改后的 AST 树重新生成规整可读的 JS 代码。四、AST 五大核心还原实战案例4.1 案例一混淆变量自动重命名还原4.1.1 实战代码新建rename_var.jsjavascript运行const parser require(babel/parser); const traverse require(babel/traverse).default; const generate require(babel/generator).default; // 高强度变量混淆JS源码 const confuseJs var _0x12a3123456;var _0x45b2sign;function _0x78c3(){return _0x12a3_0x45b2;}; // 解析为AST const ast parser.parse(confuseJs); let varIndex 1; // 遍历标识符节点批量重命名 traverse(ast, { Identifier(path){ const name path.node.name; // 匹配混淆格式变量名 if(/^_0x[a-f0-9]{4,}$/.test(name)){ path.node.name var_varIndex; } } }); // 生成还原后代码 const result generate(ast,{retainWhitespace:true}).code; console.log(变量重命名还原结果\n,result);原理剖析通过正则匹配站点典型混淆变量名_0x十六进制字符精准定位混淆标识符遍历 AST 标识符节点直接修改节点的 name 属性完成批量重命名重新生成代码后无意义乱码变量变为var_1、var_2规整命名可读性大幅提升全程不改动代码业务逻辑仅修改变量展示名称完全无损还原。4.2 案例二字符串数组加密 AST 解密还原4.2.1 实战代码新建decode_string.jsjavascript运行const parser require(babel/parser); const traverse require(babel/traverse).default; const generate require(babel/generator).default; // 字符串数组混淆示例JS const confuseJs var arr[abc123,tokenKey,https://api.test.com];function getStr(n){return arr[n];}; const ast parser.parse(confuseJs); let strMap new Map(); // 第一步提取数组内所有字符串 traverse(ast, { VariableDeclaration(path){ path.node.declarations.forEach(dec{ if(dec.init dec.init.type ArrayExpression){ dec.init.elements.forEach((el,idx){ if(el.type StringLiteral){ strMap.set(idx,el.value); } }); } }); } }); // 第二步替换数组下标调用为真实字符串 traverse(ast, { MemberExpression(path){ if(path.node.property.type NumericLiteral){ const idx path.node.property.value; if(strMap.has(idx)){ path.replaceWith({ type:StringLiteral, value:strMap.get(idx) }); } } } }); const result generate(ast).code; console.log(字符串数组解密还原\n,result);原理剖析遍历 AST 找到全局数组变量提取数组下标与对应明文字符串建立映射表匹配所有数组下标调用节点直接用真实字符串字面量替换原有下标访问彻底消除数组中转加密逻辑代码中直接展示明文 URL、密钥、接口参数适用于 90% 前端字符串数组移位、隐藏核心常量的混淆场景。4.3 案例三控制流平坦化死代码剔除4.3.1 实战代码javascript运行const parser require(babel/parser); const traverse require(babel/traverse).default; const generate require(babel/generator).default; const confuseJs function test(){if(12) return 垃圾代码;else return realData;}; const ast parser.parse(confuseJs); // 剔除永远不会执行的死代码分支 traverse(ast, { IfStatement(path){ const testNode path.node.test; // 判定固定假条件分支 if(testNode.type BinaryExpression testNode.operator ){ path.replaceWith(path.node.alternate); } } }); const result generate(ast).code; console.log(死代码剔除后\n,result);原理剖析AST 可精准识别 if 条件表达式、二元运算节点判断逻辑真假自动删除恒假分支代码保留真实执行的 else 业务逻辑批量清理站点刻意插入的无效分支、空循环、冗余判断精简代码结构。4.4 案例四扁平化嵌套函数还原4.4.1 核心原理前端混淆常将一个完整业务逻辑拆分为多个小函数互相调用AST 通过遍历CallExpression函数调用节点梳理函数依赖关系合并碎片化逻辑还原正常函数结构。通过标记被多次调用的公共函数、剥离无关嵌套层级把扁平化打散的代码重新聚合为可读完整函数。4.5 案例五Python 调用 Node 实现批量 JS 还原4.5.1 实战代码python运行import subprocess import os # 批量读取混淆JS文件调用AST还原脚本 def batch_ast_reduce(): # 混淆JS存放目录 confuse_dir ./confuse_js # 还原后JS输出目录 output_dir ./decode_js if not os.path.exists(output_dir): os.mkdir(output_dir) for file in os.listdir(confuse_dir): if file.endswith(.js): file_path os.path.join(confuse_dir,file) # 调用node执行AST还原脚本 res subprocess.run( [node,rename_var.js,file_path], capture_outputTrue, encodingutf-8 ) # 写入还原后文件 with open(os.path.join(output_dir,file),w,encodingutf-8) as f: f.write(res.stdout) print(批量AST还原完成) if __name__ __main__: batch_ast_reduce()原理剖析Python 遍历本地 JS 文件目录批量读取所有混淆脚本调用 subprocess 子进程执行 Node 端 AST 还原脚本获取标准输出的还原后代码批量写入新文件实现工程化一键处理适合爬虫项目中批量逆向多个加密 JS 文件无需手动逐个处理。五、AST 还原通用标准流程5.1 标准处理步骤源码获取抓包下载前端混淆 JS 源码保存为本地文件语法解析通过 Babel Parser 将 JS 转为 AST 语法树节点遍历遍历变量、字符串、条件、函数节点规则处理变量重命名、字符串解密、死代码删除、控制流还原代码生成通过 Generator 将修改后的 AST 重新生成可读 JS人工微调对少量复杂逻辑做简单梳理即可直接逆向算法。5.2 通用 AST 还原配置模板可固定复用 Babel 生成配置保证还原后代码格式规整javascript运行const result generate(ast,{ retainWhitespace:true, compact:false, quotes:single }).code;六、常见混淆场景 AST 落地适配方案表格混淆类型AST 处理方案适用场景随机变量名混淆正则匹配批量重命名常规站点基础混淆字符串数组加密提取数组映射 下标替换接口密钥、URL 隐藏控制流平坦化识别恒假分支 删除死代码逻辑打乱类高强度混淆自执行匿名函数提取内部逻辑、剥离外层包裹页面入口加密 JSBase64 内嵌 JSAST 提取字符串 Python 解码双层嵌套加密 JS七、工程化避坑与优化策略7.1 常见坑点部分混淆 JS 含 ES6 新语法需配置 Babel 支持 ES6 解析否则 AST 解析报错超大体积 JS 文件遍历 AST 耗时增加需做分片解析特殊自定义混淆规则需自定义正则与节点匹配逻辑不能套用通用模板。7.2 优化方案在 Parser 中增加sourceType:module适配模块化 JS采用异步遍历 AST 节点提升大文件处理速度封装通用 AST 还原工具类后续新项目直接传入 JS 源码即可输出还原结果。八、总结AST 抽象语法树是破解前端高强度 JS 混淆的核心底层技术彻底颠覆了人工逐行抠代码的传统逆向模式。依托 Babel 生态可实现变量重命名、字符串解密、死代码剔除、控制流还原全自动化配合 Python 实现批量文件处理极大提升爬虫逆向效率。掌握 AST 还原技术后面对市面上绝大多数网站的 JS 混淆、接口签名加密、参数算法混淆均可快速拆解逻辑、复刻加密算法为后续动态密钥、接口验签逆向打下坚实基础。