《JavaScript AST其实很简单》二、Step1-函数调用还原( 二 )


保存后在命令行中运行
node ob_step1.js
如果可以显示【 (()】 , 说明正常计算 。
而在中需要用到模块
with open('ob_step1.js', 'r', encoding='utf-8') as f:ctx = execjs.compile(f.read())resul = ctx.call('_0x166e', '0x305', '')print(resul)
此时一样可以得到【 (()】
3.递归还原
此时就可以递归获取所有名称为的节点 , 然后计算结果 , 基本的递归格式我是如下编写的 。
填写核心逻辑后 , 就可以递归获取所有参数 , 并进行调用还原 , 还原的结果要怎么塞回去呢?继续进行分析 , 可以看到所有的返回值都是字符串 , 那么字符串的类型就是 , 那么就可以自己构建一个节点 , 然后将源节点替换掉即可
def diguiyangli(node, Functionname, ctx):if type(node) == list:if node:for i in range(len(node)):diguiyangli(node[i], Functionname, ctx)elif type(node) == dict:for key in node.keys():if node[key]:if not type(node[key]) in [str, bool, int]:for eachkey in node[key].keys():if type(node[key][eachkey]) == dict:if 'type' in node[key][eachkey].keys():if node[key][eachkey]['type'] == 'CallExpression':# 获取类型为CallExpression的节点if 'name' in node[key][eachkey]['callee'].keys():if node[key][eachkey]['callee']['name'] == Functionname:# 获取指定函数调用名的节点if len(node[key][eachkey]['arguments']) == 2:# 获取函数调用的参数arg1, arg2 = node[key][eachkey]['arguments']arg1 = arg1['value']arg2 = arg2['value']else:arg1 = node[key][eachkey]['arguments'][0]['value']arg2 = ''value = http://www.kingceram.com/post/ctx.call(Functionname, arg1, arg2)# 创建一个Literal节点returnobject = {'type': 'Literal', 'value': value}# 替换原来节点node[key][eachkey] = returnobjectdiguiyangli(node[key], Functionname, ctx)
【《JavaScript AST其实很简单》二、Step1-函数调用还原】经过一系列的调用还原后 , 输出js代码 , 并将其格式化如下图
可以看到 , 原来的
'VlwGE': _0x166e('0x305')
已经被替换为
'VlwGE': 'return (function() '
此时第一步已经完成 , 那么前三个节点已经没有用了 , 将前三个节点删除后 , 就是第一步反混淆的最终结果.
备注:源文件见最下方附件内的.txt
附件地址: