目录
文件结构" >文件结构
防止被逆向" >防止被逆向
利用工具巧妙破解反逆向" >利用工具巧妙破解反逆向
混淆加密方法一:隐藏方法调用,降低可读性" >混淆加密方法一:隐藏方法调用,降低可读性
混淆加密方法二:将函数定义加入到证书验证流程" >混淆加密方法二:将函数定义加入到证书验证流程
逆向思路:输出所有函数调用和参数" >逆向思路:输出所有函数调用和参数
首页 web前端 js教程 Javascript逆向与反逆向

Javascript逆向与反逆向

Dec 05, 2017 am 10:25 AM
javascript js 逆向

popunderjs 原来在 github 上是有开源代码的,但后来估计作者发现这个需求巨大的商业价值,索性不开源了,直接收费。所以现在要研究它的实现方案,只能上官网扒它源码了。

文件结构

script.js 是功能主体,实现了 popunder 的所有功能以及定义了多个 API 方法

license.demo.js 是授权文件,有这个文件你才能顺利调用 script.js 里的方法

防止被逆向

这么具有商业价值的代码,就这么公开地给你们用,肯定要考虑好被逆向的问题。我们来看看它是怎么反逆向的。

首先,打开控制台,发现2个问题:

  1. 控制台所有内容都被反复清空,只输出了这么一句话: Console was cleared script.js?0.5309098417125133:1

  2. 无法断点调试,因为一旦启用断点调试功能,就会被定向到一个匿名函数 (function() {debugger})

也就是说,常用的断点调试方法已经无法使用了,我们只能看看源代码,看能不能理解它的逻辑了。但是,它源代码是这样的:

<span style="font-size: 16px;">var a = typeof window === S[0] && typeof window[S[1]] !== S[2] ? window : global;<br>    try {<br>        a[S[3]](S[4]);<br>        return function() {}<br>        ;<br>    } catch (a) {<br>        try {<br>            (function() {}<br>            [S[11]](S[12])());<br>            return function() {}<br>            ;<br>        } catch (a) {<br>            if (/TypeError/[S[15]](a + S[16])) {<br>                return function() {}<br>                ;<br>            }<br>        }<br>    }<br></span>
登录后复制

 

可见源代码是根本不可能阅读的,所以还是得想办法破掉它的反逆向措施。

利用工具巧妙破解反逆向

首先在断点调试模式一步步查看它都执行了哪些操作,突然就发现了这么一段代码:

<span style="font-size: 16px;">(function() {<br>    (function a() {<br>        try {<br>            (function b(i) {<br>                if (('' + (i / i)).length !== 1 || i % 20 === 0) {<br>                    (function() {}<br>                    ).constructor('debugger')();<br>                } else {<br>                    debugger ;<br>                }<br>                b(++i);<br>            }<br>            )(0);<br>        } catch (e) {<br>            setTimeout(a, 5000);<br>        }<br>    }<br>    )()<br>}<br>)();<br></span>
登录后复制

 

这段代码主要有2部分,一是通过 try {} 块内的 b() 函数来判断是否打开了控制台,如果是的话就进行自我调用,反复进入 debugger 这个断点,从而达到干扰我们调试的目的。如果没有打开控制台,那调用 debugger 就会抛出异常,这时就在 catch {} 块内设置定时器,5秒后再调用一下 b() 函数。

这么说来其实一切的一切都始于 setTimeout 这个函数(因为 b() 函数全是闭包调用,无法从外界破掉),所以只要在 setTimeout 被调用的时候,不让它执行就可以破解掉这个死循环了。

所以我们只需要简单地覆盖掉 setTimeout 就可以了……比如:

<span style="font-size: 16px;">window._setTimeout = window.setTimeout;<br>window.setTimeout = function () {};<br></span>
登录后复制

 

但是!这个操作无法在控制台里面做!因为当你打开控制台的时候,你就必然会被吸入到 b() 函数的死循环中。这时再来覆盖 setTimeout 已经没有意义了。

这时我们的工具 TamperMonkey 就上场了,把代码写到 TM 的脚本里,就算不打开控制台也能执行了。

