A シリーズ e コマース アプリの doCommandNative の分析

1. 目標

Boss Li: Fenfei、あなたは X-sign に関するいくつかの記事を読んで、APK を使い回していますが、いつ分析しましょうか?

フェンフェイ: 段階的に、前回の発見を行ったばかりなので、今日はそれを分析します。

アプリバージョン:v4.15.1

2 つのステップ

ネイティブ層の入り口

まずこのスタックを思い出してください

[NewStringUTF] bytes:x-sign
Rc Full call stack:dalvik.system.VMStack.getThreadStackTrace(Native Method)
 tt: java.lang.Thread.getStackTrace(Thread.java:1538)
 tt: com.txxxao.wireless.security.adapter.JNICLibrary.doCommandNative(Native Method)
 tt: com.axxbxxx.wireless.security.mainplugin.а.doCommand(Unknown Source:0)
 tt: com.axxbxxx.wireless.security.middletierplugin.c.d.a.a(Unknown Source:280)
 tt: com.axxbxxx.wireless.security.middletierplugin.c.d.a$a.invoke(Unknown Source:56)
 tt: java.lang.reflect.Proxy.invoke(Proxy.java:913)
 tt: $Proxy12.getSecurityFactors(Unknown Source)
 tt: mtopsdk.security.d.a(lt:620)
 tt: mtopsdk.mtop.a.a.a.a.a(lt:218)
 tt: mtopsdk.framework.a.b.d.b(lt:45)
 tt: mtopsdk.framework.b.a.a.a(lt:60)

0xcb434e10 libsgmiddletierso-6.5.50.so!0x33e10
0xcb404e28 libsgmiddletierso-6.5.50.so!0x3e28
0xc9dd5536 libsgmainso-6.5.49.so!0x10536
0xc9dd71c8 libsgmainso-6.5.49.so!0x121c8
0xf365607a libart.so!art_quick_generic_jni_trampoline+0x29
0xf364068a libart.so!MterpAddHotnessBatch+0x29
0xf3651b76 libart.so!art_quick_invoke_stub_internal+0x45

スタックは会話できる、と彼は私たちに言いました

1. jni 関数は、com.txxxao.wireless.security.adapter.JNICLibrary.doCommandNative と呼ばれます。

2. doCommandNative の実装は libsgmainso-6.5.49.so にあり、オフセット 0x121c8 付近にある可能性があります。

最初に jni 関数をフックします

jni 関数は入力と戻り値の型を教えてくれるので、これを手放すことはできません。

この jni 関数の宣言は、libsgmain.soの偽の soにあります。

ドキュメント.png

この jni 関数には 2 つのパラメーターがあり、最初のパラメーターは int 型、2 番目のパラメーターはオブジェクト配列です。

まずフリーダに行って、それがターゲットであるかどうかを確認しましょう。

Java.enumerateClassLoaders({
    "onMatch": function(loader) {
        if (loader.toString().indexOf("libsgmain.so") >= 0 ) {
            Java.classFactory.loader = loader; // 将当前class factory中的loader指定为我们需要的					
            console.log("loader = ",loader.toString());

        }
    },
    "onComplete": function() {
        console.log("success");
    }
});

// 此处需要使用 Java.classFactory.use
var  signCls =  Java.classFactory.use('com.txxxao.wireless.security.adapter.JNICLibrary');
signCls.doCommandNative.implementation = function(a,b){
    var retval = this.doCommandNative(a,b);
    console.log(" #### >>> a = " + a);

    if( a == 70102){
        console.log(" #### >>> Obj = " + b);
    }

    console.log(" #### >>> rc= " + retval)  // .entrySet().toArray());

    // var stack = threadinstance.currentThread().getStackTrace();
    // console.log("#### >>> Rc Full call stack:" + Where(stack));

    return retval;
}
// */

まず、この70102の由来を説明しましょう。doCommandNative は明らかに多くの機能を引き受けますが、すべてを表示するには煩雑です。

以前のスタックcom.axxbxxx.wireless.security.middletierplugin.cdaaクラスから、 X サイン署名を作成するときに使用されるコマンド パラメーターが70102であることがわかります(対応するコードは偽の libsgmiddletier.so にあります)。

走る

frc1.png

目を確認したら、それです。

ヒント: このスクリプトを Frida スポーン モードで実行すると、ローダーは何も出力しません。このとき、スペースを入れてスクリプトを任意に変更して保存してください。Frida は自動的にリロードされ、その後初めて出力が行われます。

libsgmainso-6.5.49.so について

これはまだ非常に予測可能です。

まず第一に、 doCommandNative はエクスポート関数に見つかりません。これは、動的に登録されていることを示しています。

