您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > javascript

JavaScript 的 Anti-Debugging 技術

时间:2023-05-20 14:02:17  来源:今日头条  作者:闪念基因

 

JAVAScript 運行在客戶端,多數 Browser 亦有很強的 debugger,有時為了保護程式碼的邏輯不被破解或想要藏惡意程式之類的,會想辦法讓分析者沒辦法輕易分析原始碼。通常又可以分為阻撓靜態分析(例如 obfuscation)和動態分析(例如 anti-debugging)。這篇文章會介紹 JavaScript 的一些 anti-debugging 的方法,討論可以如何讓分析者沒辦法在 browser 上用 debugger 或甚至偵測自己是否正在被 debug,並分析他們的優劣與可能破解方法。

這篇文章是 U Can’t Debug This: Detecting JavaScript Anti-Debugging Techniques in the Wild 的部份重點整理,該文發表於 USENIX Security 2021。該文其實遠不只 anti-debugging 技術,不過因為他們分析做得很好,所以想針對這部份做重點整理。

背景

雖然我猜會看這篇文章的人應該都有概念 debugging 長怎樣,不過還是簡單講一下。一般來說,如果要在 browser 上做 debugging,通常會使用 DevTool 給的 Debugger。召喚方法大概是這樣的:對著網頁(恩,你現在就正在看的)點右鍵,按「檢視」 / “Inspect”(至少在 Firefox 上長這樣),就會看到 DOM 被解析的樣子,然後點 Debugger,便可以看到 JavaScript code,也可以下 breakpoint。除了人工上 breakpoint,也可以在 JavaScript code 裡面用 debugger 直接下 breakpoint。

為了避免自己的 code 分析,有些人會希望阻撓 manual analysis,或更好的狀況是,知道自己正在被 debug,也許可以有不同的行為(例如很多 malware 可能發現自己正在被分析,就開始裝死以隱藏其原先的 behavior)。我們大致可以把策略分成三種:阻礙 debug、改變 debugger 行為、偵測是否在 debug。

阻礙 Debugger 開啟

一、攔截 DevTools 開啟的快捷鍵

一種雖然無腦但偶而會有效的方法是,直接禁止使用者嘗試打開 DevTools,自然也就沒辦法使用 debugger 了。一般來說打開 DevTools 有三種方法:按 F12、點右鍵選「檢視」(如前述)、從瀏覽器選單找到 DevTools。前兩種方法在使用時都會在網頁上觸發一些 event,例如按鍵盤會有 keydown,滑鼠點右鍵會有 oncontextmenu,只要去聽特定的 event 並阻撓其行為,就可以避免 DevTools 開啟。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
window.addEventListener("keydown", function(event){
    if (event.key == "F12") {
        event.preventDefault();
        return false;
    }
});
window.oncontextmenu = (event) => {
    event.preventDefault();
    return false;
};

然而破解方法也很簡單,一來是如果要看 source code,大可直接用 view-source: ...,二來是就算真的想用 DevTools,從瀏覽器選單選 DevTools 就可以了。

二、塞入大量 breakpoint

另一種惱人的方法是,在 code 裡面塞一堆 debugger 來預設 breakpoint,一般來說執行時 runtime 會直接忽略這些 breakpoint,但只要分析者一打開 debugger,把上就會被一堆 breakpoint 阻撓,完全沒辦法順利 debug。

不過要阻止的方法很簡單。首先,有些 browser 可以設定忽略特定 breakpoint,不過可以透過不斷建立新的 anonymous function 並在其中塞 debugger 來解決(因為對 browser 來說,anonymous function 的 breakpoint 是全新、未見過的)。另一個方法則是直接忽略特定區段裡面的所有 debugger,有些 browser extension 可以作到這件事。

三、不斷清除 console

有些人 debug 的習慣是把訊息 output 到 console,或是可以透過在 console 執行一些 code 來改變變數數值,藉此分析程式行為。因此,如果不斷地用 console.clear 把 console 清空,會對分析者造成不小的困擾。

1
2
3
setInterval(function() {
    console.clear();
}, 100);

改變 Debugger 行為

四、覆蓋掉預設 function 的行為

JavaScript 有個令人又愛又恨的特性是,幾乎所有的內建 function 都可以被覆蓋。許多人 debug 時會仰賴 console.log 或 alert,只要覆蓋掉某些 function,就有機會阻止分析者 debug,甚至適時地回報某個分析者可能正在嘗試 debug。

舉例來說,Spotify 之前有一段 code 就覆蓋掉 alert 預設的行為,因為不少 bug hunter 會用 alert來檢驗 XSS 有沒有成功,如此則就算 XSS 成功呼叫 alert,也只會偷偷地回傳參數,而不會真的噴出彈跳視窗。

1
2
3
4
5
6
7
8
// WrApping funcs in a nAIve attempt to catch externally found XSS vulns
(function(fn) {
	window.alert = function() {
		var args = Array.prototype.slice.call(arguments);
		_doLog('alert', args);
		return fn.apply(window, args);
	};
}(window.alert));

除此之外,也有人會透過把 console.log 覆蓋成空函數來讓分析者沒辦法順利使用 console 來 debug。

偵測是否在 Debug

五、比較視窗寬度高度

DevTools 開啟會佔用螢幕空間,如果能偵測到高度差異,便有可能知道使用者是否有打開 DevTools。在 JavaScript,可以透過 innerHeight / innerWidth 與 outerHeight / outerWidth 來取得網頁本身大小(inner)以及整個視窗的大小(outer),如果兩者相異過大,也許就代表 DevTools 正在開啟導致 innerHeight / innerWidth 縮小了。

1
2
3
4
5
6
setInterval(() => {
    if (outerWidth - innerWidth > threshold ||
    	outerHeight - innerHeight > threshold) {
    	// DevTools are open.
    }
}, 500);

這個方法的缺點有二:首先,並非每個會改變 innerHeight / innerWidth 的都是 DevTools,其他如書籤列之類的也都會改變之,這樣會導致 false positive;此外,如果在另一個視窗開啟 DevTools 便可以不改變 innerHeight / innerWidth,造成 false negative。

六、Log Custom Getter

這個方法比較像是一系列 anti-debugging 方法的分類而非特定的方法。當 DevTools 開啟時,可能會因為各種原因而讓 DevTools 去存取一些 object 的特定 method 或 attribute,透過在這些 method 或 attribute 上設 getter,就可以知道有沒有任何 code 去嘗試存取之。

舉例來說,在過去三年,只要 DevTools 開啟時,基於某些原因,DevTools 會去存取 object 的 id,所以可以在 id 上設定一個 getter, 如果發現有程式嘗試存取之,就知道 DevTools 被打開了。不過這方法目前失效了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// https://stackoverflow.com/a/30638226
let checkStatus;
let element = document.createElement('any');
element.__defineGetter__('id', function() {
    // DevTools are open.
});

setInterval(function() {
    // This function call would access `id` if the DevTools are open.
    console.log(element);
}, 1000);

另一個方法則是,console.log 的字串會一直 delay 到 console 被打開的那一刻才會被 render,所以如果去監視一個物件的 toString 有沒有被呼叫,就可以知道 DevTools 有沒有打開。不過這方法目前一樣是失效了。

1
2
3
4
5
let logme = function(){ };
logme.toString = function() {
  // DevTools are open.
}
console.log('%c', logme);

可惜這些技巧所用的 bug 幾乎都已經被 patch 了。

上述兩個方法都屬於使用 DevTools 的基本性質來做偵測,這些方法通常很容易被繞過或是被 patch。下面三者則會嘗試使用時間的特性來偵測 Debugger 是否有被開啟。

七、監視已知 Breakpoint 執行時間

如同在第二點所說,如果 DevTools 有開啟,則遇到 debugger 時會進入 breakpoint,讓分析者使用 debugger 時感到很困擾。但除了造成困擾以外,我們也可以透過檢查 debugger 指令的執行時間來知道現在 DevTools 是否有被開啟。簡單來說,假設 DevTools 有開啟,執行時 breakpoint 會把 runtime 暫停,則重新開始後會發現過了一段時間,可是假設 DevTools 沒有開啟,則 breakpoint 被忽略,如此 debugger 將非常快地被略過。透過這個性質就可以知道 DevTools 有沒有開啟。

1
2
3
4
5
6
7
8
9
function measure() {
    const start = performance.now();
    debugger;
    const time = performance.now() - start;
    if (time > 100) {
        // DevTools are open.
    }
}
setInterval(measure, 1000);

這個方法雖然就跟第二點一樣,可以很輕易地透過關掉所有或特定區段的 breakpoint 來解決,然而我們在此的目的是偵測 DevTools 是否有開啟,換言之,就算分析者之後關掉 breakpoint,只要第一次有成功卡住分析者,我們就知道這個使用者會使用 debugger 了。

然而這個方法有個缺點是,它非常明顯。一個有經驗的分析者如果發現自己被預設的 breakpoint 卡住,可能就會懷疑他是否已經被發現了。

八、監視 setInterval 兩次執行時間間距

另一個方法則是監測 setInterval 所設定的 function 的執行間距,理想上兩次緊鄰的執行應該時間差距要非常接近於一開始設定的 interval,只要出現顯著變化,就可能是分析者在任何一個地方下了 breakpoint 以致 function 沒有準時執行。然而缺點就是,如果分析者完全沒用到 breakpoint,則這個方法將不會奏效。此外,如果使用者切換到其他 tab,JS 的計時器可能會變不準確,所以還要額外檢查目前是否在這個 tab 上(document.focus)。

1
2
3
4
5
6
7
8
9
let threshold = 350;
function measure() {
    const diff = performance.now() - timeSinceLast;
    if (document.hasFocus() && diff > threshold) {
        // DevTools are open.
    }
    timeSinceLast = performance.now();
}
setInterval(measure, 300);

九、灌爆 console

另一個有趣的 side-channel 是透過大量寫入各種資訊並衡量所需時間。

以前有一種方法是,不斷地建立新的 DOM element,並計算所需時間,如果所需時間太長,可能就是 DevTools 有開啟,因為當 DevTools 開啟時若 DOM tree 有改變則會需要在 DevTools 中標示出改變,這個動作很吃效能,會導致新增 DOM element 的速度變慢。然而這方法已經不能用了。

現在有另一個方法是,不斷寫資料到 console 並計算所需時間,如果所需時間過長,可能就是瀏覽器忙著把資料輸出到 DevTools,代表 DevTools 有開啟。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
function measure() {
    const start = performance.now();
    for (let i = 0; i < 100; i++) {
        console.log(i);
        console.clear();
    }
    const time = performance.now() - start;
    if (time > threshold) {
        // DevTools are open.
    }
}
setInterval(measure, 1000);

這個方法的一個缺陷是,如果使用者電腦太慢,可能會導致 false positive 或是拖垮網頁效能。

後記

以上總共討論了九種 anti-debugging 的方法。方法與 code 主要出自 U Can’t Debug This: Detecting JavaScript Anti-Debugging Techniques in the Wild,除了少數幾個範例為了呈現品質而有調整。另外我也參考了這篇 Stackoverflow 問題。如果想對這議題有更多了解,例如該怎麼偵測 anti-debugging techniques、哪些方法被廣泛使用之類的,可以看看原始論文。

  • Author: Allen Chou
  • Link: https://blog.allenchou.cc/post/js-anti-debugging/


Tags:JavaScript   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
17 个你需要知道的 JavaScript 优化技巧
你可能一直在使用JavaScript搞开发,但很多时候你可能对它提供的最新功能并不感冒,尽管这些功能在无需编写额外代码的情况下就可以解决你的问题。作为前端开发人员,我们必须了解...【详细内容】
2024-04-03  Search: JavaScript  点击:(5)  评论:(0)  加入收藏
你不可不知的 15 个 JavaScript 小贴士
在掌握如何编写JavaScript代码之后,那么就进阶到实践&mdash;&mdash;如何真正地解决问题。我们需要更改JS代码使其更简单、更易于阅读,因为这样的程序更易于团队成员之间紧密协...【详细内容】
2024-03-21  Search: JavaScript  点击:(27)  评论:(0)  加入收藏
使用 JavaScript 清理我的 200GB iCloud,有了一个意外发现!
本文作者在综合成本因素之下,决定用 Java 脚本来清理一下自己的 iCloud,结果却有了一个意外发现,即在 iCloud 中上传同一个视频和删除此视频之后,iCloud 的空间并不一致,这到底是...【详细内容】
2024-01-11  Search: JavaScript  点击:(99)  评论:(0)  加入收藏
JavaScript 真的是在 10 天内完成的吗?
起初网景公司用了十天时间创建了一个 Java,后来它成为事实上的 Web 标准,并横扫各大编程语言榜单成为开发者最受欢迎的语言之一。近日,有开发者对 Java 的开发周期提出了质疑,以...【详细内容】
2024-01-03  Search: JavaScript  点击:(83)  评论:(0)  加入收藏
创建一个双模式跨运行时的 JavaScript 包,你学会了吗
本文将指导你发布双模式、跨运行时的 JavaScript 包。了解如何创建与 ESM 和 CommonJS 以及 Node.js、Deno 和浏览器等不同运行时兼容的库。随着 JavaScript 开发的不断发展...【详细内容】
2023-12-27  Search: JavaScript  点击:(157)  评论:(0)  加入收藏
五种在 JavaScript 中创建对象的方法
在 JavaScript 中,对象是多功能工具,可以通过多种方式创建,每种方式适合不同的场景。了解何时使用每种方法是编写高效且可维护的 JavaScript 代码的关键。让我们探讨在 JavaScr...【详细内容】
2023-11-23  Search: JavaScript  点击:(235)  评论:(0)  加入收藏
GitHub:程序员正积极使用 AI 编程、JavaScript 语言依然最流行
IT之家 11 月 20 日消息,GitHub 发布了 2023 年度 Octoverse 开源状态报告,其中主要强调了 AI 在开发过程中的作用,并围绕云和 Git 的开源活动展开。官方介绍称,今年的三大趋势...【详细内容】
2023-11-20  Search: JavaScript  点击:(171)  评论:(0)  加入收藏
通过示例解释所有 JavaScript 数组方法
作为一名程序员,我们的工作是写有效的代码,但是仅仅写有效的代码,这还不够。如果想成为优秀的程序员,我们还需要编写可维护和可扩展的代码。JavaScript为我们提供了很多可以用来...【详细内容】
2023-11-15  Search: JavaScript  点击:(264)  评论:(0)  加入收藏
JavaScript 地位不保!WasmGC 将成为下一个“网红”?
整理 | 太冷不穿格子衫 出品 | 51CTO技术栈(微信号:blog51cto)早在 2017 年,主流浏览器都已经支持 WebAssembly。随着 WebAssembly 的蓬勃发展,各种编程语言也在增加对它的支持。...【详细内容】
2023-11-13  Search: JavaScript  点击:(216)  评论:(0)  加入收藏
Jest:目前最广泛使用的前端 JavaScript 测试框架
Jest 是一个简单易用的 JavaScript 测试框架。最初由 Meta 公司团队维护。2022 年 5 月,Meta 公司正式将自己的开源项目Jest 移交给 OpenJS Foundation[1],这表示 Jest 由公司...【详细内容】
2023-11-08  Search: JavaScript  点击:(341)  评论:(0)  加入收藏
▌简易百科推荐
17 个你需要知道的 JavaScript 优化技巧
你可能一直在使用JavaScript搞开发,但很多时候你可能对它提供的最新功能并不感冒,尽管这些功能在无需编写额外代码的情况下就可以解决你的问题。作为前端开发人员,我们必须了解...【详细内容】
2024-04-03  前端新世界  微信公众号  Tags:JavaScript   点击:(5)  评论:(0)  加入收藏
你不可不知的 15 个 JavaScript 小贴士
在掌握如何编写JavaScript代码之后,那么就进阶到实践&mdash;&mdash;如何真正地解决问题。我们需要更改JS代码使其更简单、更易于阅读,因为这样的程序更易于团队成员之间紧密协...【详细内容】
2024-03-21  前端新世界  微信公众号  Tags:JavaScript   点击:(27)  评论:(0)  加入收藏
又出新JS运行时了!JS运行时大盘点
Node.js是基于Google V8引擎的JavaScript运行时,以非阻塞I/O和事件驱动架构为特色,实现全栈开发。它跨平台且拥有丰富的生态系统,但也面临安全性、TypeScript支持和性能等挑战...【详细内容】
2024-03-21  前端充电宝  微信公众号  Tags:JS   点击:(25)  评论:(0)  加入收藏
构建一个通用灵活的JavaScript插件系统?看完你也会!
在软件开发中,插件系统为应用程序提供了巨大的灵活性和可扩展性。它们允许开发者在不修改核心代码的情况下扩展和定制应用程序的功能。本文将详细介绍如何构建一个灵活的Java...【详细内容】
2024-03-20  前端历险记  微信公众号  Tags:JavaScript   点击:(20)  评论:(0)  加入收藏
对JavaScript代码压缩有什么好处?
对JavaScript代码进行压缩主要带来以下好处: 减小文件大小:通过移除代码中的空白符、换行符、注释,以及缩短变量名等方式,可以显著减小JavaScript文件的大小。这有助于减少网页...【详细内容】
2024-03-13  WangLiwen    Tags:JavaScript   点击:(2)  评论:(0)  加入收藏
跨端轻量JavaScript引擎的实现与探索
一、JavaScript 1.JavaScript语言JavaScript是ECMAScript的实现,由ECMA 39(欧洲计算机制造商协会39号技术委员会)负责制定ECMAScript标准。ECMAScript发展史: 2.JavaScript...【详细内容】
2024-03-12  京东云开发者    Tags:JavaScript   点击:(2)  评论:(0)  加入收藏
面向AI工程的五大JavaScript工具
令许多人惊讶的是,一向在Web开发领域中大放异彩的JavaScript在开发使用大语言模型(LLM)的应用程序方面同样大有价值。我们在本文中将介绍面向AI工程的五大工具,并为希望将LLM...【详细内容】
2024-02-06    51CTO  Tags:JavaScript   点击:(53)  评论:(0)  加入收藏
JS小知识,使用这6个小技巧,避免过多的使用 if 语句
最近在重构我的代码时,我注意到早期的代码使用了太多的 if 语句,达到了我以前从未见过的程度。这就是为什么我认为分享这些可以帮助我们避免使用过多 if 语句的简单技巧很重要...【详细内容】
2024-01-30  前端达人  今日头条  Tags:JS   点击:(56)  评论:(0)  加入收藏
18个JavaScript技巧:编写简洁高效的代码
本文翻译自 18 JavaScript Tips : You Should Know for Clean and Efficient Code,作者:Shefali, 略有删改。在这篇文章中,我将分享18个JavaScript技巧,以及一些你应该知道的示例...【详细内容】
2024-01-30  南城大前端  微信公众号  Tags:JavaScript   点击:(68)  评论:(0)  加入收藏
使用 JavaScript 清理我的 200GB iCloud,有了一个意外发现!
本文作者在综合成本因素之下,决定用 Java 脚本来清理一下自己的 iCloud,结果却有了一个意外发现,即在 iCloud 中上传同一个视频和删除此视频之后,iCloud 的空间并不一致,这到底是...【详细内容】
2024-01-11    CSDN  Tags:JavaScript   点击:(99)  评论:(0)  加入收藏
站内最新
站内热门
站内头条