2013年7月3日水曜日

【Xperia】perf_swevent関連のアドレスを特定する

メモです。
JBなXperiaのカーネルを想定しています。

前提は以下です。
・この記事を参考にいろいろやった結果トラブっても自力で復旧できること(つまり自己責任)
・作業PCはWindows 7 64bit

■必要物資
・ターゲットとなるXperia端末のftf
・7za等、zipを展開できるツール
・lzop.exe(lzoを展開するツール)
unpack-kernelsin
pullkernellzo
・arm-linux-androideabi-objdump
kallsymsprint

7zaは「7-zip」で検索、コマンドラインバージョンをダウンロードしてゲット。
lzop.exeは「lzop」で検索、Windows用をダウンロードしてゲット。
arm-linux-androideabi-objdump.exeは、android-ndk(sdkではない)の toolchains\arm-linux-androideabi-なんちゃら\prebuilt\windows\bin あたりに入っています。単体でも動くので、作業フォルダにコピーして使っても良いでしょう。
android-ndkはググってWindows用をダウンロードしてください。

■手順
1.ftfからkernel.sinを抽出
7za e なんちゃら.ftf kernel.sin

2.kernel.sinを展開
unpack-kernelsin.exe kernel.sin

「kernel.sin-header」「kernel.sin-kernel」「kernel.sin-ramdisk.cpio.gz」の3つが生成されます。
今回使用するのは「kernel.sin-kernel」です。

3.kernel.sin-kernelからlzo部分を抽出
pullkernellzo.exe kernel.sin-kernel

「kernelbin.lzo」が生成されます。

4.kernelbin.lzoを展開
lzop -d kernelbin.lzo

「kernelbin」が生成されます。

5.関数のアドレスをゲットする
欲しいアドレスは、

prepare_kernel_cred
commit_creds
remap_pfn_range
perf_swevent_enabled
ptmx_fops

の5つですが、このうち上から3つが関数のアドレス、残り2つは変数のアドレスです。
その2つの変数のアドレスを見付けるために、さらに以下の関数のアドレスも調べておきます。

sw_perf_event_destroy
pty_init
tty_default_fops

kallsymsprint.exe kernelbin > kallsymsprintdump.txt

上記を実行すると、何やらずらずらっと表示され、作業フォルダに「kallsymsprintdump.txt」というテキストファイルが生成されます。
kallsymsprintdump.txtの中を覗くと、

c00081c0 asm_do_IRQ
c00081c0 _stext
c00081c0 __exception_text_start
  ・
  ・
  ・

こんな感じで、アドレスと関数名の対応がひたすら並んでいます。
つまり、関数名でテキスト検索をかけると、関数の開始アドレスが分かるというわけです。
SO-01E(9.1.C.0.475)の例で言うと、各関数のアドレスは以下のような感じでした。

c009843c prepare_kernel_cred
c0097f60 commit_creds
c010e1f4 remap_pfn_range
c00e7b98 sw_perf_event_destroy
c0a1ecf8 pty_init
c02d267c tty_default_fops

とりあえず、求めたいアドレスのうち「prepare_kernel_cred」「commit_creds」「remap_pfn_range」はこれで判明しました。

6.kernelbinの逆アセンブル
perf_swevent_enabled を見付けるために sw_perf_event_destroy を、 ptmx_fops を見付けるために pty_init を逆アセンブルします。
それぞれの関数の開始アドレスから、0x1000くらいまでの範囲に絞って実行します。

arm-linux-androideabi-objdump -b binary -m arm --adjust-vma=0xc0008000 --start-address=0xc00e7b98 --stop-address=0xc00e8b98 -D kernelbin > kernel_asm1.txt

arm-linux-androideabi-objdump -b binary -m arm --adjust-vma=0xc0008000 --start-address=0xc0a1ecf8 --stop-address=0xc0a1fcf8 -D kernelbin > kernel_asm2.txt

7.アセンブリコードからアドレスを特定
まずテキストエディタでkernel_asm1.txt(sw_perf_event_destroyのコード)を開きます。

