Android用のストックファームウェアの変更。 パート2

こんにちは、Habr!



最初の部分を書いた後、私は1週間を通して、私が約束したことについて書くか、いくつかの読者の要求に応じて、私の意見では、基本的なことについて説明と説明をするかどうかを考えました。

私はしたくないが、あなたの一部は動揺する必要があります。 自分で書くには、多くの時間と労力がかかります。ほとんどの場合、コピー&ペーストするのは好きではありません。記事からさまざまなリソースへのリンクを作成するのは悪いニュースです。



たとえば、この記事でAndroidのロード方法を説明することは適切ではありません。 BIOSでコンピューターのハードウェアを初期化し、システムのカーネルを介してロードするという原則を知っている場合、Androidはこの点で違いはありません。 唯一の違いはプロセッサアーキテクチャです。 ファイルシステム構造? 紳士、これは純粋なUNIXシステムであり、どこに、何を、どのように保存するかを書くのはばかげています! build.propの編集はシステムの調整です。 はい、これは変更ですが、これらのパラメーターのほとんどはサードパーティ製のアプリケーションで作成でき、たとえばSystem Tunerなど、より使いやすくなっています。



Androidシステムの原理を自分で理解するのに2、3か月かかりました。同じ時間をかけて、すべての基本的なことをカバーする記事を書きます。 だから、Dalvikコードを逆アセンブルし、電話で「使用」の便利さを作成する方法の特定の例についてよりよく書きましょう。



それでは、行きましょう! 今日は、ネイティブの方法で電話会話の自動録音の機能を実装した方法を説明します。



前文



一部の国では、技術的な手段による電話での会話の録音を許可していません。 たとえば、米国では、当事者の事前の同意なしに個人的な電話での会話を録音することは禁じられています。 ソビエト後のスペースでは、会話の他の参加者に警告することなく、あなたがパーティーの1つである会話を録音できます。 同じ中国では、記録は単に歓迎され、隣人への「ノック」はイデオロギーの原則です。 そして、これは会話の記録だけに適用されません。 インターネットの使用、SMSメッセージの送信、ソーシャルネットワークの使用、暗号化アルゴリズム、2枚のSIMカードを搭載した電話なども、各国の法律によって個別に規制されています。 今、あなたがビジネスオーナーであり、世界中のIT製品を輸出していると想像してください。 もちろん、複数ではなく1つのブランチでソフトウェアを「作成」しますが、構成は地域によって異なります。 CIS諸国にとっては、ヨーロッパにとっては、もう1つです。 電話のメーカーも到着します。 Androidオペレーティングシステムは、メインブランチのプログラマーの1グループのみによってファイナライズされており、地域ごとに、特定の構成ファイルが最終リリースのコンパイルに使用されています。 かつてベンダーの1つで働いていたので、私は自信を持ってこれを言います。



これを証明するために、ファームウェアを他の人のデバイスに移植する方法に関する優れたガイドがあります。



行こう!



Phone.apkの逆アセンブルされたJAVAコードを読んでいるときに、私は偶然に面白い旗につまずいた。 実際、私たちには興味深いが隠れた機能がたくさんあります。 ちょうど今日、私は私の電話に日本のオペレーターKDDIのためのパラメータがあることを発見しました。 プロバイダーからの特別に作成されたSMSメッセージは、地震や津波が発生した場合に、私の電話が心を打つ音を発し、数分間振動する原因になります。 しかし、私たちの旗に戻りましょう。

public static final boolean IS_INCALL_RECORDING_ENABLE = false;
      
      





面白いと思いました。 そのようなフラグがある場合、どこかで使用されます。 しかし、ここでは明確ではありません。 ただし、通話中に通話録音ボタンを表示することをお勧めします。 小物用ケース! FALSEをTRUEに変更し、パッチを適用したPhone.apkを上書きします。これは自宅の電話と呼ばれ、電話を拾い上げると「録音開始」ボタンが表示されました。 しかし、それがなかった前に!!!





