JavaソースコードなしでAndroidアプリをデバッグする:ブレークポイントに関するいくつかの言葉

この記事について


これは、 JavaソースコードなしでAndroidアプリケーションをデバッグすることに関する昨日の私の記事の続きです (誰かがそれを読んでいないなら、それから始めることを強くお勧めします)。 昨日、ApkツールバンドルとNetBeansを設定して使用を開始する方法について順を追って説明しました。 そこの最後の2つのポイントは、次のようなものでした。

13.関心のある命令にブレークポイントを設定します...何とか何とか...

14.ブレークポイントが機能するように、アプリケーションで何かを行います。 その後、段階的なデバッグを実行したり、フィールドや変数の値を表示したりできます。

さらに、落とし穴のセクションでは、アプリケーションを開始するアクティビティのonCreate(...)メソッドの命令にブレークポイントを設定するなど、最初からアプリケーションのデバッグを開始できない理由について説明しました。

この記事では、最初からJavaソースコードなしでアプリケーションのデバッグを開始する方法を示します。 この記事も初心者向けではありません。 少なくともSmaliアセンブラーの構文を理解し、ペンで.smaliファイルにパッチを当て、そこにコードを正しく入力できる必要があります。

ツール


再びApk-tool 1.4.1NetBeans 6.8が必要です -これらはこれまでで最も古いバージョンです。 新しいバージョンでは、デバッグを機能させることができません。 そして、私だけでなく、テーマ別フォーラムでの議論によって判断します。

昨日の記事ですでにApkツールとNetBeansのインストールについて説明しましたが、それでも繰り返します。 NetBeansはデフォルトでインストールされます。インストールウィザードで[次へ]、[次へ]、[次へ]の順にクリックするだけです。 Apk-toolsのインストールは、 apktool.jarファイルをアーカイブから任意のフォルダーに抽出するapktool.jarです。

アプリケーションの最初にブレークポイントを置く方法


アイデアは一般的にシンプルです。 最初にアプリケーションで開始するアクティビティを見つけ、このアクティビティのonCreate(...)メソッドの開始時に無限ループに入る必要があります。 アプリケーションが起動し、このアクティビティのコンストラクターを呼び出した直後に、 onCreate(...)メソッドが呼び出されます。 その結果、制御は無限のサイクルに陥ります。 そこでループが回転している間、実行中のアプリケーションにデバッガーをゆっくりとアタッチし、無限ループの直後にブレークポイントを配置してから、デバッガーの機能を利用して、制御をこのループから抜けさせます。 そしてすぐにブレークポイントに到達しました。 ご覧のとおり、すべてが基本です。

このセクションでは、手順を追って説明します。 この指示はWindows用に書かれていますが、ほとんどの場合、LinuxおよびMac OSで動作します。

指示に正確に従ってください-これは重要です!

  1. Apkツールを使用して、.apkファイルをtempディレクトリにデコードします。 -dオプションを使用しないでください
     java -jar apktool.jar d my.app.apk temp 

    その結果、 temp/smaliディレクトリに多数の.smaliファイルが作成されます。
  2. temp/AndroidManifest.xmlファイルで、アクティビティを見つけます
     <intent -filter="-filter"> <action android:name="android.intent.action.MAIN"> <category android:name="android.intent.category.LAUNCHER"> </intent> 

    これは、アプリケーションで最初に開始されるアクティビティです。
  3. 最初にアプリケーションで開始するアクティビティを見つけましたか? ここで、このアクティビティのクラス(通常はandroid.app.Activityクラスの子孫)を実装する.smaliファイルを見つけます。 temp/smali深く見てください。
  4. このクラスで、呼び出しの直後にonCreate(...)メソッドを見つけます(通常、この呼び出しは最初から始まります)
     invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V 

    onCreate(...)で次のコードを記述します。
     :debug sget v0, Lmy/activity/class/MyActivity;->debugFlag:I if-nez v0, :debug 

    気配りのある読者は、おそらく、このコードが前に説明した無限ループであることをすでに推測していました。 当然、 MyActivity代わりに実名アクティビティを使用する必要があり、 v0代わりに適切なローカルレジスタをこのコードで使用できます。 適切なレジスタがない場合は、それに応じて.registersまたは.registers編集して追加します。
  5. また、クラスにフィールドを追加します
     .field static debugFlag:I = 0x01 

    そうしないと、前の段落の無限ループのコードは機能しません。
  6. -dオプションを指定せずにtempディレクトリを.apkファイルに再構築します。
     java -jar apktool.jar b temp my.app.apk 

    もちろん、元のmy.app.apkはこの前のどこかにmy.app.apk必要があります。