c00e7b98:    e92d4070     push    {r4, r5, r6, lr}
c00e7b9c:    e1a04000     mov    r4, r0
c00e7ba0:    e590319c     ldr    r3, [r0, #412]    ; 0x19c
c00e7ba4:    e5905080     ldr    r5, [r0, #128]    ; 0x80
c00e7ba8:    e3530000     cmp    r3, #0
c00e7bac:    0a000002     beq    0xc00e7bbc
c00e7bb0:    e59f0070     ldr    r0, [pc, #112]    ; 0xc00e7c28
c00e7bb4:    e30113f9     movw    r1, #5113    ; 0x13f9
c00e7bb8:    ebfe3788     bl    0xc00759e0
c00e7bbc:    e59f3068     ldr    r3, [pc, #104]    ; 0xc00e7c2c
c00e7bc0:    e0835105     add    r5, r3, r5, lsl #2
  ・
  ・
  ・

こんな感じの中身です。
左から、アドレス・機械語コード・ニーモニックですかね。
(ちなみに、関数は大体「push {うんたらかんたら}」で始まって、「pop {うんたらかんたら}」で終わります。ご参考までに。)
関数の結構最初の方(場合によっては後半)にある「add r5, r3, r5, lsl #2」の前の行、「ldr r3, [pc, #104] ; 0xc00e7c2c」に注目。
このr3の中身がperf_swevent_enabledのアドレスなのですが、「0xc00e7c2c」のアドレスに入ってるということで、そのアドレスの行がどうなっているか見てみます。

c00e7c2c:    c0cee0f4     strdgt    lr, [lr], #4

機械語部分が「c0cee0f4」となっています。これが perf_swevent_enabled のアドレスとなります。

次にkernel_asm2.txt(pty_initのコード)を開きます。
テキスト検索で、一番最初に出てくる「0xc02d267c」(前項で調べておいたtty_default_fopsのアドレス)のあたりを見ます。

  ・
  ・
  ・
c0a1ee64:    e2850008     add    r0, r5, #8
c0a1ee68:    ebe2ce03     bl    0xc02d267c
  ・
  ・
  ・

「bl 0xc02d267c」で、tty_default_fopsに飛ぶ感じなのですが、その前の行「add r0, r5, #8」に注目。
これは「r5に8を足して、r0に代入するよ」ということです。
ここに出てくるr0が ptmx_fops のアドレスなのですが、r5が分かれば8を足せば良いということになりますね。
ではここからさかのぼって、直近の「ldr r5, [xxx]」を探します。
すると以下のような部分が見付かりました。

c0a1ed04:    e59f51d4     ldr    r5, [pc, #468]    ; 0xc0a1eee0

「0xc0a1eee0」のアドレスに、r5の中身が入っていそうです。
ということで、c0a1eee0の行を調べてみると、

c0a1eee0:    c0d03200     sbcsgt    r3, r0, r0, lsl #4

となっていました。機械語部分は「c0d03200」です。つまり、「r5 = 0xc0d03200」ということになります。
先ほど述べたように、これに8を足せばいいので、 ptmx_fops のアドレスは「c0d03208」となります。

■結果
以上をもちまして、求めたいアドレスは以下のようになりました。

prepare_kernel_cred = 0xc009843c
commit_creds = 0xc0097f60
remap_pfn_range = 0xc010e1f4
perf_swevent_enabled = 0xc0cee0f4
ptmx_fops = 0xc0d03208

9 件のコメント:

  1. わかりやすいまとめ、ありがとうございます。

    返信削除
  2. Cubemodをvl用にしたいんですが
    具体的にどんなことをすればいいですか?
    実機とぐぐる能力しかありません

    返信削除
    返信
    1. コメント欄で一口に回答できるような内容ではありません。
      大雑把に申し上げると、本来のapk、odexとmodのそれとを比較して変更点をおさえ、移植先のコードに反映、またリソースIDのズレを修正、実機で動作確認しながら調整という流れになるかと思いますが、一からmodを作るより大変かと思われます。

      削除
    2. それから、次回からは記事の内容に関連したコメントをいただけるとありがたいです。

      削除
  3. ちゃんとカーネル取り出すろことから書いたんですねぇ。
    お疲れ様です。

    返信削除
    返信
    1. ftf作るまでなら結構情報揃ってると判断しまして、その次の段階から説明したら誰でも出来るかな、という感じで、この形に落ち着きました。

      削除
  4. お陰様で.401なSOL21でワンクリキットを作る事が出来ました。
    素人にも解りやすい解説ありがとうございました。
    はぐれさんも(^^)

    返信削除
    返信
    1. いやはや、素晴らしいです。
      殴り書き記事なので自分以外分かるのかこれ、と思ってましたが、ちゃんと伝わることが実証されました。
      突っ込み等ありましたら、今後も遠慮無くご指摘下さいませ。

      削除