最後に、ゼロからPythonを学ぶ (18). APPリバースエンジニアになりたい場合、どのような技術的なポイントを習得する必要がありますか?

Pythonをゼロから学ぶ最終記事として、内容を簡単におさらいしてみましょう

1. プログラミング構文

2.機械学習

3.フルスタック開発

4. データ分析

5. 爬虫類エンジニアの育成

ゼロベースの学習と上級者に適した Python リソース:
① Tencent 認定 Python 完全プロジェクトの実践的なチュートリアル ノート PDF
② 十数の主要工場の Python インタビュー トピック PDF
③ Python フルセットのビデオ チュートリアル (ゼロベースから上級の JS リバース)
④数百のプロジェクト + ソースコード + メモ
⑤ プログラミング文法 - 機械学習 - フルスタック開発 - データ分析 - 爬虫類 - APP リバースおよびその他のプロジェクトのフルセット + ドキュメント

APP リバースエンジニアリング

1. Java 構文プログラミング

1. Java環境構築

APP リバース エンジニアは、Java 構文プログラミングのための Java 開発環境を構築する必要があります。Java 環境を構築する詳細な手順は次のとおりです。

Java 開発キット (JDK) をダウンロードする:
オペレーティング システム用の JDK のバージョンをダウンロードします。オペレーティング システムとシステム アーキテクチャに適したバージョンを選択し、インストール ファイルをダウンロードします。

JDK をインストールします

ダウンロードした JDK インストール ファイルを実行し、インストール ウィザードの指示に従ってインストールします。インストール プロセス中に、インストール パスをカスタマイズすることも、デフォルトのパスを使用することもできます。

環境変数を構成します (Windows システム) :

  • 「コントロールパネル」→「システムとセキュリティ」→「システム」を開き、左側の「システムの詳細設定」をクリックします。
  • 表示されたダイアログボックスで「環境変数」ボタンをクリックします。
  • 「ユーザー変数」セクションで「新規」ボタンをクリックし、次の 2 つの環境変数を追加します。
    • 変数名: JAVA_HOME、変数値: JDK インストール パス (例: C:\Program Files\Java\jdk-11.0.12)
    • 変数名: PATH、変数値: %JAVA_HOME%\bin
  • 「OK」をクリックして設定を保存します。

環境変数を構成します (macOS および Linux システム) :

  • ターミナルを開いて ~/.bash_profile ファイルを編集します。任意のテキスト エディタを使用できます。
  • ファイルの末尾に次の行を追加します。
export JAVA_HOME=/Library/Java/JavaVirtualMachines/{jdk版本}/Contents/Home
export PATH=$JAVA_HOME/bin:$PATH

{jdk version} を、インストールされている JDK バージョンのフォルダー名に置き換えます (例: jdk-11.0.12)。

  • ファイルを保存し、次のコマンドを実行して構成を有効にします:
    source ~/.bash_profile

インストールの確認:
ターミナルまたはコマンド ライン インターフェイスを開き、次のコマンドを入力して、Java 環境が正常にインストールおよび構成されているかどうかを確認します。

java -version

次の出力のようなバージョン情報が表示されれば、Java 環境は正常に構築されています。

java version "11.0.12" 2021-07-20 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.12+8-LTS-237)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.12+8-LTS-237, mixed mode)

Java 開発環境の構築が完了したので、Java 言語を使用して APP リバース エンジニアリング プログラミング タスクの実行を開始できます。Java 開発ツール (Eclipse、IntelliJ IDEA など) を使用して、Java プログラムを作成して実行できます。

2. Javaの基本構文とデータ型

APP リバース エンジニアリングを行う場合、Java の基本的な構文とデータ型を理解することが非常に重要です。以下は、Java の基本的な構文とデータ型の詳細な説明です。

識別子: Java では、識別子は変数、クラス、メソッドなどに名前を付けるために使用される名前です。識別子は文字、アンダースコア、またはドル記号で始まる必要があり、その後に文字、数字、アンダースコア、またはドル記号の組み合わせを続けることができます。

