搜尋
首頁web前端js教程Javascript逆向與反逆向

Javascript逆向與反逆向

Dec 05, 2017 am 10:25 AM
javascriptjs逆向

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     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['RegExp']('/R[\S]{4}p.c\wn[\D]{5}t\wr/','g')['test'](T + '')<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
從C/C到JavaScript:所有工作方式從C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript引擎:比較實施JavaScript引擎:比較實施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

超越瀏覽器:現實世界中的JavaScript超越瀏覽器:現實世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

如何使用Next.js(前端集成)構建多租戶SaaS應用程序如何使用Next.js(前端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:22 AM

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript:探索網絡語言的多功能性JavaScript:探索網絡語言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的演變:當前的趨勢和未來前景JavaScript的演變:當前的趨勢和未來前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

神秘的JavaScript:它的作用以及為什麼重要神秘的JavaScript:它的作用以及為什麼重要Apr 09, 2025 am 12:07 AM

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

See all articles

熱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.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能