もう一度、マテリアルを同化するためにそのようなことをする方法を説明します。



  1. ホテルフォルダーを作成し、そこにPhone.apkファイルを配置し、それにsmaliとbacksmali追加します
  2. コマンドjava -Xmx512m -jar baksmali.jar -a -d -o Phone -x Phone.apk



    — API Android. JB — 16

    — , .

    , Phone\com\android\phone\util\VoiceRecorderHelper.smali













    使用して、Dalvikコードの前に解析するファイルをjava -Xmx512m -jar baksmali.jar -a -d -o Phone -x Phone.apk



    — API Android. JB — 16

    — , .

    , Phone\com\android\phone\util\VoiceRecorderHelper.smali













    java -Xmx512m -jar baksmali.jar -a -d -o Phone -x Phone.apk



    — API Android. JB — 16

    — , .






    , Phone\com\android\phone\util\VoiceRecorderHelper.smali









     .field public static final IS_INCALL_RECORDING_ENABLE:Z = false
          
          



     .field public static final IS_INCALL_RECORDING_ENABLE:Z = true
          
          





    ファイルを戻す: java -Xmx512m -jar smali.jar -a 16 Phone -o classes.dex





    元のファイルの結果のclasses.dexをアーカイバーに置き換えます

    電話でPhone.apkを書き換える



    いくつかの通話の録音をテストしたところ、電話は標準の内蔵ボイスレコーダーで会話を録音すると同時に、非常に非常に高品質で録音することがわかりました。 ファイルの名前は自動的に生成され、通話者の番号または名前、および通話の日時が含まれます。 ファイル保存形式は、ネイティブアプリケーションでも設定できます。 これらの通話記録が必要なのはなぜですか?



    まあ、最初に、それは非常に便利です。 私の妻は、購入する製品のリストを呼び出して言ったが、録音する場所はないので、レコーダーが役立ちます。

    第二に、電話で私はクライアントや顧客と話さなければなりません。時には、必要で重要な情報が紛失したり、聞こえなかったりすることがあります。 または、重要な会話が行われたとしましょう。重要な会話を聞いて分析し、タイムリーな決定を下すか、ビジネスパートナーや他の人と行動を起こす必要があります。

    第三に、仕事と生活における非常に便利な証拠ベース。



    また、サードパーティのアプリケーションを使用しない理由を尋ねることができます。サードパーティのアプリケーションには、オープンで無料のアクセスがたくさんありますか?

    • サードパーティのテストされていないアプリケーションを信頼していません。 多くの場合、これらの各アプリケーションは携帯電話のメモリで絶えずハングアップし、プロセッサ時間を消費するため、バッテリーが不足します。
    • 録音品質は、常に約束されたものと一致するとは限りません。
    • 私はインターフェイスについて好き嫌いがあります。 アプリケーションの機能は豊富かもしれませんが、GUIが私にとって都合が悪い場合は、使用しません。 残念なことに、多くの国内の発展はこれに欠けています。


    それはどのように機能しますか?



    すべてのAndroid開発者は、システムがさまざまな標準ブロードキャストメッセージでいっぱいであることを知っています。 システムで何が起こっても、そのようなメッセージの「その」受信者を実装していれば、どのアプリケーションでも受信できます。 ブロードキャストメッセージを作成できます。このメッセージの受信者のみが、アプリケーション自体または作成したアプリケーション全体となり、何らかの方法でこのメッセージを処理します。 GoDialerとGoSMSProで実際にこれを見ました。



    サードパーティの通話録音アプリケーションも同じように機能します。 通話が確立されたというメッセージが渡されるとすぐに、録音が開始されます。 呼び出しが停止すると、記録が停止し、バッファがファイルに書き込まれます。



    私の仕事は、このメッセージが形成または処理される場所を見つけ、不必要なジェスチャーをせずに通話の録音を強制的に開始することでした。 結局のところ、電源を入れるのを忘れたり、単に時間がないことがよくあります。 大量のファームウェアコードで適切な場所を一般的に見つける方法は、次の記事のトピックですが、今は「私たちの場所」に進みましょう。



    ハンドラー、または2つは、ファイル\ com \ android \ phone \ CallNotifier.javaになりました



    JavaのDalvikからの逆コンパイルされたコード(ここではコードの一部のみを示します)は、次のようになりました。



      private void onCallConnected(AsyncResult paramAsyncResult) { Connection localConnection = (Connection)paramAsyncResult.result; String str = ((IfConnection)localConnection).getDialString(); VLog.d("onCallConnected() dialed number:" + str); removeMessages(120000); removeMessages(120001); this.mIsEccNeedRetry = false; this.mEccIsSwitchingForRetrying = false; //    }
          
          



    そして

      private void onDisconnect(AsyncResult paramAsyncResult) { Phone.State localState = this.mCM.getState(); if (CallNotifier.VDBG) super.log("onDisconnect()... CallManager state: " + this.mCM.getState()); VLog.d(this, "onDisconnect()"); removeMessages(120000); removeMessages(120001); //    }
          
          





    前の記事に比べて、タスクは複雑です。 前回単純な関数を修正する必要があった場合、ここでは修正することができません。書き換えるためのソースコードがないためです。 ここで、コードを埋め込む必要があります。



    Dalvikとは何ですか?



    これはここここに簡単に書かています 。 さらに簡単な言語で言えば、仮想マシンのバイトコードは、レジスタ(変数を処理するために割り当てられたメモリ領域)と多くの命令と演算子に基づいています。 操作の意味と原理は非常に簡単です。レジスタに値を書き込んでから操作を実行すると、操作の結果がアクションを適用した場所に返されます。 すべての演算子と手順の詳細については、Dalvik VMのバイトコードを参照してください。



    コードを埋め込む



    何かを入力するには、そこに何を入力するかを知る必要があります。 [記録の開始]ボタンハンドラーからコードをなめることができます。

    Androidの初心者プログラマーでさえ、ハンドラーの保存場所を見つけることは難しくありません。 その後、今後の記事で何をどのように探すかに戻ります。 最初の記事の本質は、原則を説明しています。



    ボタンが押されると、次のコードがトリガーされます。

      VoiceRecorderHelper localVoiceRecorderHelper = VoiceRecorderHelper.getInstance(); if (!localVoiceRecorderHelper.isRecording()) { localVoiceRecorderHelper.start(); }
          
          



    つまり、すべての呼び出しの記録を自動化するには、このコードをonCallConnectedハンドラーに追加する必要があります。



    このエントリのDalvikコードは次のようになります



      invoke-static {}, Lcom/android/phone/util/VoiceRecorderHelper;->getInstance()Lcom/android/phone/util/VoiceRecorderHelper; move-result-object v1 invoke-virtual/range {v1 .. v1}, Lcom/android/phone/util/VoiceRecorderHelper;->isRecording()Z move-result v2 const/4 v3, 0x0 if-ne v3, v2, :cond_a9 invoke-virtual/range {v1 .. v1}, Lcom/android/phone/util/VoiceRecorderHelper;->start()Z :cond_a9
          
          





    コードを1行ずつ解析してみましょう。

    1. invoke-staticはVoiceRecorderHelperクラスのインスタンスを呼び出します
    2. インスタンスを保存してv1を登録する
    3. このクラスのisRecordingというメソッドを呼び出し、trueまたはfalseを返します
    4. 結果はレジスタv2に書き込まれます
    5. レジスタv3に値0を書き込みます
    6. 2つのレジスタv2とv3の比較を行っています。 ロジック:v2!= V3。 isRecordingがTRUEを返す場合、v2の値は1になり、FALSEの場合はその逆になります。 条件が機能しない場合は、cond_a9マーカーにジャンプします。 そうでない場合は、
    7. レジスタv1に格納されているクラスインスタンスのstartメソッドが呼び出されます
    8. 会話が録音され始めました。




    onCallConnectedに戻ります。 彼のdalvikコードは次のとおりです。

     .method private onCallConnected(Landroid/os/AsyncResult;)V .registers 8 .parameter "r" .prologue .line 2302 iget-object v0, p1, Landroid/os/AsyncResult;->result:Ljava/lang/Object; check-cast v0, Lcom/android/internal/telephony/Connection; .local v0, c:Lcom/android/internal/telephony/Connection; move-object v2, v0
          
          





    このコードも分析して、何が何であるかを明確にします



    • .registers 8



      この機能に必要かつ使用されるメモリレジスタの数
    • parameter "r"



      は、ソースコードで使用されたパラメーターの名前です。 それが私たちの興味を引くことはめったにありません。
    • prologue



      -関数アルゴリズムの始まり
    • .line 2302



      ソースコードの行番号。 これはデバッグ専用です。
    • iget-object v0, p1, Landroid/os/AsyncResult;->result:Ljava/lang/Object;



      次の行は、 (Connection)paramAsyncResult.result;



      対応してい(Connection)paramAsyncResult.result;



    • check-cast v0, Lcom/android/internal/telephony/Connection;



      Connection



      対応
    • .local v0, c:Lcom/android/internal/telephony/Connection;



      localConnection



      一致
    • move-object v2, v0



      ローカル変数v0をレジスタv2に複製
    • など


    説明を参照してJavaコードと比較すれば、コードを解析することはそれほど難しくありません。



    ボタンクリックハンドラーからコードをコピーし、コールハンドラーの先頭に貼り付けるだけで完了です。 そこにはありませんでした。 時々それは動作しますが、ほとんどは動作しません。 実際、データを書き込むレジスタはプログラムのさらなるコードで使用でき、最初に間違ったレジスタを使用して何かを書き込むと、プログラムの実行中にエラーが発生し、アルゴリズム全体が故障する可能性があります。 この場合、最初に関数を入力し、最初に初期化されないレジスタを使用できるという点で単純です。これらのレジスタは将来上書きされるためです。 しかし、多くの場合、コードはプログラムの途中のどこかに埋め込む必要があり、レジスタに注意する必要があります。 これは将来の記事にもあります。



    レジスタ変更


    埋め込み可能なコードの最初の2行には次のものがあります。



      invoke-static {}, Lcom/android/phone/util/VoiceRecorderHelper;->getInstance()Lcom/android/phone/util/VoiceRecorderHelper; move-result-object v1
          
          



    適切なレジスタ番号を探す最も簡単な方法は、必要なレジスタ番号に書き込まれているデータの種類をメソッド自体で調べることです。 コードを見ると、v2とv 3でmove-result-objectが書き込まれていることがわかります。

    したがって、埋め込み可能なコードのv1はすべてv2またはv3に置き換えられます



    埋め込み可能なコードのレジスタ番号を置き換えるためのすべての操作を行った後、次の図を取得します。



      invoke-static {}, Lcom/android/phone/util/VoiceRecorderHelper;->getInstance()Lcom/android/phone/util/VoiceRecorderHelper; move-result-object v3 invoke-virtual/range {v3 .. v3}, Lcom/android/phone/util/VoiceRecorderHelper;->isRecording()Z move-result v4 const/4 v5, 0x0 if-ne v5, v4, :cond_27 invoke-virtual/range {v3 .. v3}, Lcom/android/phone/util/VoiceRecorderHelper;->start()Z :cond_27
          
          



    マーカーcond_a9をcond_27に変更したことは注目に値します。 実際、cond_a9マーカーは、コードを埋め込んだファイル内に既に存在しており、2回目はそのようなマーカーを使用できません。 マーカー番号は16進コードであり、任意の、最も重要なことには一意にすることができます。



    次に、ソースファイルで、行.line 2302



    を埋め込み可能コードに置き換えて、

     .method private onCallConnected(Landroid/os/AsyncResult;)V .registers 8 .parameter "r" .prologue invoke-static {}, Lcom/android/phone/util/VoiceRecorderHelper;->getInstance()Lcom/android/phone/util/VoiceRecorderHelper; move-result-object v3 invoke-virtual/range {v3 .. v3}, Lcom/android/phone/util/VoiceRecorderHelper;->isRecording()Z move-result v4 const/4 v5, 0x0 if-ne v5, v4, :cond_27 invoke-virtual/range {v3 .. v3}, Lcom/android/phone/util/VoiceRecorderHelper;->start()Z :cond_27 .line 2302 iget-object v0, p1, Landroid/os/AsyncResult;->result:Ljava/lang/Object; check-cast v0, Lcom/android/internal/telephony/Connection; .local v0, c:Lcom/android/internal/telephony/Connection; move-object v2, v0
          
          







    コマンドjava -Xmx512m -jar smali.jar -a 16 Phone -o classes.dex



    を使用してコードを収集し、 java -Xmx512m -jar smali.jar -a 16 Phone -o classes.dex



    で置き換えてテストします。



    Javaでは、私たちの仕事は次のようになり始めました。

      private void onCallConnected(AsyncResult paramAsyncResult) { VoiceRecorderHelper localVoiceRecorderHelper = VoiceRecorderHelper.getInstance(); if (!localVoiceRecorderHelper.isRecording()) { localVoiceRecorderHelper.start(); } Connection localConnection = (Connection)paramAsyncResult.result; String str = ((IfConnection)localConnection).getDialString(); VLog.d("onCallConnected() dialed number:" + str); removeMessages(120000); removeMessages(120001);
          
          







    すべてが正常で、すべてが機能しますが、唯一の問題は、会話が完了した後、通話録音が無期限に継続することです。

    これを行うには、関数(メソッド)onDisconnectの先頭に同様のコードを登録する必要があります。ただし、リバースロジックのみです。



      VoiceRecorderHelper localVoiceRecorderHelper = VoiceRecorderHelper.getInstance(); if (localVoiceRecorderHelper.isRecording()) { localVoiceRecorderHelper.stop(); }
          
          







    録音の開始と同様に、レジスタ番号を置き換える小さな手順を作成します



     .method private onDisconnect(Landroid/os/AsyncResult;)V .registers 41 .parameter "r" .prologue invoke-static {}, Lcom/android/phone/util/VoiceRecorderHelper;->getInstance()Lcom/android/phone/util/VoiceRecorderHelper; move-result-object v34 invoke-virtual/range {v34 .. v34}, Lcom/android/phone/util/VoiceRecorderHelper;->isRecording()Z move-result v4 if-eqz v4, :cond_33 invoke-virtual/range {v34 .. v34}, Lcom/android/phone/util/VoiceRecorderHelper;->stop()Z .line 2487 :cond_33
          
          





    変更を収集し、電話と出来上がりで置き換えます-すべてが正常に機能します。



    エピローグ



    この資料は、前の記事と比較して、数倍複雑で混乱していることがわかったと思います。 いくつかのレジスタ、演算子、修飾子...それはナンセンスのようです。 Dalvikを自分で初めて見たとき、私はぞっとし、ページを閉じて、半年も開きませんでした。 壁に押し付けられたとき、2週間以内に、何が起こっていたのか、それをどのように実行するのかをすぐに見つけました。 喜ばしいことに、私はレンガを受け取ったことはありません。



    広告ではなく、多くの情報を得ることができる2つのリソースをお伝えします。



    ロシア語英語

    両方のリソースで、同じニックネームで出席します。



    それまでの間、次の記事まで、一週間以内にお願いします。



All Articles