コメント: コメントは、コードにコメントや説明を追加するために使用されます。Java には、次の 3 種類のアノテーションがあります。

  • 単一行コメント: 二重スラッシュ (//) で始まり、コメントの内容は行の終わりにあります。
  • 複数行のコメント: スラッシュとアスタリスク (/) で始まり、アスタリスクとスラッシュ (/) で終わり、複数行にまたがることができます。
  • ドキュメント コメント: ドキュメントの生成に使用される、スラッシュとそれに続く 2 つのアスタリスク (/**) で始まり、アスタリスクとそれに続くスラッシュ (*/) で終わります。

キーワード: Java には、特定の意味や機能を示すために使用される予約キーワードがいくつかあります。よく使用されるキーワードには、class、public、private、static、void などが含まれます。

データ型: Java には 2 種類のデータ型があります。

  • 基本データ型: 整数型 (byte、short、int、long)、浮動小数点型 (float、double)、文字型 (char)、およびブール型 (boolean) を含みます。
  • 参照データ型: クラス、インターフェイス、配列などを含みます。

変数: Java では、変数はデータを保存するために使用されます。変数を宣言するときは、データ型を指定する必要があります。その後、変数に値を割り当てることができます。変数には、プリミティブ データ型または参照データ型を使用できます。

演算子: Java には、算術演算子 (+、-、​​、/、%)、代入演算子 (=、+=、-= など)、比較演算子 (==、!=、 >、<など)、論理演算子(&&、||、!など)など。

制御フロー ステートメント: Java には、プログラムの実行フローを制御するために使用されるいくつかの制御フロー ステートメントが用意されています。

  • 条件文: if 文、switch 文。
  • ループ ステートメント: for ループ、while ループ、do-while ループ。
  • 分岐ステートメント: Break ステートメント、Continue ステートメント、Return ステートメント。

配列: 配列は、同じ型の複数の要素を保持できるデータ構造です。Java では、配列のサイズは作成時に指定され、変更できません。配列内の要素にはインデックスによってアクセスできます。

これらは、Java の基本的な構文とデータ型の主な内容です。これらの概念を理解しておくと、APP リバース エンジニアリングを実行する際の Java コードの分析や変更など、Java コードを理解して作成するのに役立ちます。

3.java制御処理

Java 制御フローとは、プログラムの実行中のさまざまな条件や状況に応じたさまざまな実行パスの選択を指します。Java の制御フローには主に条件文とループ文が含まれます。

1. 条件文

条件ステートメントは、さまざまな条件に基づいてさまざまな実行パスを選択するために使用されます。Java の条件文には、if 文、if-else 文、if-else if 文、switch 文などがあります。

if ステートメント:

if ステートメントは、条件が true かどうかを判断するために使用され、true の場合はコード ブロックが実行されます。

文法形式:

if (条件) {
    // 执行代码块
}

サンプルコード:

int a = 10;
if (a > 5) {
    System.out.println("a大于5");
}

if-else ステートメント:

if-else ステートメントは、条件が true かどうかを判断するために使用され、true の場合はコードのブロックが実行され、そうでない場合は別のコードのブロックが実行されます。

文法形式:

if (条件) {
    // 执行代码块1
} else {
    // 执行代码块2
}

サンプルコード:

int a = 3;
if (a > 5) {
    System.out.println("a大于5");
} else {
    System.out.println("a小于等于5");
}

if-else if ステートメント:

if-else if ステートメントは複数の条件を判定するために使用され、最初の条件が true の場合は最初のコード ブロックが実行され、そうでない場合は 2 番目の条件が判定されます。

文法形式:

if (条件1) {
    // 执行代码块1
} else if (条件2) {
    // 执行代码块2
} else {
    // 执行代码块3
}

サンプルコード:

int a = 3;
if (a > 5) {
    System.out.println("a大于5");
} else if (a > 0) {
    System.out.println("a大于0,小于等于5");
} else {
    System.out.println("a小于等于0");
}

switch ステートメント:

switch ステートメントは、if-else if ステートメントと同様に、さまざまな条件に応じて異なる実行パスを選択するために使用されますが、switch ステートメントで判断できるのは整数、文字、および列挙型のみです。

文法形式:

switch (表达式) {
    case 值1:
        // 执行代码块1
        break;
    case 值2:
        // 执行代码块2
        break;
    ...
    default:
        // 执行代码块n
        break;
}

サンプルコード:

int a = 2;
switch (a) {
    case 1:
        System.out.println("a等于1");
        break;
    case 2:
        System.out.println("a等于2");
        break;
    default:
        System.out.println("a不等于1或2");
        break;
}

2. ループ文

ループ ステートメントは、コード ブロックを繰り返し実行するために使用されます。Java のループ ステートメントには、for ループ、while ループ、do-while ループが含まれます。

for ループ:

for ループはコードのブロックを繰り返し実行するために使用され、ループの数を指定できます。

文法形式:

for (初始化; 条件; 更新) {
    // 执行代码块
}

サンプルコード:

for (int i = 0; i < 5; i++) {
    System.out.println("i的值为:" + i);
}

while ループ:

while ループは、条件が true である限り、コードのブロックを繰り返し実行するために使用されます。

文法形式:

while (条件) {
    // 执行代码块
}

サンプルコード:

int i = 0;
while (i < 5) {
    System.out.println("i的值为:" + i);
    i++;
}

do-while ループ:

do-while ループは、コード ブロックを繰り返し実行するために使用されます。最初にコード ブロックを 1 回実行し、次に条件が true かどうかを判断し、true の場合は実行を継続し、そうでない場合はループを終了します。

文法形式:

do {
    // 执行代码块
} while (条件);

サンプルコード:

int i = 0;
do {
    System.out.println("i的值为:" + i);
    i++;
} while (i < 5);

4、Javaデータ型

Java は厳密に型指定された言語です。つまり、コードを記述するときに変数のデータ型を指定する必要があります。Java のデータ型は、プリミティブ データ型と参照データ型の 2 つのカテゴリに分類できます。

1. 基本的なデータ型

Java の基本的なデータ型には次のものがあります。

  • 整数: バイト、short、int、long
  • 浮動小数点型: float、double
  • 文字の種類: char
  • ブール値: ブール値

これらのデータ型には、次のように値の範囲と記憶領域のサイズが異なります。

2. 参照データ型

Java の参照データ型には次のものがあります。

  • 親切
  • インターフェース
  • 配列

参照データ型の変数には、オブジェクト自体ではなく、オブジェクトへの参照が格納されます。オブジェクト自体はヒープ メモリに格納され、参照はスタック メモリに格納されます。

3. 自動型変換と強制型変換

Java では、2 つのデータ型が異なる場合、自動型変換またはキャストを行うことができます。

自動型変換とは、あるデータ型の値が別のデータ型の変数に割り当てられると、Java がそれをターゲットの型に自動的に変換することを意味します。たとえば、int 型の値を double 型の変数に代入すると、Java は自動的に int 型を double 型に変換します。

キャストとは、あるデータ型を別のデータ型に変換することです。たとえば、double 型の値を int 型に変換する場合、必須の型変換記号「()」を使用する必要があります。

4.文字列型

Java の文字列型は参照データ型ですが、Java は文字列を作成するための特別な構文、つまりテキストの一部を二重引用符で囲む構文を提供します。例えば:

String str = "Hello, world!";

文字列型には、次のような一般的に使用されるメソッドもいくつか用意されています。

  • length(): 文字列の長さを返します。
  • charAt(int index): 指定された位置にある文字を返します。
  • substring(int beginIndex, int endIndex): 指定された範囲内の部分文字列を返します。
  • quals(String str): 2 つの文字列が等しいかどうかを比較します。

5. 配列型

Javaの配列は、同じ型の複数の値を格納できる参照データ型です。配列は次のように宣言されます。

データ型 [] 配列名 = 新しいデータ型 [配列長];

たとえば、長さ 5 の int 型の配列を宣言するには、次のようにします。

int[] arr = new int[5];

配列のアクセス方法は添字によるアクセスとなり、添字は0から始まります。たとえば、配列内の最初の要素にアクセスするには、次のようにします。

int first = arr[0];

配列には、次のような一般的に使用されるメソッドもいくつか用意されています。

  • length: 配列の長さを返します。
  • sort: 配列をソートします
  • toString: 配列を文字列に変換します

五、Javaデータ構造

Java はオブジェクト指向プログラミング言語であるため、データを処理および整理するための多くのデータ構造を提供します。Java で一般的に使用されるデータ構造は次のとおりです。

  • 配列 (Array) : 配列は、同じタイプのデータ要素のコレクションです。これらはメモリ内に連続して保存され、インデックスを介してアクセスできます。Java の配列は 1 次元または多次元にすることができます。

  • コレクション (コレクション) : コレクションは、要素を動的に増減できるオブジェクトのグループのコンテナーです。Java のコレクション フレームワークには、List、Set、Map が含まれます。

  • リスト (リスト) : リストは、繰り返しの要素を含めることができる順序付けされたコレクションです。Java の ArrayList と LinkedList は、一般的に使用されるリストの実装です。

  • セット (Set) : セットは、要素の重複を許可しないコレクションです。Java の HashSet と TreeSet は、一般的に使用されるセットの実装です。

  • マッピング (マップ) : マップはキーと値のペアのコレクションです。Java の HashMap と TreeMap は、一般的に使用されるマッピング実装です。

  • スタック: スタックは後入れ先出し (LIFO) データ構造です。Java の Stack クラスは、スタックの基本操作を実装します。

  • キュー: キューは先入れ先出し (FIFO) データ構造です。Java の LinkedList クラスは、キューの基本操作を実装します。

  • ツリー (ツリー) : ツリーは階層構造であり、各ノードは複数の子ノードを持つことができます。Java の TreeSet と TreeMap は、セットとマップのツリーベースの実装です。

  • グラフ: グラフはノードとエッジで構成されるデータ構造です。Java には組み込みのグラフ実装はありませんが、サードパーティのライブラリを使用して実装できます。

上記は Java で一般的に使用されるデータ構造であり、その特性と使用法を理解することは、データをより適切に処理および整理するのに役立ちます。

6、Java オブジェクト指向

APP リバース エンジニアとして、Java のオブジェクト指向プログラミングを理解することが重要です。オブジェクト指向プログラミング (略して OOP) は、プログラム内のオブジェクトを基本単位として使用し、オブジェクト間の対話を通じてタスクを完了するプログラミング パラダイムです。Java でのオブジェクト指向プログラミングの詳細な説明は次のとおりです。

  • クラスとオブジェクト: クラスはオブジェクトを定義するブループリントまたはテンプレートであり、オブジェクトはクラスのインスタンスです。クラスには、オブジェクトのプロパティ (フィールド/メンバー変数) と動作 (メソッド/メンバー関数) が含まれます。クラスのインスタンス(オブジェクト)を作成すると、クラス内に定義されたメソッドを呼び出してオブジェクトを操作できます。

  • カプセル化: カプセル化は、データの特定の実装の詳細を隠し、データにアクセスするための共通のインターフェイスを提供するために、データとメソッドを組み合わせた概念です。アクセサー (ゲッター) メソッドとモディファイアー (セッター) メソッドを通じて、オブジェクトの内部データへのアクセスとその変更を制御できます。

  • 継承: 継承とは、クラス (サブクラス/派生クラス) が別のクラス (親クラス/基本クラス) のプロパティとメソッドを継承できることを意味します。サブクラスは親クラスのメソッドを使用でき、それらに新しいプロパティやメソッドを追加したり、親クラスのメソッドを変更したりできます。継承により、コードの再利用と拡張が容易になります。

  • ポリモーフィズム: ポリモーフィズムとは、オブジェクトが複数の形式で現れる可能性があることを意味します。ポリモーフィズムにより、親クラス型の参照変数を使用して、サブクラスのインスタンス オブジェクトを参照できます。ポリモーフィズムにより、同じメソッドを呼び出して異なるオブジェクトに対して異なる動作を生成できるため、コードの柔軟性とスケーラビリティが実現します。

  • 抽象クラス: 抽象クラスは、インスタンス化できないクラスを指し、インスタンス化するためにサブクラスが実装する必要がある一連の抽象メソッドを定義します。抽象クラスは、クラスの一般的な特性を定義するためのテンプレートまたは制約を提供します。

  • インターフェイス: インターフェイスは、メソッド宣言のみを含み、メソッド実装を含まない純粋な抽象クラスです。クラスは 1 つ以上のインターフェイスを実装し、インターフェイスで定義されたメソッドを取得できます。インターフェイスは、ポリモーフィズムとコードの分離のための動作規約を提供します。

  • コンストラクター: コンストラクターは、オブジェクトの作成と初期化に使用される特別なメソッドです。これはクラスと同じ名前を持ち、戻り値の型はありません。コンストラクターを通じて、オブジェクトの初期状態とプロパティを設定できます。

  • メンバー変数とローカル変数: メンバー変数はクラス内で定義された変数であり、クラスのすべてのメソッドからアクセスできます。ローカル変数はメソッド内で定義された変数であり、メソッド内でのみアクセスできます。

オブジェクト指向プログラミングの概念を理解して適用することで、コードをより適切に整理して設計できるようになり、理解、拡張、保守が容易になります。これは、アプリのリバース エンジニアリングや高品質の Java コードの作成にとって非常に重要です。

7、Javaの継承関係チェーン

Java 言語では、継承関係はオブジェクト指向プログラミングの重要な概念の 1 つです。継承関係は、継承関係チェーンと呼ばれるクラス階層を形成します。Java 継承関係チェーンの関連概念について詳しく説明します。

  • クラス (クラス) : クラスは Java の基本的なプログラミング単位であり、オブジェクトのプロパティとメソッドを定義するために使用されます。クラスは別のクラスの親クラスまたはスーパークラスになることができ、他のクラスに継承できます。

  • 親クラス(スーパークラス)とサブクラス(サブクラス):継承関係において、親クラスは継承されたクラスを指し、サブクラスは親クラスを継承したクラスを指します。親クラスはスーパークラスまたは基本クラスとも呼ばれ、サブクラスは派生クラスとも呼ばれます。

  • 継承: キーワード extends を使用すると、クラスは別のクラスのプロパティとメソッドを継承できます。サブクラスは、フィールド、メソッド、コンストラクターなどの親クラスの特性を継承します。継承により、コードの再利用と拡張が可能になります。

  • 単一継承 (単一継承) : Java のクラスは単一継承のみをサポートします。つまり、クラスは直接の親クラスを 1 つだけ持つことができます。これは、多重継承によって引き起こされる可能性のある複雑さと競合の問題を回避するためです。

  • マルチレベル継承 (マルチレベル継承) : マルチレベル継承とは、継承関係が複数のレベルを形成できることを意味します。クラスは別のクラスのサブクラスであると同時に、他のクラスの親クラスにもなり、一連の継承関係を形成します。

  • Override : サブクラスは、同じメソッド名とパラメーター リストを定義することで、親クラスの既存のメソッドをオーバーライドできます。サブクラス オブジェクトのこのメソッドを呼び出すと、スーパークラスのメソッドではなく、サブクラスで定義されたメソッドが実行されます。

  • 親クラスのメソッドを呼び出す (スーパークラス メソッド呼び出し) : サブクラスは、super キーワードを使用して親クラスのメソッドを呼び出すことができます。これは通常、サブクラスがオーバーライドされたメソッドでスーパークラスの実装を使用する場合に使用されます。

  • 抽象クラス (抽象クラス) : 抽象クラスはインスタンス化できないクラスであり、一連の抽象メソッドを定義します。抽象クラスは親クラスとして他のクラスに継承でき、サブクラスは抽象クラスの抽象メソッドを実装する必要があります。

  • インターフェイス (インターフェイス) : インターフェイスは、メソッド宣言のみを含み、メソッド実装を含まない純粋な抽象クラスです。クラスは 1 つ以上のインターフェイスを実装し、インターフェイスで定義されたメソッドを取得できます。

継承関係チェーンを通じて、異なるクラス間に階層構造を確立し、コードの再利用と拡張を実現できます。サブクラスは親クラスのプロパティとメソッドを継承でき、新しいプロパティとメソッドを追加したり、親クラスのメソッドをオーバーライドしたりできます。これにより、コードがより整理され、理解と保守が容易になります。APP リバース エンジニアとして、継承関係チェーンを理解して適用すると、Java コードの分析と変更に役立ちます。

八、Javaパッケージの概念

Java のパッケージ (Package) は、クラスとインターフェイスを編成するためのメカニズムであり、関連するクラスとインターフェイスをまとめて管理し、使用しやすくします。パッケージは、関連するクラスとインターフェイスのセットが含まれるフォルダーと考えることができます。

Java のパッケージには次の機能があります。

  • 名前の競合を回避する: Java のパッケージでは、異なるパッケージが同じクラス名を持つことができるため、名前の競合を回避できます。

  • クラスとインターフェイスを整理する: Java のパッケージでは、管理と使用を容易にするために、関連するクラスとインターフェイスをまとめて整理できます。

  • アクセス制御: Java のパッケージは、アクセス修飾子を使用してクラスおよびインターフェイスへのアクセスを制御できます。

  • 名前空間を提供する: Java のパッケージは、異なるクラスやインターフェイス間の名前の競合を避けるために名前空間を提供します。

Java のパッケージの命名規則は、小文字を使用し、複数の単語をドット (.) で区切ることです (例: com.example.mypackage)。

Java では、パッケージを使用する構文は、クラスの先頭で package ステートメントを使用して、クラスが属するパッケージを宣言します。次に例を示します。

package com.example.mypackage;

public class MyClass {
    // 类的代码
}

他のパッケージのクラスを使用する場合は、次のように import ステートメントを使用してクラスをインポートする必要があります。

import java.util.ArrayList;

public class MyClass {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
        // 使用ArrayList类
    }
}

