Android ネイティブ ライブラリがリリースされる前に、その強化措置が最終製品に実装されていることを確認するにはどうすればよいでしょうか?この記事では、readelf、c++filt、文字列などのツールを組み合わせて、シンボルのエクスポート、機密文字列、JNI 呼び出し、ランタイム保護に関する検査のアイデアを整理し、静的分析と動的検証の境界を区別し、その後のリリースの検証と回帰を容易にするためにバージョンに保持できるチェックリストを提供します。
リリース前にネイティブ ライブラリを確認してください。ビルド構成でストリップまたは難読化が有効になっているかどうかを確認するだけではありません。実際に納品された書類が期待通りの処理をしているかどうかは、最終的なパッケージから確認する必要があります。
検査で「合格」という言葉だけを残すことはお勧めできません。ファイル バージョンを保存し、リストをエクスポートし、検証結果を実行すると、次回ツール チェーンをアップグレードしたり、JNI インターフェイスを変更したり、保護構成を調整したりするときに、内容を比較できるようになります。
以下は、実際の製品、記号、文字列、および実行検証に従って整理されたチェック シーケンスです。
最終パッケージ内のライブラリを必ずチェックしてください
リリースするパッケージからこれを抽出し、パッケージとともに提供される各 ABI をカバーし、パッケージのバージョン、ライブラリ パス、およびファイル ハッシュを記録します。
GNU ツールがインストールされている環境では、まず次のコマンドを実行できます。
# 记录当前文件,避免后续混淆样本
sha256sum libgame.so
# 查看 ELF 基本信息和节区
readelf -h libgame.so
readelf -S -W libgame.so
このステップでは、まず対象を確認し、保護の強度を急いで判断しないでください。開発ディレクトリで処理されるライブラリと、最終的にパッケージに組み込まれるライブラリは、ファイル名だけでは特定できません。
シンボルのクリッピングとパブリックインターフェイスをチェックする
シンボルの確認を続けます。
readelf --syms -W libgame.so | c++filt
readelf --dyn-syms -W libgame.so | c++filt
デバッグ情報、通常のシンボル テーブル、および動的シンボル テーブルを別々に見る必要があります。剥奪を実行しても、すべての企業名が消えるわけではありません。動的シンボルにはインポートも含まれており、定義ステータス、バインディング タイプ、および可視性と組み合わせて、どれがパブリック インターフェイスであるかを決定する必要があります。
ライブラリ内でのみ使用されるビジネス関数については、エクスポートされるかどうかを確認してください。名前修飾子 c++filt 処理後も、クラス名、関数名、パラメータ情報が公開される可能性があります。
冗長なエクスポートを検出したら、構築フェーズに戻ってインターフェイスを統合できます。たとえば、次のように使用します。 RegisterNatives() 他にエクスポート要件がない登録メソッドと JNI ライブラリの場合は、バージョン スクリプトを使用して、 JNI_OnLoad。
ただし、名前で検索される JNI メソッドと、他の共有ライブラリが呼び出す必要があるインターフェイスは引き続き保持する必要があります。エクスポートが削減された後は、JNI 登録、実際の呼び出し、およびライブラリ間の依存関係を返す必要があり、シンボルの数だけを比較することはできません。
ログに事業所の所在地が明らかにされているかどうかを確認する
次のラウンドでは、読み取り可能な文字列がチェックされます。
strings -a -t x libgame.so | rg -i 'signature|reward|decrypt|\.json'
ここでは GNU Binutils と ripgrep を使用しますが、キーワードはプロジェクトに応じて調整する必要があります。-t x 出力ファイルのオフセットを実行時アドレスとして直接使用することはできません。ヒットがないことは公開されていないことを証明するものではなく、文字列が他のエンコーディングであるか、分割されているか、実行時に生成されている可能性があります。
検証失敗ログ、復号化プロンプト、報酬設定フィールド、内部リソース パスなど、ビジネス上重要な結果に優先順位を付けます。合計で何行抽出されるかよりも、範囲をいくつかの関数に絞り込めるかどうかの方が重要です。
まず不要なリリース ログをクリーンアップします。機密文字列が暗号化された後、それがいつ復元されるか、また長時間キャッシュされているかどうかを観察します。ファイル内にはクリアテキストが確認できないため、今回の検査に代わることはできません。
検証レコードを個別に実行する
静的検査では、名前と論理の手がかりを明らかにすることはできますが、実際のデバッグ防止、インジェクション検出、または耐改ざん効果を確実に証明することはできません。
動作検証では少なくとも、関連する状況が発生した後、検出がトリガーされるかどうか、トリガー後にどのようなアクションが実行されるか、通常の使用に影響があるかどうかに焦点を当てる必要があります。関連するインポートされた関数が表示されるだけでは、保護が実際に有効になるわけではありません。
難読化の範囲もパフォーマンスの低下とともに検査されます。フレームごとの計算、低頻度の認証チェック、およびリソースの読み込みでは、オーバーヘッドの許容範囲が異なります。起動、ホットスポットの実行、リソースの読み込みの変化は、同等のデバイスとシナリオで観察する必要があります。
リリースごとに比較記録を保持する
| チェック項目 | 内容を確認する | 結果を維持する |
|---|---|---|
| 実際の商品 | 最終パッケージ内の各 ABI のライブラリがカバーされているかどうか | パッケージのバージョン、パス、ファイルのハッシュ |
| シンボルのエクスポート | 冗長なビジネスインターフェイスがあるかどうか | シンボル出力、必要なインターフェース一覧 |
| 通話の互換性 | JNI およびライブラリ間の呼び出しは正常ですか? | 回帰シナリオと結果 |
| 弦 | ログとパスから機密プロセスが明らかになりますか? | ヒット位置と処理記録 |
| キーロジック | コア機能は見つけやすく、理解しやすいですか? | エントリーの手がかりとコール関係の分析 |
| ランタイム保護 | 検出がトリガーされたかどうか、および処理が期待どおりであるかどうかを確認する | テスト条件、応答、および例外レコード |
| パフォーマンス | 起動、ホットスポット機能、読み込みに明らかなオーバーヘッドはありますか? | 同じシーンでの補強前後の結果 |
| サーバー側の検証 | クライアントの変更は報酬、有給特典、その他の結果に影響を与える可能性がありますか? | 検証ルールと検証結果 |
このテーブルはバージョンとともに保持し、構成またはツール チェーンの変更後に影響を受けるプロジェクトを確認できます。
so ファイルを分析ツールで開けるかどうか、欠落しているシンボルの数はチェックの一部にすぎません。さらに追跡する価値があるのは、主要なロジックの配置コストが変化したかどうか、およびコードの実行後も保護措置が引き続き有効かどうかです。