溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

node.js中PC端微信小程序包解密的處理方法是什么

發(fā)布時(shí)間:2021-12-16 09:11:39 來(lái)源:億速云 閱讀:327 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹“node.js中PC端微信小程序包解密的處理方法是什么”,在日常操作中,相信很多人在node.js中PC端微信小程序包解密的處理方法是什么問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”node.js中PC端微信小程序包解密的處理方法是什么”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

微信小程序在PC端是加密存儲(chǔ)的,如果直接打開(kāi)是看不到什么有用的信息的,需要經(jīng)過(guò)解密才可以看到包內(nèi)具體的內(nèi)容。本文使用nodejs實(shí)現(xiàn)解密算法,主要涉及到crypto, commander, chalk三個(gè)包的使用。

小程序的源碼在哪里

PC端打開(kāi)過(guò)的小程序會(huì)被緩存到本地微信文件的默認(rèn)保存位置,可以通過(guò)微信PC端=>更多=>設(shè)置查看:

node.js中PC端微信小程序包解密的處理方法是什么

進(jìn)入默認(rèn)保存位置下的/WeChat Files/WeChat Files/Applet文件夾,可以看到該目錄下有一系列前綴為wx的文件(文件名其實(shí)是小程序的appid),這些就是我們打開(kāi)過(guò)的小程序啦:

node.js中PC端微信小程序包解密的處理方法是什么

進(jìn)入其中某個(gè)小程序的文件夾,我們可以看到一個(gè)名字為一串?dāng)?shù)字的文件夾。點(diǎn)進(jìn)這個(gè)文件夾, 就可以看到一個(gè)__APP__.wxapkg文件,也就是小程序?qū)?yīng)的代碼啦:

node.js中PC端微信小程序包解密的處理方法是什么

然而,當(dāng)我們打開(kāi)這個(gè)文件之后卻發(fā)現(xiàn)是這樣的:

node.js中PC端微信小程序包解密的處理方法是什么

WTF 這能看出來(lái)個(gè)????。很明顯,這個(gè)文件是經(jīng)過(guò)加密的,需要解密才能看到我們想看到的東西。

PC端小程序是怎么被加密的

這里參考了一位大佬用Go語(yǔ)言寫(xiě)的PC端wxapkg解密代碼。整理一下的話,加密流程是這樣的:

node.js中PC端微信小程序包解密的處理方法是什么

首先將明文代碼在第1024字節(jié)處一分為二,前半部分使用CBC模式的AES加密,后半部分則直接進(jìn)行異或。最后,將加密后的兩節(jié)拼接起來(lái),并在最前邊寫(xiě)入固定的字符串:"V1MMWX"。

所以,我們打開(kāi)__APP__.wxapkg文件看到的就是加密后的代碼,如果想還原回去的話,需要從后往前逐步推回去。

解密思路

預(yù)處理

我們使用node.js去寫(xiě)一個(gè)解碼的程序。根據(jù)上邊加密的流程,我們首先讀取加密文件,把前6個(gè)字節(jié)的固定字符串去除。由于AES加密和異或前后數(shù)據(jù)的位數(shù)是相同的,我們可以據(jù)此獲取到加密后的頭部1024字節(jié)和加密后的尾部部分:

const fs = require('fs').promises;
...
 
const buf = await fs.readFile(pkgsrc); // 讀取原始Buffer
const bufHead = buf.slice(6, 1024 + 6);
const bufTail = buf.slice(1024 + 6);

加密后的頭部部分

為了得到這1024個(gè)字節(jié)的明文,我們需要知道AES加密的初始向量iv,以及一個(gè)32位的密鑰。已知16字節(jié)的初始向量iv是字符串:“the iv: 16 bytes”,我們接下來(lái)需要計(jì)算出這個(gè)由pbkdf2算法導(dǎo)出的32位的密鑰。

pbkdf2(Password-Based Key Derivation Function)是一個(gè)用來(lái)生成密鑰的函數(shù),它使用一個(gè)偽隨機(jī)函數(shù),將原文密碼和salt作為輸入,通過(guò)不斷的迭代得到密鑰。在crypto庫(kù)中,pbkdf2函數(shù)是這樣的:

const crypto = require('crypto');
...
 
crypto.pbkdf2(password, salt, iterations, keylen, digest, callback)

其中參數(shù)分別是:原文密碼、鹽值、迭代次數(shù)、密鑰長(zhǎng)度、散列算法、回調(diào)函數(shù)。已知salt是"saltiest",原文密碼為微信小程序的id(也就是wx開(kāi)頭的那個(gè)文件夾名),迭代次數(shù)為1000,散列算法為sha1。因此,我們可以寫(xiě)出計(jì)算密鑰的代碼:

crypto.pbkdf2(wxid, salt, 1000, 32, 'sha1', (err, dk) => {
    if (err) {
        // 錯(cuò)誤
    }
    // dk即為計(jì)算得到的密鑰
})

密鑰和初始向量iv都有了之后,我們可以開(kāi)始對(duì)密文進(jìn)行解密了。AES加密算法是一種非對(duì)稱(chēng)加密算法,它的密鑰分成公開(kāi)的公鑰和只有自己知道的私鑰,任何人都可以使用公鑰進(jìn)行加密,但是只有持有私鑰的人解密得到明文。

小程序使用的加密算法是CBC(Cipher Block Chaining, 密碼分組鏈接)模式的AES,也就是它在加密的時(shí)候,首先把明文進(jìn)行分塊,然后將每一塊與前一塊加密后的密文進(jìn)行異或,再使用公鑰進(jìn)行加密,得到每一塊的密文。對(duì)于第一塊明文,由于它不存在前一塊明文,因此它會(huì)與初始向量iv進(jìn)行異或,再進(jìn)行公鑰加密。在實(shí)現(xiàn)的時(shí)候,我們只需要調(diào)用crypto提供的解密函數(shù)就可以啦。

我們知道,AES算法根據(jù)密鑰長(zhǎng)度的不同有AES128, AES192和AES256。回顧上邊,我們的密鑰是32字節(jié),也就是256位的,因此顯然我們應(yīng)該使用的是AES256。綜上,我們可以寫(xiě)出來(lái)解密的代碼:

const decipher = crypto.createDecipheriv('aes-256-cbc', dk, iv);
const originalHead = Buffer.alloc(1024, decipher.update(bufHead));

其中originalHead就是我們要的前1024字節(jié)的明文啦。我們可以打印出來(lái)看看:

node.js中PC端微信小程序包解密的處理方法是什么

嗯…… 有那么點(diǎn)意思了。

加密后的尾部部分

這一部分就很簡(jiǎn)單啦。由于異或運(yùn)算是具有自反性的,因此只需要簡(jiǎn)單的判斷一下小程序id的位數(shù)獲得異或的xorKey,再把它與密文進(jìn)行異或,就可以得到原文了:

const xorKey = wxid.length < 2 ? 0x66 : wxid.charCodeAt(wxid.length - 2);
const tail = [];
for(let i = 0; i < bufTail.length; ++i){
    tail.push(xorKey ^ bufTail[i]);
}
const originalTail = Buffer.from(tail);

將頭部部分的明文與尾部部分的明文進(jìn)行拼接,再以二進(jìn)制形式寫(xiě)入文件,就可以得到最終的明文啦。

再漂亮點(diǎn)

根據(jù)上邊的描述,我們可以把我們整個(gè)的解密過(guò)程封裝成一個(gè)黑盒子:

node.js中PC端微信小程序包解密的處理方法是什么

commander

我們可以使用commander庫(kù)讓程序直接從命令行讀取小程序的id和密文包。commander是一個(gè)nodejs命令行界面的解決方案,可以很方便的定義自己的cli命令。比如說(shuō)對(duì)于下面這一串代碼:

const program = require('commander');
...
program
    .command('decry <wxid> <src> [dst]')
    .description('解碼PC端微信小程序包')
    .action((wxid, src, dst) => {
        wxmd(wxid, src, dst);
    })
 
program.version('1.0.0')
    .usage("decry <wxid> <src> [dst]")
    .parse(process.argv);

我定義了一個(gè)"decry <wxid> <src> [dst]"的命令,其中尖括號(hào)代表必選參數(shù),方括號(hào)代表可選參數(shù)。description內(nèi)是關(guān)于這個(gè)命令的描述文本,action則是執(zhí)行這段命令。在控制臺(tái)使用node執(zhí)行代碼之后,可以看到如下界面:

node.js中PC端微信小程序包解密的處理方法是什么

于是我們就可以根據(jù)提示,輸入?yún)?shù)進(jìn)行解密啦。commander.js的中文文檔在這里。

chalk

為了讓我們的控制臺(tái)多一抹顏色,我們可以使用chalk.js來(lái)美化輸出。chalk的基本用法也比較簡(jiǎn)單:

const chalk = require('chalk');
...
 
console.log(chalk.green('綠了'))

這樣我們就可以在黑白的控制臺(tái)上填上一抹綠色,替大熊貓實(shí)現(xiàn)夢(mèng)想:

node.js中PC端微信小程序包解密的處理方法是什么

除此之外,我們還可以使用es6的字符串標(biāo)簽?zāi)0甯奖愕氖褂胏halk。具體的參考chalk官方文檔吧。

到此,關(guān)于“node.js中PC端微信小程序包解密的處理方法是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI