准备工作:

1.网站及工具

JavaScript Obfuscator Tool   主要研究对象,主要是研究此网站的各种混淆方法及破解办法。

JS NICE: Statistical renaming, Type inference and Deobfuscation          用来格式化代码,方便调试。

notepad++                  编辑代码。

https://astexplorer.net/     用来查看各种代码的AST结构。

2.nodejs的安装

官方网站    https://nodejs.org/zh-cn/

win10 可以直接下载最新版进行安装

win7   最高似乎只能安装nodejs 13.14.0版本 ,需要去页面https://nodejs.org/zh-cn/download/releases/ 下载安装。

安装过程略。

3. vscode的安装

下载地址:https://code.visualstudio.com/   安装过程略

主要用于调试代码。


babel安装及相关文档

1. Babel的安装

新建一个文件夹,cmd窗口转到此路径下,首先初始化项目:

npm init

然后执行以下命令:

# babel遍历器
npm install @babel/traverse --save# code解析为ast
npm install @babel/parser --save# ast操作相关工具类
npm install @babel/types --save# ast还原为代码
npm install @babel/generator --save

接着可参考参考:https://blog.csdn.net/weixin_40352715/article/details/109809754

可将此文章中的例子在vscode中调试以下,一来试一试环境是否已配置好,二来也先看一看效果。

2. babel官方文档

接着学习基础知识:

babel-handbook/plugin-handbook.md at master · jamiebuilds/babel-handbook · GitHub

babel-handbook/user-handbook.md at master · jamiebuilds/babel-handbook · GitHub

PS:Pandoc 可以将md文件转换为word或者pdf文件。

3.babel插件常用api

此部分来源:https://www.jianshu.com/p/7c8c5ae1e4be

行文至此,顺便梳理下babel中的一些api,市面上很少有这方面的内容,一般都是讲解插件配置和一些demo插件的编写。以下的内容都是参考源码和注释得来的。

[一]path相关api

有关path相关的源码都在@babel/traverse这个目录下。想要查找到符合条件的节点并进行各种各样的操作,都要依赖这部分的api,官方文档基本等于没有,相关api的用法只有自己扒源码,源码中的api功能大致通过名字可以猜出来,大家可以先有个印象,以后有对应的需求再去查找具体用法。

[二]ancestry.js相关api

这一部分的api主要是查找当前节点的祖先节点和有关判断,具体使用规则只有看源码自行体会。

//  从当前节点上溯,传入回调函数,通过函数来判断返回什么节点,从自己开始
exports.findParent = findParent;
//  从当前节点上溯,传入回调函数,通过函数来判断返回什么节点,从自己的父节点开始找
exports.find = find;
//  查找第一个函数式父组件
exports.getFunctionParent = getFunctionParent;
//  查找其声明的父组件(感觉指的是react中继承的父组件)
exports.getStatementParent = getStatementParent;
//  传入一个path,获取最上层的常规祖先节点
exports.getEarliestCommonAncestorFrom = getEarliestCommonAncestorFrom;
//  传入一个path,获取最底层的常规祖先节点
exports.getDeepestCommonAncestorFrom = getDeepestCommonAncestorFrom;
//  返回一个包含所有祖先的数组
exports.getAncestry = getAncestry;
//  传入一个节点,判断当前的节点是否是传入节点的祖先
exports.isAncestor = isAncestor;
//  传入一个节点,判断当前节点是否是出入节点的子节点
exports.isDescendant = isDescendant;
//  上溯,传入一个类型数组,判断所有节点中是否是数组中的类型
exports.inType = inType;

[三]comments.js相关api

这一部分的api主要是查找跟注释相关的节点

//  和兄弟元素共享注释
exports.shareCommentsWithSiblings = shareCommentsWithSiblings;
//  添加单条注释
exports.addComment = addComment;
//  添加多行注释
exports.addComments = addComments;

[四]context.js相关api

主要是跟当前访问上下文相关的api

