node.js で PC 上の WeChat アプレット パッケージを復号化するための処理アイデア

node.js で PC 上の WeChat アプレット パッケージを復号化するための処理アイデア

元々はNuggetsに投稿されていたので、こちらに移動しました。

WeChat ミニプログラムは、PC に暗号化された形式で保存されます。直接開いても、役立つ情報は表示されません。パッケージの具体的な内容を確認するには、暗号化を解除する必要があります。この記事では、Node.js を使用して復号化アルゴリズムを実装します。主に、crypto、commander、chalk の 3 つのパッケージを使用します。

アプレットのソースコードはどこにありますか?

PCで開かれたミニプログラムは、ローカルWeChatファイルのデフォルトの保存場所にキャッシュされます。WeChat PC => その他 => 設定から表示できます。

デフォルトの保存場所にある /WeChat Files/WeChat Files/Applet フォルダーに入ると、プレフィックスが wx の一連のファイルが表示されます (ファイル名は実際にはミニプログラムの appid です)。これらは、開いたミニプログラムです。

ミニプログラムの 1 つのフォルダーに入ると、数字の文字列で名前が付けられたフォルダーが表示されます。このフォルダをクリックすると、アプレットに対応するコードである __APP__.wxapkg ファイルが表示されます。

しかし、ファイルを開くと、次の内容が見つかりました。

WTF はこの🔨からわかります。当然ながら、このファイルは暗号化されており、見たい内容を表示するには復号化する必要があります。

PC ミニプログラムはどのように暗号化されますか?

これは、ある大物によって Go 言語で書かれた PC 側の wxapkg 復号化コードへの参照です。整理すると、暗号化プロセスは次のようになります。

まず、平文コードは 1024 バイト目で 2 つに分割されます。前半は CBC モードの AES を使用して暗号化され、後半は直接 XOR されます。最後に、暗号化された 2 つのセクションを連結し、先頭に固定文字列「V1MMWX」を書き込みます。

したがって、__APP__.wxapkg ファイルを開くと、暗号化されたコードが表示されます。これを復元するには、後ろから前へ段階的に押し戻す必要があります。

復号化のアイデア

前処理

デコードプログラムを書くにはnode.jsを使います。上記の暗号化プロセスに従って、まず暗号化されたファイルを読み取り、最初の 6 バイトの固定文字列を削除します。 AES 暗号化と XOR の前後のビット数は同じなので、暗号化された 1024 バイトのヘッダーと暗号化されたテールを取得できます。

const fs = require('fs').promises;
...
 
const buf = await fs.readFile(pkgsrc); // 元のバッファを読み込む
bufHead = buf.slice(6, 1024 + 6);
bufTail = buf.slice(1024 + 6);

暗号化されたヘッダー

この 1024 バイトの平文を取得するには、AES 暗号化の初期ベクトル iv と 32 ビットのキーを知る必要があります。 16 バイトの初期ベクトル iv が文字列「the iv: 16 bytes」であることがわかっているので、次に pbkdf2 アルゴリズムによって導出された 32 ビット キーを計算する必要があります。

pbkdf2 (パスワードベースのキー導出関数) は、キーを生成するために使用される関数です。疑似ランダム関数を使用し、元のパスワードとソルトを入力として受け取り、継続的な反復を通じてキーを取得します。暗号ライブラリでは、pbkdf2 関数は次のようになります。

const crypto = require('crypto');
...
 
crypto.pbkdf2(パスワード、ソルト、反復、キー長、ダイジェスト、コールバック)

パラメータは、元のパスワード、ソルト値、反復回数、キーの長さ、ハッシュ アルゴリズム、およびコールバック関数です。ソルトは「saltiest」、元のパスワードはWeChatアプレットのID(つまり、wxで始まるフォルダ名)、反復回数は1000、ハッシュアルゴリズムはsha1であることがわかっています。したがって、キーを計算するコードを記述できます。

