向Typora學習electron安全攻防

語言: CN / TW / HK

本文為看雪論壇優秀文章
看雪論壇作者ID:鈔能力大叔

目標應用: aHR0cHM6Ly90eXBvcmEuaW8v

越來越多的應用開始使用 electron 來構建跨平臺桌面應用。從實現方式上來說,其本質還是基於chrome核心的html、js、css構成的應用,基於瀏覽器,程式碼必定會暴露在使用者側,任何加密手段只是增加破解門檻跟時間成本而已。

認識electron專案檔案目錄特徵

electron打包的專案,最常見的就是 asar 格式的私有編碼檔案,裡面包含檔名、大小、內容偏移量等資料,按檔案頭部的 json內容 解析即可提取出所有檔案。

electron asar解包

目前來說,官方的版本並沒有提供保護原始碼的方法。在github開源的找到個大神提供的解決方案(https://github.com/toyobayashi/electron-asar-encrypt-demo) ,該方案可以把啟動檔案編譯為node二進位制檔案,作為啟動入口,來保護薄弱的js程式碼。在專案啟動時,將加密後的程式碼進行解密,交回electron流程進行執行,從而避免上述步驟直接解包拿到原始碼的可能。

經過分析對比,typora用的恰好是這個demo提供的思路。

找到上述步驟解壓成功的 package.json 檔案,main屬性就是 electron 專案啟動的主入口。把 main.node 拖到ida中, 分析執行流程。

結合 electron-asar-encrypt-demo 跟 IDA虛擬碼, 可以定位到兩個關鍵函式 napi_create_string_utf8 跟 napi_call_function。

萬能js提取方案

已知經過編譯後的node檔案, 在執行前,都會呼叫 napi_create_string_utf8 建立js字串,所以在呼叫該函式的時候,基於electron沒有自帶加密的特性,想要執行js流程,必定會傳遞明文,所以在載入流程上截斷,就可以匯出解密後的資料。

直接上frida大法:

let napi_create_string_utf8 = Module.getExportByName(null, 'napi_create_string_utf8');
var index = 0;
if (napi_create_string_utf8) {
console.log('繫結成功');
Interceptor.attach(napi_create_string_utf8, {
onEnter: function (args) {
console.log('napi_create_string_utf8', '呼叫', args[0], args[1].readCString().substring(0, 100), args[2], args[3]);

if (args[2].toInt32() > 100) { // 過濾出大檔案
index += 1;
var f = new File('export_' + String(index) + '.js', 'wb');
f.write(args[1].readByteArray(args[2].toInt32()));
f.flush();
f.close();

}
}
});
} else {
console.log('繫結失敗');
}

解包專案中的所有 asar檔案,就能拿到所有的原始碼,並且把解壓的資料夾,改成對應的 asar 檔名即可正常執行專案,無需重打包即可除錯。

無限試用思路

刪除登錄檔鍵,讓程式認為是第一次安裝。

不想進入登錄檔這個繁瑣的話,可以儲存下面的程式碼, 把名字改成 xxx.reg, 雙擊執行即可無限暢玩。

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Typora]
"IDate"="1/24/9999"
"SLicense"=""

去除授權功能實現單機版本思路

將所有的網路驗證給他刪掉/註釋掉, 也可以直接把 “是否授權” 的變數,改成true即可。

註冊機思路

由於該示例使用了rsa解密,所以要基於官方版本編寫註冊機就不太行了。一定要出注冊機的話,需要先替換截圖部分的rsa公鑰即可。

這個地方使用了node自帶的公鑰解密,一些語言好像不能直接生成(可能我的開啟方式不對),我就直接給出node版本的建立例項。

const crypto = require('crypto');
const fs = require('fs');
const path = require('path');

const keyPair = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: ''
}
});

fs.writeFileSync("public_key.pem", keyPair.publicKey);
fs.writeFileSync("private_key.pem", keyPair.privateKey);

生成後的公鑰, 覆蓋即可,然後編寫自己的註冊機。

自建授權閘道器實現註冊機思路

自建閘道器的話,可以把應用自帶的域名,替換成自己的,然後按介面需要的返回值,給他返回響應的資料格式即可。這個例項僅需要修改兩處即可。

介面就不提供了,放張效果圖:

重打包發版思路

把解壓的資料夾打包回 asar格式的檔案即可, 這個網上一大把資料。

對於electron加密方式的思考

相對於原生開發來說,js安全做客戶端畢竟薄弱,UI互動是沒問題的,關鍵程式碼可以放到dll、so層去做,但是也沒辦法避免從js層面去剝離dll層函式的呼叫。所以目前來說並沒有很好的解決方案,本文只是起到拋磚引玉的作用。期待electron有更好、更安全的解決方案。

看雪ID:鈔能力大叔

https://bbs.pediy.com/user-home-860779.htm

*本文由看雪論壇 鈔能力大叔 原創,轉載請註明來自看雪社群

#

往期推薦

1. 遊戲安全之借坡下驢

2. EXP編寫學習之繞過SafeSEH

3. CVE-2016-0165提權漏洞學習筆記

4. CVE-2015-0057提權漏洞學習筆記

5. Android Hook技術學習——常見的Hook技術方案總結

6. 2022DASCTF MAY 出題人挑戰賽

球分享

球點贊

球在看

點選“閱讀原文”,瞭解更多!