//  调用一系列函数,返回布尔值
exports.call = call;
//  内部方法,配合call使用
exports._call = _call;
//  当前节点的类型是否在黑名单中
exports.isBlacklisted = isBlacklisted;
//  访问一个节点,返回布尔值,是否应该停止访问
exports.visit = visit;
//  标记跳过
exports.skip = skip;
//  置skipkey
exports.skipKey = skipKey;
//  停止
exports.stop = stop;
//  设置scope
exports.setScope = setScope;
//  设置上下文
exports.setContext = setContext;
//  再同步相关
exports.resync = resync;
exports._resyncParent = _resyncParent;
exports._resyncKey = _resyncKey;
exports._resyncList = _resyncList;
exports._resyncRemoved = _resyncRemoved;、
//  上下文出栈
exports.popContext = popContext;
//  上下文入栈
exports.pushContext = pushContext;
//  设置
exports.setup = setup;
exports.setKey = setKey;
//  重新入队
exports.requeue = requeue;
//  获取队列上下文
exports._getQueueContexts = _getQueueContexts;

[五]conversion.js相关api

//  获取节点的key
exports.toComputedKey = toComputedKey;
//  讲一个节点变成语句块
exports.ensureBlock = ensureBlock;
//  将箭头函数表达式变成普通函数
exports.arrowFunctionToShadowed = arrowFunctionToShadowed;
//  去掉函数环境的封装?
exports.unwrapFunctionEnvironment = unwrapFunctionEnvironment;
//  类似arrowFunctionToShadowed
exports.arrowFunctionToExpression = arrowFunctionToExpression;

[六]evaluation.js相关api

这里是进入输入节点并且做静态分析,看返回的值是true或者false,如果不能确定,返回undefined

//  返回true、false或者undefined
exports.evaluateTruthy = evaluateTruthy;
//  返回一个对象,里面有详细信息
exports.evaluate = evaluate;

[七]family.js相关api

这个文件主要处理子元素和兄弟元素

//  获得对位的兄弟元素
exports.getOpposite = getOpposite;
//  获得完整路径记录
exports.getCompletionRecords = getCompletionRecords;
//  传入key,获得兄弟节点
exports.getSibling = getSibling;
//  获得上一个兄弟节点
exports.getPrevSibling = getPrevSibling;
//  获得下一个兄弟节点
exports.getNextSibling = getNextSibling;
//  获得所有的下方的兄弟节点
exports.getAllNextSiblings = getAllNextSiblings;
//  获得所有上方的兄弟节点
exports.getAllPrevSiblings = getAllPrevSiblings;
//  根据key和上下文,传入节点
exports.get = get;
//  配合get使用
exports._getKey = _getKey;
//  配合get使用
exports._getPattern = _getPattern;
//  获得绑定的标识符
exports.getBindingIdentifiers = getBindingIdentifiers;
//  获得外部绑定的标识符
exports.getOuterBindingIdentifiers = getOuterBindingIdentifiers;
//  获得绑定的标识符路径
exports.getBindingIdentifierPaths = getBindingIdentifierPaths;
//  获得外部绑定的标识符路径
exports.getOuterBindingIdentifierPaths = getOuterBindingIdentifierPaths;

[八]introspection.js相关api

此文件包含负责为某些值内省当前路径的方法。

//  输入一个pattern,返回符合条件的节点
exports.matchesPattern = matchesPattern;
//  输入一个key,判断当前节点是否含有这个属性
exports.has = has;
//  判断是否是静态节点
exports.isStatic = isStatic;
//  节点是否不含有某个输入的key,与has相反
exports.isnt = isnt;
//  传入key和value,判断当前节点上key对应的值是否等于value
exports.equals = equals;
//  输入类型字符串,判断当前节点的类型是否和出入的类型相等
exports.isNodeType = isNodeType;
//  判断当前路径是合处在for循环中。因为for循环中允许变量声明和普通的表达式,我们需要告诉path的replactment相关方法
//  在这里替换掉表达式是ok的
exports.canHaveVariableDeclarationOrExpression = canHaveVariableDeclarationOrExpression;
//  这个方法减产我们是否在将箭头函数转换为表达式或者代码块(反之亦然),这是因为
//  箭头函数会隐式地返回表达式,这和块语句类似
exports.canSwapBetweenExpressionAndStatement = canSwapBetweenExpressionAndStatement;
//  判断当前路径是否指向一个完成的记录(是否是一个容器的最后的节点)
exports.isCompletionRecord = isCompletionRecord;
//  判断当前的节点是否允许单独的声明或者块声明,以便我们在必要的时候展开
exports.isStatementOrBlock = isStatementOrBlock;
//  判断当前的指定路径引用了moduleSource的importName
exports.referencesImport = referencesImport;
//  获取当前节点对应的源码
exports.getSource = getSource;
//  有可能会提前执行
exports.willIMaybeExecuteBefore = willIMaybeExecuteBefore;
//  传入一个节点,判断其执行状态是否和当前的节点相关
exports._guessExecutionStatusRelativeTo = _guessExecutionStatusRelativeTo;
exports._guessExecutionStatusRelativeToDifferentFunctions = _guessExecutionStatusRelativeToDifferentFunctions;
//  将一个指针node节点指向绝对路径
exports.resolve = resolve;
exports._resolve = _resolve;
//  是否是固定表达式
exports.isConstantExpression = isConstantExpression;
//  是否处于严格模式
exports.isInStrictMode = isInStrictMode;
//  has的别名
exports.is = void 0;

[九]modification.js相关api

//  在当前节点之前插入目标节点
exports.insertBefore = insertBefore;
//  传入位置和节点,在对应的位置插入节点
exports._containerInsert = _containerInsert;
//  在目标节点之前插入
exports._containerInsertBefore = _containerInsertBefore;
//  在目标节点之后插入
exports._containerInsertAfter = _containerInsertAfter;
//  在当前的节点之后插入,但在一个表达式之后插入的时候,确保完成记录是正确的
exports.insertAfter = insertAfter;
//  传入两个参数(起点,终点),更新期间所有兄弟节点的路径
exports.updateSiblingKeys = updateSiblingKeys;
//  校验节点列表
exports._verifyNodeList = _verifyNodeList;
//  容器列表头部新增一个元素
exports.unshiftContainer = unshiftContainer;
//  容器列表尾部新增一个元素
exports.pushContainer = pushContainer;
//  尽可能提升当前节点的作用域,并且返回一个可以引用的uid
exports.hoist = hoist;

[十]removal.js相关api

移除节点相关的api

//  移除当前节点
exports.remove = remove;
//  从作用域中移除
exports._removeFromScope = _removeFromScope;
//  是否调用移除钩子
exports._callRemovalHooks = _callRemovalHooks;
//  内部的remove实现
exports._remove = _remove;
//  标记移除
exports._markRemoved = _markRemoved;
//  声明某个节点不可以出
exports._assertUnremoved = _assertUnremoved;

[十一]replacement.js相关api

跟节点替换相关api

//  将当前节点替换为一系列节点(出入的是一个节点数组),该方法按照以下步骤执行
//  1、继承传入的第一个节点的注释 2、在当前的节点后插入传入的节点 3、删除当前节点
exports.replaceWithMultiple = replaceWithMultiple;
//  将传入字符串作为表达式解析,并且将当前的节点替换为解析的结果
//  这个方法很方便,但是是反模式的,不建议使用,这会使你的应用很脆弱
exports.replaceWithSourceString = replaceWithSourceString;
//  将当前节点替换为另一个
exports.replaceWith = replaceWith;
//  内部实现
exports._replaceWith = _replaceWith;
//  输入一个声明数组并且将他们在表达式中展开。这个方法将会保持完整的记录,这对于维护原始的语义非常重要
exports.replaceExpressionWithStatements = replaceExpressionWithStatements;
//  替换行内内容
exports.replaceInline = replaceInline;

找到一个各种函数详细解释的网站:

Document

4.AST 节点类型对照表