crypto.pbkdf2(wxid, salt, 1000, 32, 'sha1', (err, dk) => {
    もし(エラー){
        // 間違い}
    // dk は計算されたキーです})

キーと初期ベクトル iv を取得したら、暗号文の復号化を開始できます。 AES 暗号化アルゴリズムは非対称暗号化アルゴリズムです。そのキーは、ユーザーのみが知っている公開キーと秘密キーに分かれています。誰でも公開キーを使用して暗号化できますが、平文を復号化できるのは秘密キーを持っている人だけです。

アプレットが使用する暗号化アルゴリズムは、CBC (Cipher Block Chaining) モードの AES です。つまり、暗号化の際には、まず平文をブロックに分割し、各ブロックを前のブロックの暗号化された暗号文と XOR し、次に公開鍵を使用して暗号化して各ブロックの暗号文を取得します。最初の平文ブロックは、前の平文ブロックには存在しないため、初期ベクトル iv と XOR 演算され、公開鍵で暗号化されます。実装する際には、crypto が提供する復号化関数を呼び出すだけで済みます。

AES アルゴリズムには、キーの長さに応じて AES128、AES192、AES256 が含まれることがわかっています。振り返ってみると、キーは 32 バイト、つまり 256 ビットなので、明らかに AES256 を使用する必要があります。要約すると、復号化コードは次のように記述できます。

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

このうち、originalHead は必要なプレーンテキストの最初の 1024 バイトです。印刷して確認してみましょう:

うーん...それはちょっと面白いですね。

暗号化された尾部

この部分は簡単です。 XOR 演算は再帰的であるため、アプレット ID の桁数を判定して XOR xorKey を取得し、それを暗号文と XOR して元のテキストを取得するだけです。

const xorKey = wxid.length < 2 ? 0x66 : wxid.charCodeAt(wxid.length - 2);
末尾 = [];
for(let i = 0; i < bufTail.length; ++i){
    tail.push(xorKey ^ bufTail[i]);
}
Buffer から tail を取得します。

ヘッダー部分のプレーンテキストとテール部分のプレーンテキストを連結し、バイナリ形式でファイルに書き込んで最終的なプレーンテキストを取得します。

もっと美しく

上記の説明に基づいて、復号化プロセス全体をブラック ボックスにカプセル化できます。

指揮官

コマンダー ライブラリを使用すると、プログラムがコマンド ラインから直接アプレットの ID と暗号テキスト パッケージを読み取ることができるようになります。 Commander は、独自の CLI コマンドを簡単に定義できる Node.js コマンドライン インターフェイス ソリューションです。たとえば、次のコードの場合:

const プログラム = require('commander');
...
プログラム
    .command('decry <wxid> <src> [dst]')
    .description('PC WeChat アプレット パッケージのデコード')
    .action((wxid, src, dst) => {
        wxmd(wxid, src, dst);
    })
 
プログラム.バージョン('1.0.0')
    .usage("decry <wxid> <src> [dst]")
    .parse(プロセス.argv);

コマンド「decry <wxid> <src> [dst]」を定義しました。山括弧は必須パラメータを表し、角括弧はオプション パラメータを表します。説明にはこのコマンドについての説明テキストが含まれ、アクションはこのコマンドを実行することです。ノードを使用してコンソールでコードを実行すると、次のインターフェースが表示されます。

次に、プロンプトに従って復号化のパラメータを入力します。 commander.js の中国語ドキュメントはここにあります。

チョーク

コンソールにちょっとした色を加えるために、chalk.js を使用して出力を美しくすることができます。チョークの基本的な使い方も比較的簡単です。

const チョーク = require('チョーク');
...
 
console.log(chalk.green('green'))

このようにして、白黒のコンソールに緑のタッチを加え、パンダの夢を実現することができます。

さらに、es6 文字列タグ テンプレートを使用して、チョークをより便利に使用することもできます。詳細については、Chalk の公式ドキュメントを参照してください。

ソースコード

コードはgithubとgiteeに公開されているので参考にしてください〜

githubはこちら、giteeはこちら

これで、node.js での PC 上の WeChat アプレット パッケージの復号化に関するこの記事は終了です。より関連性の高い nodejs WeChat アプレットの復号化コンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後も 123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • 携帯電話番号を取得するためのWeChatアプレットJavaScript復号化サンプルコードの詳細な説明
  • WeChat アプレットのログインデータの復号化と状態維持の例

<<:  純粋な CSS でマークダウンの自動番号付けを実装するサンプル コード

>>:  ウェブページのCSSの優先順位について詳しく説明します

推薦する

データベース接続プール Druid の使用手順

総合的なパフォーマンス、信頼性、安定性、スケーラビリティ、使いやすさなどの要素に基づいて、最適なデー...

英語の単語の出現頻度を数えるtrコマンドの魔法

置換を削除したり文字列を削除したりできる tr コマンドは、誰もがよく知っています。 英語では、英語...

ノードイベントループにおけるイベント実行の順序

目次イベントループブラウザ環境イベントループノード環境イベントループ6つのステージ(1)setTim...

JavaScript の差異を利用して比較ツールを実装する

序文仕事では、毎週従業員が提出した資料を数える必要がありますが、それを一つずつコピーして貼り付けるの...

Linux で特殊文字のファイル名やディレクトリを削除する方法

inode番号でファイルを削除するまずls -iを使用して、削除するファイルのinode番号を見つけ...

MySQL フルテキスト インデックス、ジョイント インデックス、Like クエリ、JSON クエリのうち、どれが高速ですか?

目次クエリの背景1. クエリをいいね2. JSON関数クエリ3. 共同インデックスクエリ4. 全文イ...

サイト全体を灰色にするCSSコードのまとめ

国務院は本日、新型コロナウイルス感染症との闘いで殉教した方々と犠牲者に対し、全国各民族人民の深い哀悼...

MySql マスタースレーブレプリケーションメカニズムの包括的な分析

目次マスタースレーブレプリケーションメカニズム非同期レプリケーション準同期レプリケーションマスタース...

Linux で NFS のワンクリック展開を実装する方法

サーバー情報管理サーバー: m01 172.16.1.61サーバー: nfs01 172.16.1....

MySQLユーザー権限テーブルについての簡単な説明

MySQL はインストール時に自動的に mysql という名前のデータベースを作成します。mysql...

divの適応高さは残りの高さを自動的に埋めます

シナリオ 1: HTML: <div class="outer"> ...

海外でダウンロードできる25個の新鮮で便利なアイコンセット

1. Eコマースアイコン2. アイコンスイーツ2 3. 携帯電話アイコンパック4. 旗アイコンセット...

CentOS の環境変数と設定ファイルの詳細な説明

序文CentOS 環境変数設定ファイル システムは階層型システムであり、他のマルチユーザー アプリケ...

Mysqlはフィールドスプライシングのための3つの関数を実装している

データをオペレーションにエクスポートする場合、フィールドの結合は避けられません。MySQL でこれが...

Mysql 文字列の傍受と指定された文字列内のデータの取得

序文: 正規表現のインターセプションに似た、MySql フィールドの文字列から特定の文字を抽出すると...