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の優先順位について詳しく説明します

推薦する

アカウントとパスワードを記憶する機能を実現するVueの考え方とプロセス

目次実装のアイデアアカウント パスワードを保存する方法は 3 つあります。機能インターフェースアカウ...

MySQL ディープ ページング (数千万のデータを素早くページ分割する方法)

目次序文場合最適化まとめ序文バックエンド開発では、一度に大量のデータがロードされ、メモリやディスク ...

Docker Machineの詳細な説明

Docker と Docker Machine の違いDocker はクライアント サーバー アーキ...

Vue3 における provide と inject の使用法と原則

序文:親コンポーネントと子コンポーネント間でデータを渡す場合、通常は props と emittin...

シェル スクリプトを使用してワンクリックで MySQL 5.7.29 をインストールする方法

この記事は51CTOブログの著者wjw555の作品を参照しています。スクリプトの内容: vim イン...

Windows 10 でカスタムドメイン名をバインドするように Hexo と GitHub を構成する方法

Hexo は Windows 10 でカスタムドメイン名を GitHub にバインドしますまずドメイ...

CSS3 で QR コードスキャン効果を実装する例

オンラインプレビューhttps://jsrun.pro/AafKp/まず効果を見てみましょう:最初の...

CSSアダプティブレイアウトは、サブ要素項目の全体的な中央揃えと内部項目の左揃えを実現します。

日常業務では、次のようなレイアウトに遭遇することがあります。親要素のフレーム (ブラウザのサイズに応...

Vueはカルーセルのフレームレート再生を実装します

この記事の例では、カルーセルのフレームレート再生を実現するためのVueの具体的なコードを参考までに共...

VUEユニアプリ開発環境についての簡単な説明

目次1. HBuilderXビジュアルインターフェースを通じて2. vue-cliコマンドで実行する...

MySQL トランザクションの概念と使用法の詳細な説明

目次情事の概念取引の状態取引の役割取引の特徴トランザクション構文トランザクション対応ストレージエンジ...

html、xhtml、xmlの違い

開発動向: html (ハイパーテキスト マークアップ言語) - xhtml (拡張ハイパーテキスト...

DockerにMySQL 8.0をインストールする方法

環境: MacOS_Cetalina_10.15.1、Mysql8.0.18、Docker_2.0....