AST 技巧:使用 AST 分析函数执行路径 "更新" + 对比技巧
大家好,昨天的文章中提到了使用 AST 自动打印函数的执行路径的方法,今天在反混淆另一个 JS 文件的时候我发现了一个问题,所以我对这个功能进行了优化,并且一同分享一下如何对 nodejs
中执行的函数路径和浏览器中执行的函数路径进行快速对比。
函数执行路径
昨天的代码如下:
1 | traverse(ast, { |
在实际的反混淆中,发现有的 JS 文件混淆后的函数名是一个字符,所以执行的结果可能会是这样的:
就一堆字符,啥也看不出来,b
这个函数名可能在整个 JS 文件的多个地方使用,这样也无法分辨到底是调用了哪个函数。
为了能更好的打印函数的执行路径,需要对上面的 AST 代码进行修改。想了一下,既然每个函数可以在 JS 文件的多个位置使用,那如何定位多个同名的函数呢?可以使用 JS 文件天然自带的属性,行号!使用 AST 的方式将函数名和函数所在的行号一起打印出来。
如何知道当前被调用的函数在哪一行呢?不用担心,babel 库都为我们准备好了,来看一下 AST 网站的解析结果:
在 babel 的解析结果中,是有一个 loc
属性,它里面保存了当前节点的源代码所在的行号,这样就能在 AST 中获取函数所在的行号了。
修改代码如下:
1 | traverse(ast, { |
虽然还是有些简陋哈哈哈,不过最起码知道了当前被调用的函数在哪一行了,不会再出现重名的函数了,因为同一行不会出现两个函数定义,除非你在使用 AST 前没有进行格式化。
注:这里未处理匿名函数,有需要的小伙伴可以自行处理
行号不准
在使用上面的 AST 代码处理完成以后,查看处理后的源代码,会发现日志中的行号不准确?
计算日志中的行号和实际行号的差值,发现差值还不一样,这是为什么呢?仔细想一想,在使用 AST 解析代码的时候,行号获取的是使用 AST 处理之前的代码的行号,如下图:
在使用 AST 处理完成以后,会在每个函数的第一行添加一行日志,这样导致整个 JS 文件中就多了一行日志打印,有多少函数就要增加多少日志输出语句,但是日志输出语句也要占用一行啊,所以后面的代码只能被往后挤,导致最终的行号和日志中不一致。
更正行号
那么如何更正行号不准的问题呢?考虑一下,是不是先把日志语句加上,把行先给占用了,然后再更新行号就可以,这个时候由于没有新增行,所以行号肯定和日志中的行号能对上。
修改代码如下:
1 | traverse(ast, { |
运行以上代码,查看修改后的结果:
现在日志中的行号和函数实际所在位置就完全一样了,可以根据日志找到对应的函数,函数被调用了多少次,被谁调用了都一目了然。
核对执行路径
将修改过的代码替换到浏览器中执行,会打印出执行的函数和对应的行号,右键点击复制控制台日志,将日志复制到 pycharm 的临时文件中。
使用替换功能,正则表达式替换,将所有的 JS 文件信息去掉,只保留函数名和行号,方便后面进行比对。
在本地的同一个文件中重复调用相同的函数,注意一定要是同一个文件,不然输出的函数名和行号会对不上!
将调用后输出的结果复制到剪切板,一定要是剪切板哦,然后点击图中的与剪切板比较按钮。
pycharm 会自动对比剪切板的数据和临时文件的数据哪里不一致,就和 Git 的 diff
命令很类似,从图上可以看到,浏览器的执行结果相比于 nodejs 的执行结果多了一些函数调用。
至于为什么多了这么多函数调用,关键的原因就在第 11
行的 n
函数中,查看 n
函数的执行逻辑即可。正常来说 n
函数会被调用两次,但是实际在 nodejs 中只调用了一次,可能是由于某些判断和浏览器不一样导致的,后续就是具体原因具体分析了。
总结
到这里函数路径打印这个功能就变得比较实用了,如果大家遇到类似的需求可以使用上面的代码试一试,可以快速的找到代码中执行逻辑和浏览器不同的地方,方便快速修复环境。当然了,在补环境的时候可以结合代理一起使用,没什么方法是一劳永逸的,多种方法可以共同使用,才能事半功倍。此方法也不止可以在补环境的时候使用,在扣代码的时候一样使用,更多使用方法就靠大家来摸索了。
本文章首发于个人博客 LLLibra146’s blog
本文作者:LLLibra146
更多文章请关注公众号 (LLLibra146):
版权声明:本博客所有文章除特别声明外,均采用 © BY-NC-ND 许可协议。非商用转载请注明出处!严禁商业转载!