2013年4月18日木曜日

【Xperia】uevent_helperのバッファのアドレスを特定する

uevent_helperって何?という方には無用の記事です。需要あるのかこれ。
ということで、ftfからuevent_helperの読み書きバッファのアドレスを探る手順を殴り書きにて紹介します。
あ、ちなみにJBは多分カーネルがgzipじゃなくてlzoになってるので、この記事はICS用です。

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

■必要物資
・ターゲットとなるXperia端末のftf
・7za等、zipやgzを展開できるツール
unpack-kernelsin
pullkernelgzip
・arm-linux-androideabi-objdump
kallsymsprint

7zaは「7-zip」で検索、コマンドラインバージョンをダウンロードしてゲット。
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」ですが、これは一般的に「zImage」とか「vmlinuz」とか呼ばれるものです。

3.kernel.sin-kernelからgzip部分を抽出
pullkernelgzip.exe kernel.sin-kernel

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

4.kernelbin.gzを展開
7za e kernelbin.gz

「kernelbin」が生成されます。

5.uevent_helper_store関数のアドレスをゲットする
kallsymsprint.exe kernelbin | findstr uevent_helper

上記を実行すると、以下のように何やらずらずらっと表示されます。

[+]MapViewOfFile
  mem=00490000 length=00c01da4 offset=bfb78000
[+]kallsyms_addresses=c081abd0
  count=0000ec91
[+]kallsyms_num_syms=0000ec91
[+]kallsyms_names=c0855e30
[+]kallsyms_markers=c0902bc0
[+]kallsyms_token_table=c0902f80
[+]kallsyms_token_index=c0903330
c01a1688 uevent_helper_show
c01a16d8 uevent_helper_store

これはSO-01E(9.0.G.1.108)での例です。
最後の2行がuevent_helper_なんちゃらの関数のアドレスになります。
showの方が読み込み、storeの方が書き込み関数ですかね。
読み書きバッファの特定にはuevent_helper_storeの方が分かりやすいので、上記の場合「c01a16d8」を覚えておきましょう。
記憶力の弱い人はメモるなりしてください。私はメモる類の方の人です。

6.kernelbinの逆アセンブル
arm-linux-androideabi-objdump -b binary -m arm --adjust-vma=0xc0008000 -D kernelbin > kernel_asm.txt

上記コマンドはkernelbin全体を逆アセンブルするものですが、これだと逆アセンブルに時間がかかる(Core i5マシンでも2~3分)のと、kernel_asm.txtが100MBを超えてエディタで扱いづらくなるので具合が悪いです。
ということで、手順5で得たアドレスから大体あたりをつけて、0x1000くらいの範囲だけ逆アセンブルしてみます。

arm-linux-androideabi-objdump -b binary -m arm --adjust-vma=0xc0008000 --start-address=0xc01a1000 --stop-address=0xc01a2000 -D kernelbin > kernel_asm_c01a1000.txt

uevent_helper_storeのアドレスがc01a16d8ですので、c01a1000~c01a2000に絞ってみました。

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

kernelbin: file format binary

Disassembly of section .data:

c01a1000 <.data+0x199000>:
c01a1000: eb17bcdd bl 0xc079037c
c01a1004: e1a00004 mov r0, r4
c01a1008: e8bd8070 pop {r4, r5, r6, pc}
c01a100c: e92d4070 push {r4, r5, r6, lr}
c01a1010: e1a04000 mov r4, r0
  ・
  ・
  ・

こんな感じの中身です。
左から、アドレス・機械語コード・ニーモニックですかね。
では早速、手順5で得たアドレスを元に、uevent_helper_storeのあたりを見てみます。

c01a16d8: e92d4070 push {r4, r5, r6, lr}
c01a16dc: e1a04003 mov r4, r3
c01a16e0: e2833001 add r3, r3, #1
c01a16e4: e3530c01 cmp r3, #256 ; 0x100
c01a16e8: 83e00001 mvnhi r0, #1
c01a16ec: 88bd8070 pophi {r4, r5, r6, pc}
c01a16f0: e59f5034 ldr r5, [pc, #52] ; 0xc01a172c
c01a16f4: e1a01002 mov r1, r2
c01a16f8: e1a02004 mov r2, r4
c01a16fc: e1a00005 mov r0, r5
c01a1700: eb064a96 bl 0xc0334160
c01a1704: e3540000 cmp r4, #0
c01a1708: e3a02000 mov r2, #0
c01a170c: e7c52004 strb r2, [r5, r4]
c01a1710: 0a000003 beq 0xc01a1724
c01a1714: e2443001 sub r3, r4, #1
c01a1718: e7d51003 ldrb r1, [r5, r3]
c01a171c: e351000a cmp r1, #10
c01a1720: 07c52003 strbeq r2, [r5, r3]
c01a1724: e1a00004 mov r0, r4
c01a1728: e8bd8070 pop {r4, r5, r6, pc}
c01a172c: c0b9e4a8 adcsgt lr, r9, r8, lsr #9

ここで、最初に出てくるldr命令を見てください。
右端に、「0xc01a172c」とあります。
では、アドレスc01a172cの行を見ましょう。
機械語部分が「c0b9e4a8」となっています。
詳しい説明は省きます(省き過ぎ?)が、この「c0b9e4a8」こそが、uevent_helperの読み書きバッファのアドレスになります。

9 件のコメント:

  1. sh-02eの掲示板スレから来たのですがちんぷんかんぷんで。

    返信削除
    返信
    1. 自分のwikiでも同じ事を解説してますが、ここで解説している事を理解するにはC言語の知識やマシン語の知識、そして大元のCのソース(kernelはC言語で書かれた物をビルドして作ります)とここでディスアセンブルして出来たソースの関係を理解しないとわからないと思います。

      削除
    2. まずこの記事がXperia前提なのでftf必須なのですが、他メーカーだとまずカーネルイメージを取得しないといけないんでしょうね。それを元に手順3ぐらいからになるのかな。
      このあたりは某掲示板該当スレの772さんが詳しそうですね。
      私はというと、自分の所有している機種しか分かりません…。

      削除
  2. 772さんが示されたのを理解したくて本屋に行って調べたけど分からなかった。
    カーネルイメージの作成を目標にやってみたいのだが
    はぐれもんさんが示されたC言語から勉強するのがいいのかな?

    返信削除
    返信
    1. カーネルのCのソース自体は、
      https://sh-dev.sharp.co.jp/android/modules/oss/index.php?/sh02e
      ここで公開されてるので一度見てみるといいと思います。

      削除
  3. はぐれもんさん、ありがとうございます。
    示されたサイトを見てみました。
    ダウンロードしてみたものの、たくさんの文字列でした。
    この文字列を理解できる環境を作りたいと思うのですが、
    C環境で検索してみてPleiadesというのを入れてみたのですが。
    見当違いならご指摘お願いします。

    返信削除
    返信
    1. ソースを見るだけならテキストエディタで十分です。
      ソースを読むにはまずはC言語というプログラミング言語そのものの勉強が必要になると思います。
      それを押さえた上でandroidは基本的にlinuxですからlinuxのカーネルに関する知識とその作成方法を学べばいいと思います。

      削除
    2. はぐれもんさん、ありがとうございます。
      学生時代にコンピューターの授業でCASLを勉強しました。
      言語の勉強には興味があるので頑張ってやって行きたいと思います。

      削除
  4. Hello キューブキューブ-san,

    Thanks for these useful programs. Here is a quick fix to support kernels with CONFIG_KERNEL_LZO=y http://mysticpaste.com/view/AgSqkZL7Gl?4

    返信削除