TM 脚本写好之后,刷新页面,等它完全加载完,再打开控制台,这时 debugger 已经不会再出现了!

接下来就轮到控制台刷新代码了

通过 Console was cleared 右侧的链接点进去定位到具体的代码,点击 {} 美化一下被压缩过的代码,发现其实就是用 setInterval 反复调用 console.clear() 清空控制台并输出了

Console was cleared

信息,但是注意了,不能直接覆盖 setInterval 因为这个函数在其他地方也有重要的用途。

所以我们可以通过覆盖 console.clear() 函数和过滤 log 信息来阻止它的清屏行为。

同样写入到 TamperMonkey 的脚本中,代码:

<span style="font-size: 16px;">window.console.clear = function() {};<br>window.console._log = window.console.log;<br>window.console.log = function (e) {<br>    if (e['nodeName'] && e['nodeName'] == 'p') {<br>        return ;<br>    }<br>    return window.console.error.apply(window.console._log, arguments);<br>};<br></span>
登录后复制

 

之所以用 error 来输出信息,是为了查看它的调用栈,对理解程序逻辑有帮助。

基本上,做完这些的工作之后,这段代码就可以跟普通程序一样正常调试了。但还有个问题,它主要代码是经常混淆加密的,所以调试起来很有难度。下面简单讲讲过程。

混淆加密方法一:隐藏方法调用,降低可读性

从 license.demo.js 可以看到开头有一段代码是这样的:

<span style="font-size: 16px;">var zBCa = function T(f) {<br>    for (var U = 0, V = 0, W, X, Y = (X = decodeURI("+TR4W%17%7F@%17.....省略若干"),<br>    W = '',<br>    'D68Q4cYfvoqAveD2D8Kb0jTsQCf2uvgs'); U < X.length; U++,<br/>    V++) {<br/>        if (V === Y.length) {<br/>            V = 0;<br/>        }<br/>        W += String["fromCharCode"](X["charCodeAt"](U) ^ Y["charCodeAt"](V));<br/>    }<br/>    var S = W.split("&&");<br/></span>
登录后复制

通过跟踪执行,可以发现 S 变量的内容其实是本程序所有要用到的类名、函数名的集合,类似于 var S = ['console', 'clear', 'console', 'log'] 。如果要调用 console.clear() 和 console.log() 函数的话,就这样

<span style="font-size: 16px;">var a = window;<br/>a[S[0]][S[1]]();<br/>a[S[2]][S[3]]();<br/></span>
登录后复制

混淆加密方法二:将函数定义加入到证书验证流程

license.demo.js 中有多处这样的代码:

<span style="font-size: 16px;">a[&#39;RegExp&#39;](&#39;/R[\S]{4}p.c\wn[\D]{5}t\wr/&#39;,&#39;g&#39;)[&#39;test&#39;](T + &#39;&#39;)<br/></span>
登录后复制

这里的 a 代表 window,T 代表某个函数, T + '' 的作用是把 T 函数的定义转成字符串,所以这段代码的意思其实是,验证 T 函数的定义中是否包含某些字符。

每次成功的验证,都会返回一个特定的值,这些个特定的值就是解密核心证书的参数。

可能是因为我重新整理了代码格式,所以在重新运行的时候,这个证书一直运行不成功,所以后来就放弃了通过证书来突破的方案。

逆向思路:输出所有函数调用和参数

通过断点调试,我们可以发现,想一步一步深入地搞清楚这整个程序的逻辑,是十分困难,因为它大部分函数之间都是相互调用的关系,只是参数的不同,结果就不同。

所以我后来想了个办法,就是只查看它的系统函数的调用,通过对调用顺序的研究,也可以大致知道它执行了哪些操作。

要想输出所有系统函数的调用,需要解决以下问题:

  1. 覆盖所有内置变量及类的函数,我们既要覆盖 window.console.clear() 这样的依附在实例上的函数,也要覆盖依附在类定义上的函数,如 window.HTMLAnchorElement.__proto__.click()

  2. 需要正确区分内置函数和自定义函数

经过搜索后,找到了区分内置函数的代码:

<span style="font-size: 16px;">// Used to resolve the internal `[[Class]]` of values<br/>  var toString = Object.prototype.toString;<br/><br/>  // Used to resolve the decompiled source of functions<br/>  var fnToString = Function.prototype.toString;<br/><br/>  // Used to detect host constructors (Safari > 4; really typed array specific)<br>  var reHostCtor = /^\[object .+?Constructor\]$/;<br><br>  // Compile a regexp using a common native method as a template.<br>  // We chose `Object#toString` because there's a good chance it is not being mucked with.<br>  var reNative = RegExp('^' +<br>    // Coerce `Object#toString` to a string<br>    String(toString)<br>    // Escape any special regexp characters<br>    .replace(/[.*+?^${}()|[\]\/\\]/g, '\\$&')<br>    // Replace mentions of `toString` with `.*?` to keep the template generic.<br>    // Replace thing like `for ...` to support environments like Rhino which add extra info<br>    // such as method arity.<br>    .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'<br>  );<br><br>  function isNative(value) {<br>    var type = typeof value;<br>    return type == 'function'<br>      // Use `Function#toString` to bypass the value's own `toString` method<br>      // and avoid being faked out.<br>      ? reNative.test(fnToString.call(value))<br>      // Fallback to a host object check because some environments will represent<br>      // things like typed arrays as DOM methods which may not conform to the<br>      // normal native pattern.<br>      : (value && type == 'object' && reHostCtor.test(toString.call(value))) || false;<br>  }<br></span>
登录后复制

 

然后结合网上的资料,写出了递归覆盖内置函数的代码:

<span style="font-size: 16px;">function wrapit(e) {<br>    if (e.__proto__) {<br>        wrapit(e.__proto__);<br>    }<br>    for (var a in e) {<br>        try {<br>            e[a];<br>        } catch (e) {<br>            // pass<br>            continue;<br>        }<br>        var prop = e[a];<br>        if (!prop || prop._w) continue;<br><br>        prop = e[a];<br>        if (typeof prop == 'function' && isNative(prop)) {<br>            e[a] = (function (name, func) {<br>                return function () {<br>                    var args = [].splice.call(arguments,0); // convert arguments to array<br>                    if (false && name == 'getElementsByTagName' && args[0] == 'iframe') {<br>                    } else {<br>                        console.error((new Date).toISOString(), [this], name, args);<br>                    }<br>                    if (name == 'querySelectorAll') {<br>                        //alert('querySelectorAll');<br>                    }<br>                    return func.apply(this, args);<br>                };<br>            })(a, prop);<br>            e[a]._w = true;<br>        };<br>    }<br>}<br></span>
登录后复制

 

使用的时候只需要:

<span style="font-size: 16px;">wrapit(window);<br>wrapit(document);<br></span>
登录后复制

 

然后模拟一下正常的操作,触发 PopUnder 就可以看到它的调用过程了。

参考资料:

A Beginners’ Guide to Obfuscation Detect if function is native to browser Detect if a Function is Native Code with JavaScript

以上内容就是Javascript逆向与反逆向的教程,希望能帮助到大家。

相关推荐:

JavaScript中undefined与null的区别详解

JavaScript中confirm()方法的使用介绍

JavaScript中的后退与刷新的实例详解

以上是Javascript逆向与反逆向的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
威尔R.E.P.O.有交叉游戏吗?
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何使用WebSocket和JavaScript实现在线语音识别系统 如何使用WebSocket和JavaScript实现在线语音识别系统 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript实现在线语音识别系统引言:随着科技的不断发展,语音识别技术已经成为了人工智能领域的重要组成部分。而基于WebSocket和JavaScript实现的在线语音识别系统,具备了低延迟、实时性和跨平台的特点,成为了一种被广泛应用的解决方案。本文将介绍如何使用WebSocket和JavaScript来实现在线语音识别系

推荐:优秀JS开源人脸检测识别项目 推荐:优秀JS开源人脸检测识别项目 Apr 03, 2024 am 11:55 AM

人脸检测识别技术已经是一个比较成熟且应用广泛的技术。而目前最为广泛的互联网应用语言非JS莫属,在Web前端实现人脸检测识别相比后端的人脸识别有优势也有弱势。优势包括减少网络交互、实时识别,大大缩短了用户等待时间,提高了用户体验;弱势是:受到模型大小限制,其中准确率也有限。如何在web端使用js实现人脸检测呢?为了实现Web端人脸识别,需要熟悉相关的编程语言和技术,如JavaScript、HTML、CSS、WebRTC等。同时还需要掌握相关的计算机视觉和人工智能技术。值得注意的是,由于Web端的计

股票分析必备工具:学习PHP和JS绘制蜡烛图的步骤 股票分析必备工具:学习PHP和JS绘制蜡烛图的步骤 Dec 17, 2023 pm 06:55 PM

股票分析必备工具:学习PHP和JS绘制蜡烛图的步骤,需要具体代码示例随着互联网和科技的快速发展,股票交易已经成为许多投资者的重要途径之一。而股票分析是投资者决策的重要一环,其中蜡烛图被广泛应用于技术分析中。学习如何使用PHP和JS绘制蜡烛图将为投资者提供更多直观的信息,帮助他们更好地做出决策。蜡烛图是一种以蜡烛形状来展示股票价格的技术图表。它展示了股票价格的

WebSocket与JavaScript:实现实时监控系统的关键技术 WebSocket与JavaScript:实现实时监控系统的关键技术 Dec 17, 2023 pm 05:30 PM

WebSocket与JavaScript:实现实时监控系统的关键技术引言:随着互联网技术的快速发展,实时监控系统在各个领域中得到了广泛的应用。而实现实时监控的关键技术之一就是WebSocket与JavaScript的结合使用。本文将介绍WebSocket与JavaScript在实时监控系统中的应用,并给出代码示例,详细解释其实现原理。一、WebSocket技

如何利用JavaScript和WebSocket实现实时在线点餐系统 如何利用JavaScript和WebSocket实现实时在线点餐系统 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket实现实时在线点餐系统介绍:随着互联网的普及和技术的进步,越来越多的餐厅开始提供在线点餐服务。为了实现实时在线点餐系统,我们可以利用JavaScript和WebSocket技术。WebSocket是一种基于TCP协议的全双工通信协议,可以实现客户端与服务器的实时双向通信。在实时在线点餐系统中,当用户选择菜品并下单

如何使用WebSocket和JavaScript实现在线预约系统 如何使用WebSocket和JavaScript实现在线预约系统 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript实现在线预约系统在当今数字化的时代,越来越多的业务和服务都需要提供在线预约功能。而实现一个高效、实时的在线预约系统是至关重要的。本文将介绍如何使用WebSocket和JavaScript来实现一个在线预约系统,并提供具体的代码示例。一、什么是WebSocketWebSocket是一种在单个TCP连接上进行全双工

逆向坍塌面包房行动价格 逆向坍塌面包房行动价格 Mar 19, 2024 pm 05:13 PM

逆向坍塌面包房行动将于3月22日发售,很多玩家想知道逆向坍塌面包房行动多少钱,首周有折扣,价格为基础版80.36元,豪华版178.76元,具体内容一起来看看这篇逆向坍塌面包房行动价格介绍。逆向坍塌面包房行动价格答:首发折扣价格为基础版80.36元,豪华版178.76元。1、逆向坍塌面包房行动已经确定将于3月22日发售,首周有折扣,价格为基础版80.36元,豪华版178.76元。2、这是云母组早期作品面包房少女的重制版本,在画面、剧情、玩法上有很大的创新。3、故事发生在近未来时代,由于坍塌液污染所

JavaScript和WebSocket:打造高效的实时天气预报系统 JavaScript和WebSocket:打造高效的实时天气预报系统 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的实时天气预报系统引言:如今,天气预报的准确性对于日常生活以及决策制定具有重要意义。随着技术的发展,我们可以通过实时获取天气数据来提供更准确可靠的天气预报。在本文中,我们将学习如何使用JavaScript和WebSocket技术,来构建一个高效的实时天气预报系统。本文将通过具体的代码示例来展示实现的过程。We

See all articles