JSリバースWebパック復号化

免責事項: この記事は研究と研究のみを目的としており、違法な目的で使用することは禁止されています。そうでない場合は、その結果について責任を負います。侵害がある場合は、通知して削除してください。ありがとうございます!

前書き: 私の技術はあまり優れていないかもしれませんが、私は非常に怠け者です。できるだけ簡単に行う方法なので、より良い復号化方法がある場合は、コメントエリアにコメントしてください~

対象 Web サイト: この Web サイトは非常に貧弱で、検証フィールドが見つかりません。XHR ブレークポイントも突破できません。非常に不思議ですが、あえてこの記事を書きました。つまり、合格したことを意味します。

ウェブサイトは次のとおりです。

aHR0chM6Ly90b29scy5taWt1LmFjL25vdmVsYWkv

JS リバースエンジニアリングに関しては、次のとおりです。

        1.パラメータを見つける

        2. 位置決めパラメータの生成場所

        3. パラメータの暗号化ロジックを分析する

        4.控除コード呼び出し

Webpack について理解できない場合は、次の記事を参照してください。

https://app.yinxiang.com/fx/970ae39c-9964-4aae-aa96-7e81fee4ef8f

         簡単に言えば、すべてのリソースは webpack によってパッケージ化された後、モジュールになり、「ローダー (ディストリビューター)」を通じて呼び出されます。

逆のプロセスを開始しましょう。

ターゲット Web サイトを開き、ターゲット Web サイトの [生成開始] ボタンをさらに何回かクリックし、生成が成功するまで待ちます。いくつかのリクエストを比較した結果、リクエスト パラメーターは同じであることがわかりますが、リクエスト内の authsign はheader は毎回異なるので、パラメータがバリデーションパラメータであると判断します(実際にはこれです)。

最初のステップでは、古いルールでまずグローバルに検索します。

割り当てがないように見えますが、それは非常に奇妙ですが、

2 番目のステップは、パラメータの位置を特定することです。つまり、最初にリクエストが開始された場所を確認します (ランチャーで見つけます) (実際には、別の方法があります: Js Hook については後で説明します)。

 ここにジャンプして、ここでブレークポイントを打ちます。

 もう一度「ビルド開始」をクリックします

 ここに t があることがわかりますが、内部のヘッダーはそれが何であるかを知りません (一般的なヘッダーはリクエスト ヘッダーであるため、これは非常に疑わしいため、最初にこの t を覚えておいてください)。つまり、F10 を押して関数をスキップして続行します。実行します。

e は配列です。この配列を走査しているようです。気にしないでください。とにかく理解できません。F10 キーを押してスキップします。

ここに到着すると、ここでリクエスト パラメーターを見つけることができますが、必要な「authsign」がありません。必要なパラメーター (Authsign) が表示されるまで F10 を押してスキップします。

ここでも t が表示されており、内部のヘッダーは依然としてその値であることがわかります。F10 を押して機能をスキップします

さて、スキップした後、このヘッダーに追加の Authsign があることがわかります。したがって、この Authsign はここで生成されます。

ここでブレークポイントを設定し、他のブレークポイントをキャンセルして、もう一度「生成開始」をクリックします。

ここで停止した後、F9 を押してステップごとに実行します (F10 は関数をまたいで実行します)。

ここでステップバイステップで実行し、印刷すると、ここが暗号化パラメータが生成される場所であり、配置されていることがわかります。

別のメソッドであるJS フックについて話しましょう。

 ブラウザに拡張機能をインストールする必要があります:oil Monkey (Violentmonkey)

        プラグインを開いて新しいスクリプトを作成します。このスクリプトの機能は、指定されたリクエスト ヘッダーが設定されたときにデバッガ状態に移行することです。

        その他のスクリプト: ( https://www.jb51.net/article/241736.htm )

// ==UserScript==
// @name        tools.miku
// @namespace   Violentmonkey Scripts
// @match       https://*/*
// @grant       none
// @version     1.0
// @author      -
// @description 2022/11/4 08:39:59
// ==/UserScript==
var code = function(){
var org = window.XMLHttpRequest.prototype.setRequestHeader;
window.XMLHttpRequest.prototype.setRequestHeader = function(key,value){
    if(key=='Authsign'){
        debugger;
    }
    return org.apply(this,arguments);
}
}
var script = document.createElement('script');
script.textContent = '(' + code + ')()';
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);