Java のパッケージはフォルダーの形式で編成されるため、パッケージ名とフォルダー名は一貫している必要があることに注意してください。たとえば、パッケージ名が com.example.mypackage のクラスは、com/example/mypackage ディレクトリの .java ファイルに保存する必要があります。

NDK開発トピックス

1. NDK データ型

NDK (Native Development Kit) は Android が提供する開発ツールで、開発者は C/C++ 言語で Android アプリケーションを作成できます。NDK ではデータ型は非常に重要な概念ですので、NDK のデータ型について詳しく説明します。

1. 基本的なデータ型

NDK では、int、float、double、char などの基本的なデータ型は C/C++ 言語と同じです。これらのデータ型は、C/C++ 言語と同じ方法で NDK で使用されます。

2. ポインタ型

ポインター型も NDK では非常に重要なデータ型であり、あらゆる種類のデータを指すことができます。NDK では、ポインタ型は C/C++ 言語と同じ方法で宣言されます。次に例を示します。

int *p;

3. 構造の種類

構造型は、NDK で非常に一般的なデータ型でもあり、異なる型の複数のデータを組み合わせることができます。NDK では、構造体型の宣言方法は C/C++ 言語と同じです。次に例を示します。

struct Person {
    char name[20];
    int age;
    float height;
};

4. 列挙型

列挙型も NDK で非常に一般的なデータ型であり、関連する定数のグループをグループ化できます。NDK では、列挙型は C/C++ 言語と同じ方法で宣言されます。次に例を示します。

enum Color {
    RED,
    GREEN,
    BLUE
};

5. 配列型

配列型は NDK で非常に一般的なデータ型でもあり、同じ型の複数のデータを結合できます。NDK では、配列型の宣言方法は C/C++ 言語と同じです。次に例を示します。

int arr[10];

6. 関数型へのポインタ

関数へのポインタ型も NDK では非常に一般的なデータ型であり、あらゆる種類の関数を指すことができます。NDK では、関数へのポインター型の宣言方法は C/C++ 言語の宣言方法と同じです。次に例を示します。

int (*p)(int, int);

上記は NDK で一般的なデータ型であり、開発者は NDK を開発に使用する際にこれらのデータ型の使用法を習得する必要があります。

2. JavaリフレクションとNDKの組み合わせ

Java リフレクションと NDK を組み合わせると、Java クラスのメソッドの呼び出しや、NDK レベルでの Java クラスのプロパティ値の取得など、いくつかの高度な機能を実現できます。以下は、Java リフレクションと NDK を組み合わせた実装の詳細な紹介です。