これでmy.app.apkパッチが適用されmy.app.apk 。 アプリケーションが開始するアクティビティのクラスのonCreate(...)メソッドの開始時に、無限ループに入りました。 さて、このパッチを適用したmy.app.apkを取り、昨日の記事の段階的な指示に従ってください (「デバッグ」セクションを参照)。 この手順の9番目のステップでは、アプリケーションを起動した後、黒い画面が表示されることに注意してください。 これは正常です、そうであるはずです! これは、アプリケーションの起動直後に、パッチを適用したonCreate(...)メソッドが呼び出され、コントロールが無限ループに陥ったことを意味します。 しばらくしてAndroidが応答しないためにアプリケーションを閉じるように要求する場合、指示に従って厳密に拒否してさらに進んでください!

指示の12番目のステップで、NetBeansで、パッチを適用したonCreate(...)メソッドが配置されている.javaファイルを開きます。 NetBeansのデバッグパネルの一時停止ボタンを使用します。 次に、この開いている.javaファイルで、 onCreate(...)入力した無限ループコードの後の最初のステートメントにブレークポイントを配置します。 次に、NetBeansデバッガーで変数を表示および編集する機能を使用して、 debugFlagフィールドの値を0に変更し、NetBeansのデバッグパネルで[デバッグの続行]ボタンをクリックします。 管理は無限ループを終了し、すぐにブレークポイントに到達します。

これで、アプリケーションを最初から安全にデバッグできるようになりましたonCreate(...)最初のonCreate(...)メソッドの最初の呼び出しからです。

waitForDebuggerに関するいくつかの言葉()


読者は、このトピックで少しですが、おそらく、この記事で無限ループを使用するのと同じ目的でandroid.os.Debug.waitForDebugger()メソッドを使用することに関するトピックフォーラムを読んでください。 この同じ読者は、 onCreate(...)最初に1つの静的メソッドへの呼び出しを記述することはできますが、何らかの種類の庭を周期的に積み重ねていることに驚くでしょう。
 invoke-static {}, Landroid/os/Debug;->waitForDebugger()V 

メソッドはパラメータなしで呼び出されることに注意してください。つまり、適切なレジスタがない場合、ローカルレジスタを追加する必要はありません。 それは見えるだろう-美! 他に何が必要ですか?

理論的には、何も必要とせず、それを使用してください。 しかし実際には、すべてが少し複雑です。 実際、 android.os.Debug.waitForDebugger()したフォーカスは常に機能するとは限りません。 多くの場合(私のものを含む)、 android.os.Debug.waitForDebugger()呼び出した直後にandroid.os.Debug.waitForDebugger()アプリケーションは実際に「フリーズ」し、デバッガが参加するのを待ちます。 これはDDMSでも確認できます。アプリケーションの反対側に小さな「赤いバグ」アイコンが表示されます。 ただし、デバッガをアプリケーションに接続するとすぐに、制御はすぐにandroid.os.Debug.waitForDebugger()後の次の命令に渡され、アプリケーションは停止せずにさらに実行を開始します。 android.os.Debug.waitForDebugger()後にブレークポイントを置く時間はありません。 これに関する議論については、例えばこちらをご覧ください。

なぜandroid.os.Debug.waitForDebugger()がこのような人のために、そしてそのような人のためにandroid.os.Debug.waitForDebugger()のか-今のところはわかりません。 おそらくコメントで誰かがこれについて説明するでしょう。 また、コメントで記事について質問することができますし、質問するべきです。 私はできるだけ早く答えようとします、しかし、私が愚かであるならば-辛抱してください。 私は皆に答えようとします。

ハッピーデバッグ!

Source: https://habr.com/ru/post/J150862/


All Articles