次に、ページを更新してスクリプトを開始します。もう一度「Start Generation」をクリックすると、ここで停止することがわかります。これは、この時点で「Authsign が Header に設定されている」ことを示しています。

 次に、スタックのトレースを開始しましたが、スタック トレースの目的は、暗号化されたパラメータが生成された場所を見つけることでもあります。

呼び出しスタックは、現在のコードの呼び出し元、および呼び出し元の呼び出し元です。端的に言えば、プログラムはここまでの操作をすべて実行し、ここで「Authsign」の値を設定し、スタックを上から下にたどっていき、上が現在位置、下が前回の呼び出し位置です。やり方がわからない場合は、自分でスタックチェイスに関するチュートリアルを見つけるしかありません。

最後に、この h.request を追跡すると、ランチャーで入力したものと同じになります。F10 キーを押して、「Authsign」が追加されている部分を段階的に確認し、それに従って、暗号化されたパラメーターの位置を見つけます。

次に、先ほど述べたように、暗号化パラメータの後に配置します。

観察すると、これが webpack パッケージであることがわかります。webpackのパッケージは非常に特徴的で、販売代理店も存在します。

f は、y は上記で定義されており、 y = nn(f)、良好です。

次に、コードのバックルを開始し、最初にここ y=nn(f) にブレークポイントを設定し、ページを更新します(モジュールは最初にすべて読み込まれているため、「生成開始」をクリックする代わりにページを更新します)。

壊したらnに飛び込みます。n の上にマウスを移動してこのメ​​ソッドにジャンプすることも、コンソールに直接 n を表示してダブルクリックしてこのメ​​ソッドにジャンプすることもできます。

 

 これがいわゆるwebpackのローダー(ディストリビューター)であることがわかります。

js ファイル全体を直接コピーします。一部のチュートリアルでは、ローダーをコピーするだけで十分だと言うかもしれません。実際にはそうではありません。y=nn(f) は nn で、n は o 関数であることがわかります。これは on (f) と同等です。この js ファイルを検索すると、on が以下で定義されていることがわかります。そのため、ローダーをコピーするだけでなく、すべてをコピーする必要があります。

 新しい js ファイルを作成し、ここに貼り付けます。

グローバル変数 lorder を定義します。最後の d() を lorder=o に変更します。最後の d() はエントリ関数ですが、必要ないので、lorder を使用して o を外側で実行できます。次に、配列形式をオブジェクト形式に変更し、それをテストする 2 つのメソッドを構築しました。

 何か問題が発生しました。ウィンドウが定義されていません。window が定義されていません。最初に var window={} を定義しましょう。 

 次に、再度実行すると正常に出力され、ローダーに問題がないことがわかります。

OK、必要なメソッドf=n(267)、y=nn(f) をコピーしましょう。ページを更新してジャンプしてから、メソッドをコピーします。n(267) はメソッドではないことがわかります。

 このとき、ローダーである n にジャンプし、ブレークポイントにヒットし、ページを更新して、添え字 267 が付いた関数をコンソールに出力します。e は関数配列、つまり e[267] です。

飛び込んでみると、内部の js モジュール全体が他のモジュールとは異なっており (これは配列の形式になっています)、その中には多数の関数が呼び出されていることがわかりましたが、現時点ではそれらは気にしません。 1つずつコピーするのは面倒です もちろん気に入ったものがあれば1つだけでも大丈夫ですが、オブジェクトの形式を対応する添え字に変更することを忘れないでください、それだけです

ここでは説明しませんが、遅延メソッドを使用してワンクリックで吐き出します。まず、e[267] が配置されている js の先頭を見つけます。これで始まるすべてのモジュールは、webpack パッケージ化されたモジュール ファイルです。

また、js モジュールをコピーしてローダーに置きます (ローダー js はブラウザから再度コピーする必要があることに注意してください。変更されていない、つまり Lorder なしでなければなりません)。

 次に、漁師のアストリバースを使用する必要があります。これは偉い人のプロジェクトのアドレスです。

ドキュメント · マスター · フィッシュ / webpack_ast · GitCode

依存関係を補うための依存関係が不足しているため、この ast フォルダーに a.js ファイルを作成し、作成した js (ローダーと配列モジュール) を a.js にコピーしました。

次に、cmd を開いて ast フォルダーに入り、コマンドを実行します。

ノード webpack_mixer.js -l a.js -o webpack_out.js

 エラーが報告された場合、不足している依存関係が補完され、操作が成功すると、オブジェクト形式のモジュールである追加の webpack_out.js ファイルが作成されます。