1. Java レベルで呼び出す必要があるメソッドまたはプロパティを定義します。

まず、Java レベルで呼び出す必要があるメソッドまたはプロパティを定義します。次に例を示します。

public class Test {
    private int value;

    public Test(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}

2. リフレクションを使用して Java クラスの Class オブジェクトを取得します

NDK レベルでは、リフレクションを使用して Java クラスの Class オブジェクトを取得する必要があります。次に例を示します。

jclass clazz = env->FindClass("com/example/Test");

3. Java クラスのコンストラクターを取得します。

リフレクションを使用して Java クラスのコンストラクターを取得します。次に例を示します。

jmethodID constructor = env->GetMethodID(clazz, "<init>", "(I)V");

4. Java オブジェクトの作成

リフレクションを使用して Java オブジェクトを作成します。次に例を示します。

jobject obj = env->NewObject(clazz, constructor, 10);

5. Javaクラスのメソッドを取得する

リフレクションを使用して Java クラスのメソッドを取得します。次に例を示します。

jmethodID getValueMethod = env->GetMethodID(clazz, "getValue", "()I");
jmethodID setValueMethod = env->GetMethodID(clazz, "setValue", "(I)V");

6. Javaクラスのメソッドを呼び出す

リフレクションを使用して Java クラスのメソッドを呼び出します。次に例を示します。

int value = env->CallIntMethod(obj, getValueMethod);
env->CallVoidMethod(obj, setValueMethod, 20);

7. Javaクラスの属性値を取得する

リフレクションを使用して Java クラスのプロパティ値を取得します。次に例を示します。

jfieldID valueField = env->GetFieldID(clazz, "value", "I");
int value = env->GetIntField(obj, valueField);

8. Javaクラスの属性値を設定する

リフレクションを使用して Java クラスのプロパティ値を設定します。次に例を示します。

env->SetIntField(obj, valueField, 30);

3. JNI は Java 関数オブジェクトを呼び出し、Java メソッドおよびクラスにアクセスします。

1. JNI は Java 関数オブジェクトを呼び出します

JNI では、JNIEnv オブジェクトを通じて Java のメソッドを呼び出すことができます。JNIEnv オブジェクトは JNI 環境へのポインタであり、Java オブジェクトにアクセスし、Java メソッドを呼び出すために使用できる一連の関数を提供します。

Java メソッドを呼び出す前に、Java メソッドの ID を取得する必要があります。Java メソッドの ID は、JNIEnv オブジェクトの GetMethodID 関数を呼び出すことで取得できます。GetMethodID 関数のパラメータには、Java クラスのオブジェクト、Java メソッドの名前、および Java メソッドのシグネチャが含まれます。

Java メソッドの ID を取得した後、JNIEnv オブジェクトの CallXXXMethod 関数を呼び出すことで Java メソッドを呼び出すことができます。このうち、XXX は Java メソッドの戻り値の型を表し、Int、Boolean、Object などになります。

以下は、Java メソッドを呼び出す JNI のサンプル コードです。

JNIEXPORT void JNICALL Java_com_example_test_TestJNI_callJavaMethod(JNIEnv *env, jobject obj) {
    jclass clazz = env->GetObjectClass(obj);
    jmethodID methodId = env->GetMethodID(clazz, "javaMethod", "()V");
    env->CallVoidMethod(obj, methodId);
}

上記のコードでは、まず GetObjectClass 関数を通じて Java クラスのオブジェクトを取得し、次に GetMethodID 関数を通じて Java メソッドの ID を取得し、最後に CallVoidMethod 関数を通じて Java メソッドを呼び出します。

なお、JNIがJavaメソッドを呼び出す場合には、Javaメソッドのアクセス権限がpublicであることを保証する必要がある。そうしないと、Java メソッドの呼び出し時に IllegalAccessException がスローされます。

2. Java メソッドとクラスにアクセスする

APP リバース エンジニアとして、Java のメソッドとクラスの概念を習得することは非常に重要です。以下では、Java のメソッドとクラスについて詳しく説明します。

1.方法(方法)

  • メソッドは、特定のアクションを実行するか、特定のタスクを完了する再利用可能なコード ブロックです。
  • メソッドは、メソッド名、パラメータ リスト (オプション)、戻り値の型、およびメソッド本体で構成されます。
  • メソッド名はメソッドを一意に識別するために使用され、パラメータ リストはメソッドに渡される値であり、戻り値の型はメソッドによって返される値の型を指定します。
  • メソッドはパラメータを受け入れて値を返すことも、パラメータを持たない no-return メソッドにすることもできます。
  • メソッドは呼び出しによって実行されます (メソッド名とパラメーター リストを使用)。

2.クラス(クラス)

  • クラスは、オブジェクトを作成するためのテンプレートまたは設計図であり、オブジェクトのプロパティと動作を定義します。
  • クラスは Java の基本的なプログラミング単位であり、すべてのオブジェクトはクラスからインスタンス化されます。
  • クラスはフィールド (メンバー変数) とメソッド (メンバー関数) で構成されます。
  • フィールドは、オブジェクトに関する状態情報を格納するクラス内の変数です。
  • メソッドは、オブジェクトの状態を操作するクラスで定義された動作です。

3. オブジェクト (オブジェクト) :

  • オブジェクトはクラスのインスタンスであり、キーワード new とクラスのコンストラクターを使用して作成されます。
  • オブジェクトにはクラスによって定義されたプロパティと動作があり、オブジェクトのフィールドとメソッドにアクセスして操作できます。
  • オブジェクトは独立して存在し、固有の状態を持ち、他のオブジェクトと相互作用することができます。

4. 施工方法(施工者)

  • コンストラクターは、オブジェクトの作成と初期化に使用される特別なメソッドです。
  • コンストラクターはクラスと同じ名前ですが、戻り値の型はありません。
  • コンストラクターは、 new キーワードを使用してオブジェクトが作成されるときに呼び出され、オブジェクトの状態を初期化するために使用されます。
  • Java では複数のコンストラクターを定義でき、異なるパラメーター リストによって区別されます。

5. 静的メソッド:

  • 静的メソッドは、クラスのインスタンスを作成せずに呼び出すことができるクラスレベルのメソッドです。
  • 静的メソッドはキーワード static で装飾されており、静的メンバー変数にアクセスして他の静的メソッドを呼び出すことのみが可能です。
  • 静的メソッドは通常、ユーティリティ関数や、特定のオブジェクトに依存する必要のないユーティリティ メソッドに使用されます。

6. カプセル化:

  • カプセル化とは、データとメソッドを 1 つのユニットに組み合わせて、データの隠蔽とアクセス制御を行うことです。
  • カプセル化では、private、public などのアクセス修飾子を使用して、クラスのフィールドおよびメソッドへのアクセスを制限します。

7. 継承:

  • 継承は、クラスが別のクラスからプロパティとメソッドを継承できるようにするオブジェクト指向の概念です。
  • 継承はキーワード extends を使用して実現され、サブクラスは親クラスの特性を継承し、独自の関数を追加できます。
  • 継承はコードの再利用と拡張のためのメカニズムを提供し、クラス間の階層構造を実装します。

8. ポリモーフィズム:

  • ポリモーフィズムは、オブジェクトをさまざまな方法で使用できるようにするオブジェクト指向プログラミングにおける重要な概念です。
  • ポリモーフィズムは、スーパークラス型の参照変数を使用してサブクラスのオブジェクトを参照することによって実現されます。
  • ポリモーフィズムは柔軟性とスケーラビリティを提供し、メソッドの動的なバインドを通じて、どのメソッドを呼び出すかを実行時に決定できます。

メソッドとクラスの概念をマスターすることが、APP のリバース エンジニアリングの鍵です。メソッドの作成および使用方法、クラスの定義およびインスタンス化の方法、カプセル化、継承、ポリモーフィズムなどの概念の使用方法を理解すると、Java コードをより適切に分析および変更できるようになります。

3、フックフレームワークのトピック

フリーダ・フック

Frida は、APP リバース エンジニアリング、セキュリティ テスト、脆弱性マイニングなどに使用できる強力な動的分析ツールです。この記事では、Frida の開発とデバッグ環境の構築、Frida の構造体配列オブジェクト、Frida と解凍、Frida Hook シェルとプラグイン dex、Frida のソース コードのコンパイル、Frida の検出とアンチデバッグの 6 つの方向から詳しく説明します。

1. Frida 開発およびデバッグ環境のセットアップ

1.フリーダをインストールする

Frida は Windows、macOS、Linux などの複数のプラットフォームをサポートしています。公式 Web サイトから対応するプラットフォームのインストール パッケージをダウンロードしてインストールできます。インストールが完了したら、コマンド ラインに frida -version コマンドを入力して、Frida が正常にインストールされたかどうかを確認できます。

2.Frida-Serverをインストールする

Frida-Server は Frida のコア コンポーネントであり、ターゲット デバイス上で実行され、Frida クライアントと通信します。APP リバース エンジニアリングに Frida を使用する場合、ターゲット デバイスに Frida-Server をインストールする必要があります。Frida-Serverのインストール方法は公式ドキュメントを参照してください。

3.Frida-Toolsをインストールする

Frida-Tools は、frida-ps、frida-trace、frida-discover などを含む Frida 用のツールのセットです。これらのツールは、動的分析に Frida をより便利に使用するのに役立ちます。コマンドラインに pip install frida-tools コマンドを入力して、Frida-Tools をインストールできます。

2. Frida は配列オブジェクトを構築します

APP リバース エンジニアリングに Frida を使用する場合、多くの場合、データ操作のためにいくつかの配列とオブジェクトを構築する必要があります。よく使われる施工方法を以下に紹介します。

1. 配列を構築する

配列は、Frida が提供する Java.array() メソッドを使用して構築できます。たとえば、長さ 3 の int 配列を構築するには、次のようにします。

var arr = Java.array("int", [1, 2, 3]);

2. オブジェクトを構築する

オブジェクトは、Frida が提供する Java.use() メソッドを使用して構築できます。たとえば、java.lang.String オブジェクトを構築するには、次のようにします。

var str = Java.use("java.lang.String").$new("hello");

3. フリーダと砲撃

APP リバース エンジニアリングを実行する場合、分析を改善するために APP を解凍することが必要になることがよくあります。一般的な解凍方法をいくつか紹介します。

1. Frida-Objection を砲撃に使用する

Frida-Objection は、APP シェル、データ漏洩検出、SSL ピンニング バイパスなどに使用できる、Frida ベースのモバイル デバイス セキュリティ テスト フレームワークです。Frida-Objection は、コマンド ラインで pip install object コマンドを入力することでインストールできます。

Frida-Objection を使用して解凍する手順は次のとおりです

  • 1) Fridaサーバーを起動します

ターゲットデバイス上で Frida-Server を起動します。

  • 2) フリーダの異議を開始

コマンドラインにobjectionexploreコマンドを入力して、Frida-Objectionを起動します。

  • 3) アプリを入力します

Frida-Objection のコマンドラインに Android 脱獄コマンドを入力して、APP に入ります。

  • 4) 砲撃

Frida-Objection コマンド ラインで dump -h コマンドを入力して解凍します。

2. フリーダを砲撃に使用する

Frida が提供する Java.perform() メソッドを使用して、シェル操作を実行できます。簡単な解凍スクリプトの例を次に示します。

Java.perform(function () {
    var BaseDexClassLoader = Java.use("dalvik.system.BaseDexClassLoader");
    var DexFile = Java.use("dalvik.system.DexFile");
    var PathClassLoader = Java.use("dalvik.system.PathClassLoader");
    var DexClassLoader = Java.use("dalvik.system.DexClassLoader");
    var File = Java.use("java.io.File");
    var System = Java.use("java.lang.System");
    var Runtime = Java.use("java.lang.Runtime");
    var Process = Java.use("android.os.Process");
    var String = Java.use("java.lang.String");
    var Arrays = Java.use("java.util.Arrays");

    var classLoader = Java.classFactory.loader;
    var dexFile = DexFile.$new("/data/app/com.example.app-1/base.apk");
    var dexElements = BaseDexClassLoader.getDeclaredField("dexElements");
    dexElements.setAccessible(true);
    var elements = dexElements.get(classLoader);
    var newElements = Arrays.copyOf(elements, elements.length);
    var dex = DexFile.$new(File.$new("/data/data/com.example.app/files/1.dex"));
    var newElement = DexClassLoader.$new("/data/data/com.example.app/files", null, null, classLoader).findClass("com.example.app.MainActivity").getDeclaredMethod("main", String.arrayOf(String));
    newElements[newElements.length - 1] = newElement.invoke(null, null);
    dexElements.set(classLoader, newElements);

    System.loadLibrary("native-lib");
    var handle = Runtime.getRuntime().exec("su");
    var outputStream = handle.getOutputStream();
    outputStream.write(("kill " + Process.myPid() + "\n").getBytes());
    outputStream.flush();
    outputStream.close();
});

4. Frida Hook シェルとプラグイン Dex

APP リバース エンジニアリングを実行する場合、多くの場合、分析を改善するためにいくつかのシェルとプラグイン dex をフックする必要があります。一般的に使用されるフック メソッドのいくつかを以下に紹介します。

1.フックシェル

Frida が提供する Java.use() メソッドを使用してシェルをフックできます。以下は、単純なフック シェル スクリプトの例です。

Java.perform(function () {
    var BaseDexClassLoader = Java.use("dalvik.system.BaseDexClassLoader");
    var DexFile = Java.use("dalvik.system.DexFile");
    var PathClassLoader = Java.use("dalvik.system.PathClassLoader");
    var DexClassLoader = Java.use("dalvik.system.DexClassLoader");
    var File = Java.use("java.io.File");
    var System = Java.use("java.lang.System");
    var Runtime = Java.use("java.lang.Runtime");
    var Process = Java.use("android.os.Process");
    var String = Java.use("java.lang.String");
    var Arrays = Java.use("java.util.Arrays");

    var classLoader = Java.classFactory.loader;
    var dexFile = DexFile.$new("/data/app/com.example.app-1/base.apk");
    var dexElements = BaseDexClassLoader.getDeclaredField("dexElements");
    dexElements.setAccessible(true);
    var elements = dexElements.get(classLoader);
    var newElements = Arrays.copyOf(elements, elements.length);
    var dex = DexFile.$new(File.$new("/data/data/com.example.app/files/1.dex"));
    var newElement = DexClassLoader.$new("/data/data/com.example.app/files", null, null, classLoader).findClass("com.example.app.MainActivity").getDeclaredMethod("main", String.arrayOf(String));
    newElements[newElements.length - 1] = newElement.invoke(null, null);
    dexElements.set(classLoader, newElements);

    System.loadLibrary("native-lib");
    var handle = Runtime.getRuntime().exec("su");
    var outputStream = handle.getOutputStream();
    outputStream.write(("kill " + Process.myPid() + "\n").getBytes());
    outputStream.flush();
    outputStream.close();
});

2. フックプラグインデックス

Frida が提供する Java.use() メソッドを使用して、プラグイン dex をフックできます。以下は、単純なフック プラグイン dex スクリプトの例です。

Java.perform(function () {
    var classLoader = Java.classFactory.loader;
    var dexFile = Java.use("dalvik.system.DexFile").$new("/data/data/com.example.app/files/1.dex");
    var dexElements = Java.cast(classLoader, Java.use("dalvik.system.BaseDexClassLoader")).pathList.dexElements;
    var newElements = Java.array("dalvik.system.DexFile$Element", [dexFile.entries()[0]]);
    var elements = Java.array("dalvik.system.DexFile$Element", dexElements);
    var allElements = Java.array("dalvik.system.DexFile$Element", [newElements[0], elements[0]]);
    Java.cast(classLoader, Java.use("dalvik.system.BaseDexClassLoader")).pathList.dexElements = allElements;
});

5、フリーダがコンパイルしたソースコード

APP リバース エンジニアリングを実行する場合、多くの場合、分析を改善するためにいくつかのソース コードをコンパイルする必要があります。一般的に使用されるいくつかのコンパイル方法を以下に紹介します。

1. dex2jarでコンパイルする