ida1.png

第 2 に、so に少しアイデンティティがある関数はすべて動的ジャンプです。idaのF5に有効。

ida2.png

一つずつ解決していきましょう。

動的登録を恐れることはありません。Hook RegisterNatives がそれを処理できます。

[RegisterNatives] java_class: com.txxxao.wireless.security.adapter.JNICLibrary name: doCommandNative sig: (I[Ljava/lang/Object;)Ljava/lang/Object; fnPtr: 0x7637c25ba4 module_name: libsgmainso-6.5.49.so module_base: 0x7637c07000 offset: 0x1eba4

結果として、ターゲットは0x1eba4になります。

さらに恥ずかしいのは、 ida の0x1eba4の位置が関数のように見えないことです。

何をすべきか?

これのさまざまなパフォーマンスから判断すると、実行時に何らかの自己修正ゲームプレイがある可能性はありますか?

そんなことは関係なく、これを実行時からダンプしましょう。

ヒント: ダンプの方法についてはhttp://91fans.com.cn/post/carcommunitytwo/を参照してください。

私のテスト用携帯電話は 64 ビットなので、ダンプは 64 ビットで出てきました。

idasub.png

今回はちょっと面白いですが、BR X11のダイナミックジャンプが煩わしいため、f5はまだ楽しめません

修理する

このBR X11命令の x11 の値を知って、それを静的ジャンプに変更すれば、F5 の不良を修正できるのではないか?

早くやれよ

var mbase = Module.getBaseAddress('libsgmainso-6.5.49.so');
Interceptor.attach(mbase.add(0x1EC18),{
		onEnter:function(args){						
		console.log('Context  : ' + JSON.stringify(this.context));
	}
});

印刷する

Context  : {"pc":"0x7637921c18","sp":"0x7639089340","x0":"0x20","x1":"0x76390893e4","x2":"0x2776","x3":"0x28","x4":"0x1","x5":"0x0","x6":"0x4","x7":"0x0","x8":"0x16","x9":"0x7639089350","x10":"0x7637a6cd60","x11":"0x7637921c2c","x12":"0x76390893e8","x13":"0x76390893d8","x14":"0x1","x15":"0x0","x16":"0x76dadbf000","x17":"0x76da67d440","x18":"0x0","x19":"0x76506125e0","x20":"0x0","x21":"0x2776","x22":"0x76390896bc","x23":"0x7650261ddf","x24":"0x8","x25":"0x196","x26":"0x763908d588","x27":"0x2","x28":"0x76390893e8","fp":"0x76390893b0","lr":"0x76dadbf60c"}

現在のアドレスは 0x7637921c18 - 0x1EC18 = 0x763793000 で、 so のベース アドレスが 0x763793000 であり、 x11 の値が 0x7637921c2c - 0x763793000 = 0x1EC2C で、 0x1EC2Cにジャンプする必要があることを示しています。

次に、この命令行をb 0x1EC2Cに変更します。

idabx.png

もう一度F5を押すと、前よりも美しくなります

テスト.png

このネイティブ層の doCommandNative をフックします

ここでは主にHook Native関数を使用した際にObject[]型のパラメータを出力する方法を紹介します。

var mbase = Module.getBaseAddress('libsgmainso-6.5.49.so');
// 1ed4c
Interceptor.attach(mbase.add(0x1EBA4),{
    onEnter:function(args){
        console.log('doCommandNative = ' + args[2].toString(10));


        var Object_javaArray = Java.use('[Ljava.lang.Object;');
        var ArrayArgs_3 = Java.cast(args[3], Object_javaArray);
        var ArrayClz = Java.use("java.lang.reflect.Array");
        var len = ArrayClz.getLength(ArrayArgs_3);

        if( args[2].toString(10) == 70102) {
            for(let i=0;i!=len;i++){
                var objUse = ArrayClz.get(ArrayArgs_3,i);
                if(objUse != null){
                    console.log("args[3] String value:", objUse.toString());
                }
            }
        }

    }
});

まず Java.cast を使用して型を変換し、次に java.lang.reflect.Array を使用して走査します。

結果はまだきれいです

rc.png

3. まとめ

ネイティブ層にはより多くの保護手段があり、誰もが複雑すぎます。

Java リフレクションの使用に習熟することは、frida を上手にプレイするために必要な条件です。

idaのF5も皆で厳重に守っているので、修理計画も理解されているはずだ。

ffshow.png

世界でプレーしたかったのに、なぜ世界でプレーすることになったのでしょうか?

おすすめ

転載: blog.csdn.net/fenfei331/article/details/122088748