次に、その js をコピーして独自の js に戻します。また、ボスは、呼び出し用のグローバル変数の生成も思慮深く手伝ってくれました (export_function = o;)。ここでもボスに感謝の気持ちを表します。

 コード内の n は o 関数に相当し、o はグローバル変数 export_function に割り当てられます。つまり、n(267)=o(267)=export_function(267) になります。メソッド 267 があります。ダウン、

n(267) と y も定義します。

次に、上で定義した m 関数をコピーします。つまり、不足しているものを補うものです。

実行後、再び例外が発生します。この例外が発生すると、関数が欠落していることがわかりますが、どの関数が欠落しているかはわからないため、コード console.log(c) をローダーに追加します。ここで、 c は添え字であり、 It はオブジェクトの名前であると言えます。これにより、どの関数でエラーが報告され、どの関数が欠落しているかがわかります。 

 うーん、関数 51

古いルールでは、デコレータを入力してブレークポイントを設定します 

次に、メソッド 51 にジャンプし、js モジュール全体をローダーにコピーします。ローダー js をブラウザに再度コピーする必要があることに注意してください。上記と同様に、ast フォルダーに入ってコマンドを実行するのも cmd です:

 ノード webpack_mixer.js -l a.js -o webpack_out.js

 次に、出力 js ファイル内のモジュールを独自の js ローダー モジュールにコピーするだけです。

 メソッドをカンマで区切ることを忘れないでください。

 しまった後、保存して実行し、再度エラーを報告します。e は定義されていません。 

 e がどこから来たのか調べてみましょう。調べてみると、メソッドのパラメータである e がここにあることがわかります。

 

 次に、このメソッドのパラメータがどのように由来しているかを調べます。振り返ってみると、それが .call(this, n(262), n(51)) であることがわかります。つまり、e は n(262)、 oはn(51)です。

OK、それでは e=n(262) も定義し、それを保存して再度実行し、再度エラーを報告します。r は未定義で同じです。r が定義されている場所を見つけます。

 冒頭で見つけた、

また、r を定義しましょう。r=n(56)、保存して実行してエラーを報告します。o は未定義です。o は先ほどの n(51) です。定義してから保存して実行し、エラーを報告します。

e = decodeURIComponent(l); では、ここでエラー「URIError: URI malformed」が報告されます。これは非常に奇妙です。何かが欠落しているかどうかを確認してください。さて、この m の上に実際にいくつかのパラメータ定義があることがわかりますが、私たちはそれを持っていないので、追加します。

 まあ、追加した後も保存して実行してエラーを報告しますが、先ほどの間違いではなく、今回は d(...)(...)[m(...)] は関数ではありません、d がどの定義であるか、冗長な操作があるかどうかを確認してください。

次に、d の定義の後に、daextend(_.a)、および _ = nn(m)、m = n(568)、という演算があることがわかります。

これらの定義も追加しましたが、保存して実行してもエラーが報告され、ドキュメントが定義されていません。

 この例外は window とは異なり、上で定義した場合は機能しません。つまり、上で定義してみましょう、var document={}、f が出力されることがわかりますが、まだ問題があり、属性「words」は定義されておらず、words は f の属性です。

 つまり、これを印刷してブラウザで比較してください。 m("8", "fUV&") はドメイン、つまりドメイン名です。つまり、 document[domain] の出力は未定義です。

 ブラウザを見てみると、

 したがって、プログラムはブラウザ ドキュメントのドメイン名を取得できないため、無効な値を直接使用することができます。変更後、保存して実行し、再度エラーを報告します。暗号化モジュールに問題があります。

 暗号化が何であるかを確認するために印刷してみましょう。AES 暗号化方式であることがわかります。

パラメータはすでに存在します。nodejs の暗号化ライブラリを参照します。

var CryptoJS = require("crypto-js");

Crypto-jsは単体でインストールされますが、以下の暗号化も変更して保存して実行します 

 苦労の甲斐あって、ついに暗号化が成功しました!apipostに入れて試してみるとデータがないのはおかしいのですが、暗号化されたデータに問題があるのでしょうか?

 たゆまぬ努力の末、ついに判明したのが、

 この f の document[m("3", "jx9[")] には問題があります。プログラムは Web サイトのドキュメントにアクセスできないと前に言いました。そのため、必要な値を確認するためにドキュメントを出力してみましょう。