dex2jar は、dex ファイルを jar ファイルに変換するツールで、APP の dex ファイルを読み取り可能な jar ファイルに変換するために使用できます。コマンドラインに dex2jar.sh コマンドを入力して、dex2jar でコンパイルできます。

2. apktoolを使用してコンパイルします

apktool は、APK を逆コンパイルおよび再パッケージ化するためのツールであり、APP を逆コンパイルおよび再パッケージ化するために使用できます。コマンド ラインで apktool d コマンドを入力して APP を逆コンパイルし、apktool b コマンドを入力して APP を再パッケージ化できます。

6、Frida検出アンチデバッグ

APP リバース エンジニアリングを実行する場合、多くの場合、APP がアンチデバッグされているかどうかを検出する必要があります。一般的に使用されるいくつかの検出方法を以下に紹介します。

1. フックのデバッグ対策方法

Frida が提供する Java.use() メソッドを使用して、アンチデバッグ メソッドをフックできます。以下は、単純な Hook アンチデバッグ メソッド スクリプトの例です。

Java.perform(function () {
    var Debug = Java.use("android.os.Debug");
    Debug.isDebuggerConnected.implementation = function () {
        return false;
    };
});

2. デバッグ防止変数をフックする

Frida が提供する Java.use() メソッドを使用して、デバッグ防止変数をフックできます。以下は、単純な Hook アンチデバッグ変数スクリプトの例です。

Java.perform(function () {
    var ActivityThread = Java.use("android.app.ActivityThread");
    ActivityThread.currentApplication.implementation = function () {
        var app = this.currentApplication();
        var packageName = app.getPackageName();
        if (packageName.indexOf("com.example.app") != -1) {
            return null;
        } else {
            return app;
        }
    };
});

上記は、Frida HOOk トピックの詳細な説明です。APP リバース エンジニアリング愛好家にとって役立つことを願っています。

APPシェル処理

1. APP強化の原理の説明

APP 強化とは、モバイル アプリケーションの保護機能を向上させ、攻撃者によるリバース エンジニアリング、改ざん、データ漏洩などの悪意のある行為を防ぐためのセキュリティ強化処理を指します。以下は、APP 強化の原理の詳細な説明です。

  • コード難読化: コード難読化とは、ソース コードを変更および最適化して、コードの構造とロジックを複雑にして理解しにくくすることで、攻撃者によるアプリケーションの逆解析の難易度を高めます。変数や関数名の変更、冗長コードの追加、制御フローの変更などにより、攻撃者はコードの意味や実行の流れを理解しにくくなり、リバースエンジニアリングの成功率が低下します。

  • 暗号化保護: 暗号化保護は、機密データまたはキー コードを暗号化して、攻撃者がデータを直接取得および変更することを防ぎます。一般的な暗号化方法には、文字列、構成ファイル、アルゴリズム、ネットワーク通信の暗号化、対称または非対称暗号化アルゴリズムを使用してデータの機密性と整合性を保護する方法が含まれます。

  • セキュア ストレージ: セキュア ストレージとは、アプリケーションの機密データ (ユーザー資格情報、キー、証明書など) を暗号化されたコンテナーに保存し、悪意のあるアプリケーションや攻撃者による取得を防ぐことを指します。強化ツールは、安全なストレージを提供し、機密データを暗号化し、キーを使用してデータのセキュリティを保護できます。

  • アンチデバッグおよびアンチ動的分析: 攻撃者がアプリケーションをデバッグおよび動的に分析して重要な情報を取得するのを防ぐために、強化ツールはアンチデバッグおよびアンチ動的分析技術を使用できます。たとえば、デバッガの存在の検出、動作環境の変化の監視、動的にロードされるライブラリの挿入の防止などの方法により、攻撃者によるアプリケーションの分析や変更を防ぐことができます。

  • セキュリティ認証と改ざん防止: アプリケーションの正当性と完全性を保証するために、強化ツールはデジタル署名、ダイジェスト検証、コード整合性検証を通じてセキュリティ認証を実行できます。これらのテクノロジーは、アプリケーションの改ざん、悪意のあるコードの埋め込み、悪意のあるアプリケーションによる置き換えを防ぎます。

  • 実行時保護: アプリケーション実行中のセキュリティ問題を目的として、強化ツールは実行時保護メカニズムを提供できます。たとえば、メモリ オーバーフロー、バッファ オーバーフロー、コード インジェクション、動的にロードされたライブラリの不正な呼び出しなどのランタイム攻撃を検出して防止し、アプリケーションのセキュリティを向上します。

APP の強化によりアプリケーションのセキュリティは向上しますが、すべてのセキュリティ リスクを完全に排除できるわけではないことに注意してください。攻撃者は、高度なリバース エンジニアリング技術と脆弱性を使用して、強化されたアプリケーションを攻撃する可能性があります。したがって、開発者とセキュリティ チームは、セキュリティ テクノロジと戦略を組み合わせて使用​​し、包括的なアプリケーション セキュリティ保護を実現する必要があります。

2. APPがパックされているかどうかを確認する方法

APP がパックされているかどうかを識別するには、次の方法を検討できます。

  • 静的解析:APPを静的に解析し、APPのファイル構造や内容を確認することで、パッキングの有無を事前に判断できます。パッカーは通常、解凍するために元のバイナリにコードの一部を挿入するため、解凍するコードに類似した署名を見つけるようにしてください。

  • 動的デバッグ: デバッグ ツールを使用して APP を動的にデバッグし、その動作と実行プロセスを観察し、パックするかどうかを決定するための詳細情報を取得します。たとえば、アンパック動作があるかどうかを検出し、メモリ内のアンパック コードを表示し、アプリケーションによってロードされたダイナミック ライブラリを監視します。

  • 逆コンパイル解析:アプリを逆コンパイルしてソースコードまたは類似のソースコードを復元し、逆コンパイルされたコードを解析することでパックされているかどうかを判断できます。通常、パッキング ツールは、いくつかの特別な命令や関数呼び出しをコードに挿入するか、コードを書き換えて再構築しますが、これらはすべて逆コンパイル分析を通じて判断できます。

  • 特別なツールを使用する: パッカーを検出および識別して判断を支援するために特別に設計されたツールがいくつかあります。たとえば、AndroGuard、Frida、IDA Pro などのツールはすべて、梱包状況を分析および特定するための特定の機能を備えています。

梱包技術は開発と進化を続けており、新しい梱包方法では従来の識別方法の一部が回避される可能性があることに注意してください。したがって、パッカーの特定は継続的な課題であり、複数の方法とツールの組み合わせが必要であり、単一の判断基準に依存するものではありません。

3、フリーダダンプ砲撃スキル

Frida-dump は、Frida フレームワークに基づいて開発された、パックされたアプリケーションを解凍 (ダンプ) するためのツールです。実行時にアプリケーションを動的に挿入し、強化された保護手段をバイパスし、アプリケーションの復号化されたメモリ イメージを抽出できます。以下は、Frida ダンプ解凍手法の詳細な説明です。

  • Frida 環境のセットアップ: まず、コンピューターに Frida フレームワークをインストールし、動作環境を構成する必要があります。詳細については、Frida の公式ドキュメントで提供されるインストールおよび構成ガイドを参照してください。

  • 強化ポイントの特定: Frida-dump を使用する前に、ターゲット アプリケーションで使用される強化スキームを理解する必要があります。さまざまな強化スキームでは、特定の Frida スクリプトを使用して保護メカニズムをバイパスする必要がある場合があります。DEX 暗号化、関数の復号化などの一般的な強化スキームの場合、強化ポイントの位置は静的分析またはデバッグを通じて確認できます。

  • Frida スクリプトの作成: ターゲット アプリケーションの強化スキームに応じて、アプリケーションの実行中に強化ポイントを特定してバイパスするカスタム Frida スクリプトを作成できます。Frida スクリプトは JavaScript で記述されており、コード インジェクションと動的デバッグのために Frida が提供する API を使用できます。

  • 動的インジェクションとアンパック: 作成された Frida スクリプトを使用し、ターゲット アプリケーションを実行し、スクリプトをアプリケーション プロセスにインジェクトします。アプリケーションの実行中にスクリプトが自動的に実行され、メモリ アクセスを監視して復号化されたメモリ領域が特定され、ローカル ファイル システムにエクスポートされて解凍操作が完了します。