序号 类型原名称 中文名称 描述
1 Program 程序主体 整段代码的主体
2 VariableDeclaration 变量声明 声明一个变量,例如 var let const
3 FunctionDeclaration 函数声明 声明一个函数,例如 function
4 ExpressionStatement 表达式语句 通常是调用一个函数,例如 console.log()
5 BlockStatement 块语句 包裹在 {} 块内的代码,例如 if (condition){var a = 1;}
6 BreakStatement 中断语句 通常指 break
7 ContinueStatement 持续语句 通常指 continue
8 ReturnStatement 返回语句 通常指 return
9 SwitchStatement Switch 语句 通常指 Switch Case 语句中的 Switch
10 IfStatement If 控制流语句 控制流语句,通常指 if(condition){}else{}
11 Identifier 标识符 标识,例如声明变量时 var identi = 5 中的 identi
12 CallExpression 调用表达式 通常指调用一个函数,例如 console.log()
13 BinaryExpression 二进制表达式 通常指运算,例如 1+2
14 MemberExpression 成员表达式 通常指调用对象的成员,例如 console 对象的 log 成员
15 ArrayExpression 数组表达式 通常指一个数组,例如 [1, 3, 5]
16 NewExpression New 表达式 通常指使用 New 关键词
17 AssignmentExpression 赋值表达式 通常指将函数的返回值赋值给变量
18 UpdateExpression 更新表达式 通常指更新成员值,例如 i++
19 Literal 字面量 字面量
20 BooleanLiteral 布尔型字面量 布尔值,例如 true false
21 NumericLiteral 数字型字面量 数字,例如 100
22 StringLiteral 字符型字面量 字符串,例如 vansenb
23 SwitchCase Case 语句 通常指 Switch 语句中的 Case

以下内容来源:GitHub - coder-gao/Spider: 爬虫, 反爬虫, JS 逆向, 安卓逆向, AST

节点属性及方法

enter(默认)与 exit 的区别

5.一些结构及函数

内容来自:带你玩转babel工具链(二)@babel/traverse - 掘金

pathNode {// 属性:node // 当前 AST 节点parent // 父 AST 节点parentPath // 父 AST 节点的 pathscope // 作用域hub // 可以通过 path.hub.file 拿到最外层 File 对象, path.hub.getScope 拿到最外层作用域,path.hub.getCode 拿到源码字符串container // 当前 AST 节点所在的父节点属性的属性值key // 当前 AST 节点所在父节点属性的属性名或所在数组的下标listKey // 当前 AST 节点所在父节点属性的属性值为数组时 listkey 为该属性名,否则为 undefined
}

那么scope有哪些属性呢?

  • scope.bindings 当前作用域内声明的所有变量

  • scope.block 生成作用域的 block,例如FunctionDeclaration, Program等AST节点

  • scope.path 生成作用域的节点对应的 path,例如FunctionDeclaration, Program等AST节点的path

  • scope.references 所有 binding 的引用对应的 path,详见下文

  • scope.dump() 打印作用域链的所有 binding 到控制台

  • scope.parentBlock() 父级作用域的 block

  • getAllBindings() 从当前作用域到根作用域的所有 binding 的合并

  • getBinding(name) 查找某个 binding,从当前作用域一直查找到根作用域

  • getOwnBinding(name) 从当前作用域查找 binding

  • parentHasBinding(name, noGlobals) 查找某个 binding,从父作用域查到根作用域,不包括当前作用域。可以通过 noGlobals 参数指定是否算上全局变量(比如console,不需要声明就可用),默认是 false

  • removeBinding(name) 删除某个 binding

  • hasBinding(name, noGlobals) 从当前作用域查找 binding,可以指定是否算上全局变量,默认是 false

  • moveBindingTo(name, scope) 把当前作用域中的某个 binding 移动到其他作用域

  • generateUid(name) 生成作用域内唯一的名字,根据 name 添加下划线,比如 name 为 a,会尝试生成 _a,如果被占用就会生成 __a,直到生成没有被使用的名字。

上面的方法和属性有很多,就不一个个说明了,我们能通过scope很方便的操作作用域中的某个变量。完全不需要我们手动去获取对应的AST了!

其他值得学习知识:

AST  deObfuscator   AST 反混淆  js逆向

js逆向技巧分享 - 知乎

https://www.codenong.com/cs106567825/

ob混淆AST | 一只橘子的思考

https://www.mdeditor.tw/pl/puBb

https://www.jianshu.com/p/7c8c5ae1e4be

