【Androidリバース】フリーダ入門と共通メモ

予備知識

フックとは何ですか?

フックは「フック」と訳され、メソッド/関数をフックすることを指し、その後、やりたいことを実行できるようになります。実際、いくつかのツールを使用して、メソッド/関数の呼び出しを Java およびネイティブ レベルで「フック」することも、それをモニタリングとして直接理解することもでき、メソッドの呼び出し、メソッドのパラメータの受け渡し、および変更されたメソッドの戻りをモニタリングできます。 .値など

フックの機能

これらのツールを理解することは、問題の特定、デバッグ、さらには一部のアプリのクラックや変更をより適切に行うのに役立ちます。

一般的なリバースツール

ツール/方法 効果 Java層 ネイティブ層 SDKの統合 ルートが必要ですか 述べる 他の
JADX 逆コンパイルしてソースコードを表示する サポート サポートしません なし なし 強化された APK を最初に解凍する必要があります
apktool APKを逆コンパイル/再コンパイルする なし なし なし なし メールコードを変更する
エピック/サンドフック アプリにはコードフック用の SDK が統合されています サポート サポート 必要 不要 Xped フレームワーク、さまざまなシステム API に一貫性がないため、調整する必要がある
xposed プラグイン xused フレームワークと統合された Android 環境をフックする サポート サポートしません 不要 必要 root が必要、その他は上記と同じ
フリーダ root化されたAndroid環境では、java/nativeに対してバイナリフックを直接実行します。 サポート サポート 不要 必要 root環境、Python環境が必要

フリーダを使い始める

概要と参考ノート

Frida は、Java/ネイティブ レイヤ フックをサポートし、ルート環境を必要とするバイナリ フック フレームワークです。バイナリ メモリ フックであるため、SDK を統合したり、プロセスを再起動したりせずに、現在のプロセスを直接フックできます。

事前環境構成

  • Python3とpip環境をインストールする
  • pip を使用して frida ライブラリとツールをインストールする
  // 安装特定版本 pip install frida==版本号
 pip install frida
 pip install frida-tools
 // 网络不好使用镜像库
 pip install firda -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
 // 查看当前frida版本
 frida --version
  • エミュレータを使用する場合、ポートフォワーディング(デフォルトポート)
adb forward tcp:27042 tcp:27042
adb forward tcp:27043 tcp:27043
   # 这里放于 /data/local/tmp
  adb push E:\frida-server /data/local/tmp/frida-server
  # 进入adb shell
  adb shell
  # 以管理员权限访问
  su
  # 进入frida-server目录
  cd /data/local/tmp
  # 提供权限
  chmod 777 frida-server
  # 运行frida-server
  ./frida-server
  • frida-server を実行した後、この時点ではウィンドウを開いたままにし、新しいウィンドウを開いて成功したかどうかを確認します。
# 命令成功输出进程列表
frida-ps -U

# 根据包名连接目标进程
frida -U -f com.xxx.xxx 

ここに画像の説明を挿入

フックを実行する

  • Python スクリプトはフックを実行します。サンプルコードは次のとおりです。
import frida, sys

def on_message(message, data):
    if message['type'] == 'send':
        print("[*] {0}".format(message['payload']))
    else:
        print(message)

jscode = """
Java.perform(() => {
  // Function to hook is defined here
  const MainActivity = Java.use('com.example.seccon2015.rock_paper_scissors.MainActivity');

  // Whenever button is clicked
  const onClick = MainActivity.onClick;
  onClick.implementation = function (v) {
    // Show a message to know that the function got called
    send('onClick');

    // Call the original onClick handler
    onClick.call(this, v);

    // Set our values after running the original onClick handler
    this.m.value = 0;
    this.n.value = 1;
    this.cnt.value = 999;

    // Log to the console that it's done, and we should have the flag!
    console.log('Done:' + JSON.stringify(this.cnt));
  };
});
"""

#  pid or package name
process = frida.get_usb_device().attach(13347) 
script = process.create_script(jscode)
script.on('message', on_message)
print('[*] Running CTF')
script.load()
sys.stdin.read())
script = process.create_script(jscode)
script.on('message', on_message)
print('[*] Running CTF')
script.load()
sys.stdin.read()
  • jsスクリプトを直接挿入する
frida -U [pid|packagename] -l test.js

一般的に使用されるフック スクリプト/API

  • テストコードクラス

public class TestStaticClass {
    
    

    public static int count = 0;
    private static String TAG = "TestStaticClass";

    public static String getCountString(){
    
    
        Log.i(TAG, "call testMethod");
        return "count:" + count;
    }

    public static void addCount(){
    
    
        count++;
    }

    public static String getCountString(int input){
    
    
        return "getCountString:" + input;
    }

    public static String getCountString(int[] input){
    
    
        return "getCountString:" + Arrays.toString(input);
    }

    public void testStack(){
    
    
        Log.i(TAG, "call testStack");
    }

}
  • Javaクラスを取得して新しいオブジェクトを構築する
方法 意味 他の
$new 新しいオブジェクト
$init コンストラクタ
const JavaString = Java.use('java.lang.String');
var exampleString1 = JavaString.$new('Hello World, this is an example string in Java.');
  • クラスおよび静的関数のメソッド呼び出しを取得する

    Java.perform(() => {
          
          
     const TestStaticClass = Java.use("com.hjl.nativetest.TestStaticClass");
     TestStaticClass.count.value = 1; //访问静态变量
     TestStaticClass.addCount();   //hook静态函数直接调用
    });
    
  • フックメソッドはメソッド値を出力し、戻り値を変更します。

    Java.perform(() => {
          
          
     // 获取类
     const TestStaticClass = Java.use("com.hjl.nativetest.TestStaticClass");
     // 获取方法
     const getCountString = TestStaticClass.getCountString;  
     // hook方法
     getCountString.implementation = function () {
          
          
    
      // 当方法调用时 
      send('call getCountString');
    
      // 调用原方法获取结果
      var result = getCountString.call(this);
    
      console.log("getCountString:" + result);
      // 返回自定义的结果 
      return "hook return String";
    };
    
    // 获取重载方法
    // 基础类型直接填,数组以类似JNI的签名形式如[I ,类型填完整类
    const getCountString2 = TestStaticClass.getCountString.overload('int')
    getCountString2.implementation = function (data) {
          
          
    
      // 打印原始输入参数
      send('call getCountString:' + data);
    
      // 调用原方法获取结果
      var result = getCountString2.call(this,data);
      console.log("getCountString:" + result);
      // 返回自定义的结果
      return "hook return String";
    };
    });
    
  • コールスタックを取得する

    Java.perform(() => {
          
          
    const TestStaticClass = Java.use("com.hjl.nativetest.TestStaticClass");
    const Exception = Java.use('java.lang.Exception');
    const Log = Java.use('android.util.Log');
    
    const testStack = TestStaticClass.testStack
    testStack.implementation = function () {
          
          
       console.log(stackTraceHere());
    };
    
    function stackTraceHere() {
          
          
      return Log.getStackTraceString(Exception.$new());
    }
    });
    

おすすめ

転載: blog.csdn.net/weixin_41802023/article/details/128726055