Frida-dump を使用した解凍は高度な技術であり、モバイル アプリケーションの内部構造と強化メカニズムをある程度理解する必要があることに注意してください。さらに、解凍には法的および倫理的な影響がある可能性があるため、合法的なセキュリティ評価および研究目的でのみ、慎重に使用する必要があります。さらに、Frida-dump などの解凍ツールを使用した解凍操作によって、アプリケーション独自のデバッグ防止およびクラック防止メカニズムがトリガーされ、解凍の失敗やアプリケーションの異常終了が発生する可能性があります。

smail 構文

アプリをリバース エンジニアリングする場合、smari 構文を理解することは非常に重要です。以下では、smali 構文のデータ型、定数宣言構文、メソッド関数の宣言、コンストラクターの宣言、静的コード ブロックの宣言、インターフェイスに基づく呼び出しについて詳しく紹介します。

1. データ型:

smali は次のデータ型をサポートします。

  • Z:ブール型
  • B:バイト型
  • S:ショートタイプ
  • C:char型
  • I:int型
  • J:ロングタイプ
  • F:フロート型
  • D: double 型
    L クラス名;: 参照型
    たとえば、I は int 型を意味し、Ljava/lang/String; は参照型が java.lang.String であることを意味します。

2. 定数宣言の構文:

定数の宣言には const 命令を使用します。構文は次のとおりです。

const 寄存器, 常量值

たとえば、const v0, 10 は、レジスタ v0 を整数定数値 10 に設定することを意味します。

3. メソッド関数の宣言:

メソッド関数の宣言では、method キーワードを使用し、構文は次のとおりです。

.method 修饰符 返回类型 方法名(参数列表) [异常列表]

    方法体

.end method

修飾子には、public、private、protected、abstract、static などが含まれます。
戻り値の型は、上記のデータ型で表される任意のデータ型にすることができます。
パラメータのリストはカンマで区切られ、各パラメータはタイプと変数名で構成されます。

例えば、

.method public static add(II)I

    ...

.end method

int 型の 2 つのパラメーターを受け取り、int 型の値を返す add という名前のパブリック静的メソッドを表します。

4 番目に、コンストラクターの宣言:

コンストラクターの宣言では、constructor キーワードを使用します。構文は次のとおりです。

.constructor 修饰符(参数列表) [异常列表]

    构造函数体

.end constructor

コンストラクターとメソッド関数は同様に宣言されますが、戻り値の型はありません。

例えば、

.constructor public <init>()V

    ...

.end constructor

パラメーターのないパブリック コンストラクターを表します。

5. 静的コードブロックの宣言:

静的コード ブロックは clinit キーワードを使用して宣言され、構文は次のとおりです。

.clinit

    静态代码块体

.end clinit

静的コード ブロックはクラスのロード時に実行され、一度だけ実行されます。

例えば、

.clinit

    # 执行静态代码块的操作

.end clinit

静的コードブロックを表します。

6. インターフェイスベースの呼び出し:

smali では、invoke-interface コマンドを使用してインターフェイスのメソッドを呼び出します。構文は次のとおりです。

invoke-interface {参数列表}, 接口类型->方法签名

このうち、パラメータ リストはメソッドに渡されるパラメータ、インターフェイス タイプは呼び出されるインターフェイスのタイプ、メソッド シグネチャは呼び出されるメソッドの記述子です。

例えば、

invoke-interface {v0}, Ljava/util/Iterator;->next()Ljava/lang/Object;

java.util.Iterator インターフェースの次のメソッドを呼び出すことを示します。

これらは、データ型、定数宣言、メソッド関数宣言、コンストラクター宣言、静的コード ブロック宣言、および smali 構文でのインターフェイス ベースの呼び出しについて詳しく説明します。これらの文法規則を理解することで、リバース エンジニアリングで小さなコードをより適切に分析および変更できるようになります。smali 構文は大きく複雑であり、熟練するには継続的な練習と探索が必要であることに注意してください。

APP RPC トピック

1. frida rpc プラグインを作成する

Frida は、モバイル アプリケーションのリバース エンジニアリングとデバッグに使用できる強力な動的分析ツールです。中でも RPC (Remote Procedure Call) は Frida の重要な機能であり、Frida クライアントと Frida サーバー間の通信を可能にし、より柔軟で効率的な動的分析を実現します。

この記事では、Frida クライアントと Frida サーバー間で通信するための Frida RPC プラグインを作成する方法について説明します。

1. Frida RPC プラグインを作成する

まず、Frida RPC プラグインを作成する必要があります。Frida では、RPC プラグインは、Frida クライアントと Frida サーバー間の RPC 通信を介してロードおよび実行できる JavaScript ファイルです。

以下は、単純な Frida RPC プラグインの例です。

rpc.exports = {
  add: function (a, b) {
    return a + b;
  },
  sub: function (a, b) {
    return a - b;
  }
};

この例では、加算と減算をそれぞれ実装する 2 つの関数 add と sub を定義します。これらの関数は、Frida クライアントと Frida サーバー間の RPC 通信を通じて呼び出すことができます。

2. Frida RPC プラグインをロードします

Frida RPC プラグインを作成したら、それをロードして Frida クライアントと Frida サーバーの間で通信できるようになります。Frida クライアントでは、次のコードを使用して Frida RPC プラグインをロードできます。

const rpc = new frida.Rpc(peer);
const plugin = rpc.use("path/to/plugin.js");

この例では、まず Frida RPC オブジェクト rpc を作成し、次に use メソッドを使用して Frida RPC プラグインをロードします。ピア パラメータは、Frida サーバーのアドレスとポート番号を指定します。

3. Frida RPC プラグインを呼び出します。

Frida RPC プラグインをロードすると、Frida クライアントと Frida サーバー間の RPC 通信を通じて、そのプラグインに定義されている関数を呼び出すことができます。Frida クライアントでは、次のコードを使用して Frida RPC プラグインの関数を呼び出すことができます。

const result = await plugin.add(1, 2);
console.log(result);

この例では、Frida RPC プラグインの add 関数を呼び出し、2 つのパラメーター 1 と 2 を渡します。呼び出しの結果は結果変数に保存され、コンソールに出力されます。

4. まとめ

この記事では、Frida RPC プラグインを作成し、Frida クライアントと Frida サーバー間で通信する方法について説明しました。Frida RPC プラグインを使用することで、より柔軟で効率的な動的分析を実現し、モバイル アプリケーションをより深く理解し、安全にすることができます。

2. frida を使用して Java コードをリモートで呼び出す

Frida を使用して Java コードをリモートで呼び出す前に、いくつかの基本的な概念と手順を理解する必要があります。

1. フリーダとは何ですか?

Frida は、Android および iOS アプリケーションを動的に分析および変更するために使用できる JavaScript ベースの動的コード インジェクション ツールです。Frida は、関数呼び出し、パラメーターの受け渡し、戻り値などを含む、実行時のアプリケーションの動作を変更できます。

2. RPC とは何ですか?

RPC (リモート プロシージャ コール) は、クライアントがローカル関数を呼び出すのと同じようにリモート サーバー上の関数を呼び出すことができるリモート プロシージャ コール プロトコルです。RPC を使用すると、アプリケーションが異なるコンピュータ上で通信して分散コンピューティングを実現できます。

3. RPC に Frida を使用するにはどうすればよいですか?

Frida は、JavaScript コードがローカル デバイスとリモート デバイス間で通信できるようにする RPC メカニズムを提供します。RPC を使用すると、ローカル デバイスで JavaScript コードを記述し、そのコードをリモート デバイスで実行して、Java コードをリモートで呼び出す機能を実現できます。

以下は、Frida を使用して Java コードをリモートで呼び出す詳細な手順です。

  • ローカルデバイス上にJavaScriptコードを記述して、リモートからJavaコードを呼び出す機能を実現します。たとえば、Java.perform() メソッドを使用して Java 仮想マシン インスタンスを取得し、Java クラスのメソッドを呼び出すことができます。