利用AST对抗js混淆(一) 基础知识相关推荐

  1. 利用AST对抗js混淆(三) 控制流平坦化(Control Flow Flattening)的处理

    控制流平坦化 参考:https://security.tencent.com/index.php/blog/msg/112 控制流平坦化,简单来讲就是将代码块之间的关系打断,由一个分发器来控制代码块的 ...

  2. js打印,基础知识,数据类型

    打印,基础知识,数据类型 <!DOCTYPE html> <html><head><meta charset="utf-8" />& ...

  3. 云笔记项目-补充JS面向对象编程基础知识

    简单介绍: 此部分知识为在做云笔记项目中补充,因为云笔记项目中涉及到前端js,里面写了很多js脚本,用到了创建js属性和方法,在js中直接声明的属性和方法最终都会变成window的对象,即其成为了全局 ...

  4. Python操作AST解JS混淆

    通过生成语法树(AST),可快速修改代码中的一些混淆处理,从而简化代码,便于后续分析. 本文通过Python来把JS转为AST并进行简单的操作,内容很简单. 比如我们下图中的JS代码,有sum和min ...

  5. 爬虫 JavaScript 逆向进阶!利用 AST 技术还原混淆代码

    这是「进击的Coder」的第 617 篇技术分享 作者:K 小哥 来源:K 哥爬虫 " 阅读本文大概需要 47 分钟. " 目录 文章较长,可作为 AST Babel 入门手册,强 ...

  6. [Vue.js 1] 入门基础知识与开发

    最近接触的几个项目框架全部用到了Vue.js技术,没办法只能对vuejs进行深入学习,不过可喜的是Vue.js学习路线非常快,上手也是非常快的,所以对于前端开发也是主流的开发框架了.不过其中的js部分 ...

  7. JS学习笔记——入门基础知识总结

    JS入门基础知识总结1 前言 基础背景知识 一.产生历史: 二.特点: 三.应用方向: 四.Javascript组成: JavaScript书写使用方式 一.行内式(了解即可,项目中不使用,日常练习尽 ...

  8. JavaScript基础知识与脚本语言总结

    1 Aptana插件安装 1.Aptana插件安装 <1>Aptana是一个非常强大,开源,JavaScript-focused的AJAX开发IDE. <2>它的特点包括: J ...

  9. [Python图像识别] 四十九.图像生成之什么是生成对抗网络GAN?基础原理和代码普及

    该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门.OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子.图像增强技术.图像分割等,后期结合深度学习研究图像识别 ...

最新文章

  1. Yahoo为啥赚不到钱
  2. JAVA中protected的作用
  3. iview table 自定义列_基于VueJS的render渲染函数打造一款非常强大的IView 的Table组件...
  4. 日记 [2007年03月10日]重回blog,开始2007
  5. Visio—如何画矩形虚线边框?
  6. EXCEL如何新建自定义单元格以及样式怎么设置
  7. Programming WCF Services中文翻译(3)-契约
  8. SQL server2019安装教程
  9. Java已死?一眼就能看懂的Java自学手册,挑战大厂重燃激情!
  10. avr单片机流水灯程序c语言,动手学AVR单片机流水灯实验电路和程序实现.doc
  11. 防关联超级浏览器(超级防关联浏览器)的应用场景和技术原理
  12. python人机交互界面
  13. 【C语言】【结构体】复数类型加减乘除的实现
  14. 用C语言编辑一光年相当于多少米,一光年到底有多远?是光速跑了365天的距离,这样说你就少算了...
  15. 实验一 Java编程基础
  16. 【Modbus 】Modbus 协议
  17. 听说软件测试工程师们都在考ISTQB?
  18. 按照日期:蓝桥杯真题、洛谷题单、力扣题单汇总
  19. Oracle not in 范围超过 1000 报错问题及解决方案
  20. java websocket即时通讯+layui实现移动端一对一聊天客服功能

热门文章

  1. 智能家居产业,利润主要是从哪获得的?
  2. autoit 3常用快捷键
  3. 网站快速通过ICP备案的方法!
  4. KPI自动化异常检测系统——Opprentice
  5. IBM X3650 M4安装win 2008 Server操作指南
  6. 【转载】JConsole监控Tomcat简单配置
  7. 数字图像处理(十)腐蚀和膨胀
  8. C语言刷题(8)——“C”
  9. android 打开其它app,Android APP打开另一个APP的几种实现总结
  10. 「Python」数字推盘游戏-pygame