これはドメイン名でもあることがわかります。そのため、 document[m("3", "jx9[")] も 'tools.miku.ac' に置き換えて、保存して実行する必要があります。

暗号化されたデータを再度 Apipost に置きます。今回はリクエストが長くなります (大喜び)。

Web サイトが画像を Base64 形式で返し、最終的に成功したことがわかります。

コアの復号化コードを貼り付けますが、途中のモジュールは貼り付けません(多すぎるため)。

var CryptoJS = require("crypto-js");
var document = {}
var export_function;
!function (e) {
    //这里是加载器代码
}({
    //这里是模块代码
});
module.exports = export_function;
e = export_function(262)
o = export_function(51)
r = export_function(56)
f = export_function(267)
y = export_function.n(f)
h = (export_function(37), export_function(91), export_function(92), export_function(25), export_function(123), export_function(49))
d = export_function.n(h)
m = export_function(568)
_ = export_function.n(m)
d.a.extend(_.a)
var n, l, h = ["jsjiami.com.v6", "jsjSiamtirN.coEmh.Fulv6YWfbWzOB==", "bALCr8KoHEA=", "w7BQDcKBPMO7", "wqw8W8OFT1XDnw==", "TcKFbsOIw7oTwqnDrQ==", "wqM3w7c=", "w6TCqsKDw6PCsMOaRA==", "wq9Qw7rDpcKRZg==", "w7Msw5zDtsORCsOJIw==", "OlPDoQ==", "IsOIWMOowpvCtHdD"];
n = h,
    l = 448,
    function (e, t, o, r) {
        if ((t >>= 8) < e) {
            for (; --e;)
                r = n.shift(),
                    t === e ? (t = r,
                        o = n.shift()) : o.replace(/[StrNEhFulYWfbWzOB=]/g, "") === t && n.push(r);
            n.push(n.shift())
        }
    }(++l, 114688);
var m = function t(n, c) {
    n = ~~"0x".concat(n);
    var l = h[n];
    if (void 0 === t.RVAulw) {
        !function () {
            var t = "undefined" != typeof window ? window : "object" === (void 0 === e ? "undefined" : Object(r.a)(e)) && "object" === (void 0 === o ? "undefined" : Object(r.a)(o)) ? o : this;
            t.atob || (t.atob = function (e) {
                for (var t, n, o = String(e).replace(/=+$/, ""), r = 0, c = 0, l = ""; n = o.charAt(c++); ~n && (t = r % 4 ? 64 * t + n : n,
                    r++ % 4) ? l += String.fromCharCode(255 & t >> (-2 * r & 6)) : 0)
                    n = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(n);
                return l
            }
            )
        }();
        t.hRdDHj = function (e, t) {
            for (var n, o = [], r = 0, c = "", l = "", h = 0, d = (e = atob(e)).length; h < d; h++)
                l += "%" + ("00" + e.charCodeAt(h).toString(16)).slice(-2);
            e = decodeURIComponent(l);
            for (var m = 0; m < 256; m++)
                o[m] = m;
            for (m = 0; m < 256; m++)
                r = (r + o[m] + t.charCodeAt(m % t.length)) % 256,
                    n = o[m],
                    o[m] = o[r],
                    o[r] = n;
            m = 0,
                r = 0;
            for (var _ = 0; _ < e.length; _++)
                r = (r + o[m = (m + 1) % 256]) % 256,
                    n = o[m],
                    o[m] = o[r],
                    o[r] = n,
                    c += String.fromCharCode(e.charCodeAt(_) ^ o[(o[m] + o[r]) % 256]);
            return c
        }
            ,
            t.gjhasZ = {},
            t.RVAulw = !0
    }
    var d = t.gjhasZ[n];
    return void 0 === d ? (void 0 === t.PPSXqK && (t.PPSXqK = !0),
        l = t.hRdDHj(l, c),
        t.gjhasZ[n] = l) : l = d,
        l
}
_ = d()()[m("0", "ZLEd")]()[m("1", "1)V^")]()
f = y.a[m("2", "ise7")]("" + _ + 'tools.miku.ac');
authsign=f + "." + CryptoJS.AES.encrypt(_, 'tools.miku.ac')[m("9", "6lDQ")]()
console.log(authsign)

この記事は自分自身の記録のためのものであり、もちろん皆さんの学びや交流も大歓迎です。

おすすめ

転載: blog.csdn.net/qq_51502150/article/details/127879654