Java.perform(function() {
    var MainActivity = Java.use("com.example.MainActivity");
    MainActivity.sayHello.implementation = function() {
        console.log("Hello from Frida!");
        return this.sayHello();
    }
});
  • JavaScript コードを rpc.js などのファイルとして保存します。

  • リモート デバイスに Frida をインストールし、Frida サービスを開始します。Frida サービスは次のコマンドで開始できます。

frida-server -l 0.0.0.0
  • リモート デバイス上でターゲット アプリケーションを起動し、アプリケーションのプロセス ID を記録します。

  • ローカル デバイスで Frida コマンド ライン ツールを使用してリモート デバイスに接続し、JavaScript コードをロードします。次のコマンドを使用してリモート デバイスに接続できます。

frida -U -f com.example.app -l rpc.js

このうち、com.example.appは対象アプリケーションのパッケージ名、rpc.jsはJavaScriptコードを保存するファイル名です。

  • ローカルデバイス上でJavaScriptコードを実行し、リモートからJavaコードを呼び出す機能を実現します。JavaScript コードは、次のコマンドを使用して Frida コンソールで実行できます。
rpc.exports.sayHello();

このうち、sayHello()はJavaScriptコード内で定義されている関数名です。

上記の手順により、Frida を使用して Java コードをリモートで呼び出すことができます。Frida の RPC メカニズムはローカル デバイスとリモート デバイス間でのみ通信でき、異なるリモート デバイス間では通信できないことに注意してください。

三、sekiroフレームワークのソースコード解体

SEKIRO フレームワークは、Netty と SpringBoot をベースとした、クロスプロセスおよびクロスプラットフォームのリモート呼び出しを実現できるリモート呼び出しフレームワークです。sekiroフレームワークを使用する場合、サーバーとクライアント用のコードを記述する必要があります。サーバーはSekiroServerインターフェイスを実装する必要があり、クライアントはSekiroClientインターフェイスを実装する必要があります。

リモート呼び出しがどのように実装されているかを理解するために、Sekiro フレームワークのソース コードを逆アセンブルしてみましょう。

1.セキロサーバー

sekiroServer は、Sekiro フレームワークのサーバー インターフェイスであり、次のメソッドを定義します。

public interface SekiroServer {
    void start() throws Exception;
    void stop() throws Exception;
    void registerHandler(String uri, SekiroRequestHandler handler);
}

このうち、start()メソッドはサーバーの起動に使用され、stop()メソッドはサーバーの停止に使用され、registerHandler()メソッドはリクエスト ハンドラーの登録に使用されます。

2.SekiroRequestHandler

sekiroRequestHandler は、Sekiro フレームワークのリクエスト ハンドラー インターフェイスであり、次のメソッドを定義します。

public interface SekiroRequestHandler {
    void handle(SekiroRequest sekiroRequest, SekiroResponse sekiroResponse);
}

このうち、handle()リクエストを処理し、処理結果をレスポンスに書き込むメソッドです。

3.セキロクライアント

sekiroClient は、Sekiro フレームワークのクライアント インターフェイスであり、次のメソッドを定義します。

public interface SekiroClient {
    void start() throws Exception;
    void stop() throws Exception;
    SekiroResponse invokeSync(String uri, SekiroRequest sekiroRequest) throws Exception;
}

このうち、start()メソッドはクライアントの起動に使用され、stop()メソッドはクライアントの停止に使用され、invokeSync()メソッドはリモート サービスを同期的に呼び出すために使用されます。

4.隻狼リクエスト

sekiroRequest は、Sekiro フレームワークのリクエスト オブジェクトであり、リクエストされた URI、リクエスト パラメータ、その他の情報が含まれています。

5.セキロレスポンス

sekiroResponse は、Sekiro フレームワークの応答オブジェクトであり、応答ステータス コード、応答データ、その他の情報が含まれています。

6.SekiroServerHandler

sekiroServerHandler は、Sekiro フレームワークのサーバー側プロセッサであり、Netty の SimpleChannelInboundHandler クラスを継承してクライアントのリクエストを処理します。

sekiroServerHandler では、次のコードが確認できます。

@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
    if (msg instanceof FullHttpRequest) {
        FullHttpRequest request = (FullHttpRequest) msg;
        String uri = request.uri();
        if (uri.startsWith("/api/")) {
            handleHttpRequest(ctx, request);
        } else {
            ctx.fireChannelRead(msg);
        }
    } else {
        ctx.fireChannelRead(msg);
    }
}

このコードは、リクエストの URI が「/api/」で始まるかどうかを判断するために使用され、そうである場合はメソッドを呼び出してhandleHttpRequest()リクエストを処理し、それ以外の場合はリクエストを次のプロセッサに渡します。

handleHttpRequest()メソッド内には次のコードがあります。

SekiroRequest sekiroRequest = SekiroRequestParser.parse(request);
SekiroResponse sekiroResponse = new SekiroResponse();
sekiroResponse.setRequestId(sekiroRequest.getRequestId());
sekiroResponse.setVersion(sekiroRequest.getVersion());
sekiroResponse.setStatusCode(200);
sekiroResponse.setContentType("application/json;charset=UTF-8");
try {
    SekiroRequestHandler handler = handlerMap.get(sekiroRequest.getUri());
    if (handler != null) {
        handler.handle(sekiroRequest, sekiroResponse);
    } else {
        sekiroResponse.setStatusCode(404);
        sekiroResponse.setContent("{\"message\":\"No handler found for uri: " + sekiroRequest.getUri() + "\"}");
    }
} catch (Exception e) {
    sekiroResponse.setStatusCode(500);
    sekiroResponse.setContent("{\"message\":\"" + e.getMessage() + "\"}");
}

このコードは、リクエストを解析し、応答オブジェクトを作成し、リクエストの URI に従って対応するリクエスト プロセッサを見つけるために使用されます。見つかった場合は、リクエスト プロセッサが呼び出されてリクエストを処理します。見つからない場合は 404 エラーが返されます。

7.SekiroClientHandler

sekiroClientHandler は、Sekiro フレームワークのクライアント プロセッサであり、Netty の SimpleChannelInboundHandler クラスを継承してサーバー側の応答を処理します。

sekiroClientHandler では、次のコードが確認できます。

@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
    if (msg instanceof FullHttpResponse) {
        FullHttpResponse response = (FullHttpResponse) msg;
        String content = response.content().toString(CharsetUtil.UTF_8);
        SekiroResponse sekiroResponse = JSON.parseObject(content, SekiroResponse.class);
        if (sekiroResponse.getStatusCode() == 200) {
            promise.setSuccess(sekiroResponse);
        } else {
            promise.setFailure(new SekiroException(sekiroResponse.getStatusCode(), sekiroResponse.getContent()));
        }
    } else {
        ctx.fireChannelRead(msg);
    }
}

このコードは、レスポンスのステータスコードが200であるかどうかを判定するために使用されます。イエスの場合はレスポンスをSekiroResponseオブジェクトに変換し、Promiseの成功結果として設定します。それ以外の場合は、レスポンスの内容を例外情報として使用して設定します。約束の失敗の結果として。

上記のコードの分析を通じて、Sekiro フレームワークがリモート呼び出しをどのように実装するかを理解できます。サーバー側では、Netty を通じてクライアント リクエストを受信し、リクエストの URI に従って対応するリクエスト プロセッサを見つけて、リクエスト プロセッサを呼び出してリクエストを処理し、処理結果をレスポンスに書き込みます。クライアント側では、Netty 経由でサーバーにリクエストを送信し、サーバーからの応答を待ち、その応答をsekiroResponse オブジェクトに変換し、Promise の成功または失敗の結果として設定します。

ゼロベースの学習と上級者に適した Python リソース:
① Tencent 認定 Python 完全プロジェクトの実践的なチュートリアル ノート PDF
② 十数の主要工場の Python インタビュー トピック PDF
③ Python フルセットのビデオ チュートリアル (ゼロベースから上級の JS リバース)
④数百のプロジェクト + ソースコード + メモ
⑤ プログラミング文法 - 機械学習 - フルスタック開発 - データ分析 - 爬虫類 - APP リバースおよびその他のプロジェクトのフルセット + ドキュメント

おすすめ

転載: blog.csdn.net/ch950401/article/details/132259721