2011/11/30

「超光懐中電灯」を解析してみた(前編)

追記 2012/10/01

「超光懐中電灯」で調べて本Blogエントリにたどり着いた方へ

本エントリは、2011年11月時点のアプリケーションを解析した結果です。その後アプリケーションは幾度かのバージョンアップを経てApperHandという広告モジュールを導入した結果、いくつかのウィルス対策ベンダからPUP(利用することが望ましくないプログラム)としてスキャンソフトで検知されるようになっています。

本アプリについては、本Blogエントリ「改めて警告します。「超光懐中電灯無料アプリ」は利用することが望ましくないアプリです」を参照ください。



内容が前後してしまいましたが、「超光懐中電灯」の解析に至る経緯から後編に繋がるところまでをまとめます。
本記事の内容は既に下記サイトで公開されています。

ここでは上記の経緯を私の視点でまとめます。

あらかじめ申しておきますが、「広告モジュール=悪質」ではないと私は考えていますし、セキュリティを理由に広告自体をネガキャンするのは間違いだと考えます。
ユーザの利便性から見て広告が邪魔だとか、アプリの動作を阻害するといった話は別問題で、それはそれで思う人が訴えるべきです。

また「広告というのはそういうものだ」とか「それくらい(パーミッションで)判別できるだろ」という意見を散見しますが、これには同意できません。実際「超光懐中電灯」は、インストール数にして1~5千万DLをカウントしています。マーケットの評価表示は信頼性が低いとはいえ平均評価は4.8です。

「超光懐中電灯」を使用している多くの人が、端末識別情報や契約者識別情報、位置情報を広告ベンダに収集されている認識がある(そして高評価をつけている)とは思えません。この事実を無視して判らない/知らない人が悪いとは言えないと思います。

ユーザがそのアプリが何であるかを認識した上で、使うか否かを判断できなければなりません。そのためにはコンテンツ提供者側にもそれを可能とする施策が求められると思います。

事の始まり

仕事の合間に見た@typex20さんのあるTweetに目が留まりました。

単なる懐中電灯アプリなのに、なぜ、端末のステータスと ID の読み取り、位置情報のpermissionを必要とするんだろう。”迷惑な広告なし”とも言っているのに解せない。。 / “超光懐中電灯無料アプリ - Android マーケット” http://htn.to/JNKSHE
@typex20氏のTweet(11/28)

”迷惑な広告なし”が目に留まり、これらのパーミッションがどのように使われているかちょっと調べてみようと思いました。
早速アプリを入手し、apkをデコードしてAndroidManifest.xmlを見てみました。

AndroidManifest

広告に用いられるActivityが多数記載されています。

とりあえず結果を@typex20氏に伝え、さらに調べるためディレクトリ構成を眺めてみました。
まず疑うところとして広告モジュールの有無です。
AndroidManifestに記載されているものの実際にモジュールが含まれているかどうかを確認した方が良いだろうと言う事で、comディレクトリの配下をlsしてみると。

#ls -l ./com
total 4
drwxr-xr-x+ 1 user None 0 Nov 28 18:10 adserver
drwxr-xr-x+ 1 user None 0 Nov 28 18:11 adwhirl
drwxr-xr-x+ 1 user None 0 Nov 28 18:11 amobee
drwxr-xr-x+ 1 user None 0 Nov 28 18:11 flurry
drwxr-xr-x+ 1 user None 0 Nov 28 18:11 google
drwxr-xr-x+ 1 user None 0 Nov 28 18:11 inmobi
drwxr-xr-x+ 1 user None 0 Nov 28 18:11 jumptap
drwxr-xr-x+ 1 user None 0 Nov 28 18:11 mdotm
drwxr-xr-x+ 1 user None 0 Nov 28 18:10 millennialmedia
drwxr-xr-x+ 1 user None 0 Nov 28 18:11 mobclix
drwxr-xr-x+ 1 user None 0 Nov 28 18:11 zestadz
#

これだけ多くのモジュールが入っているパッケージは初めて見ました。(正直衝撃を受けました。)

パーミッションを再確認する

さらにこれらの広告モジュールがアプリの機能に不要なパーミッションを要求しているのかどうか確認します。
このアプリの要求するパーミッションは以下の通りです。

ハードウェアの制御
画像と動画の撮影
現在地
おおよその位置情報(ネットワーク基地局)
精細な位置情報(GPS)
ネットワーク通信
完全なインターネット アクセス
電話/通話
端末のステータスと ID の読み取り
ストレージ
USB ストレージのコンテンツの変更/削除、SD カードのコンテンツの変更/削除
システム ツール
端末のスリープの無効化
ハードウェアの制御
ライトのコントロール
ネットワーク通信
ネットワーク状態の表示
デフォルト
ステータス バーの無効化や変更

「画像と動画の撮影」や「ライトのコントロール」、「端末のスリープの無効化」、「ステータス バーの無効化や変更」は、このアプリの機能提供に必要なものと考えられます。また、確認は必要ですが「USB ストレージのコンテンツの変更/削除、SD カードのコンテンツの変更/削除」も実装の良し悪しはともかく設定の保存などに用いられている可能性があります。(良心的に考えれば、ですが)
また、「全なインターネット アクセス」、「ネットワーク状態の表示」は、広告モジュールが入っていれば必要になると考えられます。

しかし、「端末のステータスと ID の読み取り」や「おおよその位置情報(ネットワーク基地局)」、「精細な位置情報(GPS)」は適切な利用方法が浮かびません。「端末のステータスと ID の読み取り」に関しては広告モジュールがIMEIを取得している前例があるため、必然的に疑われます。

dexから洗い出してみる

そこで、ディスアセンブルしたソースからTelephonyManagerとLocationManagerを利用している箇所をgrepして見ました。
(かなり長いので該当部分以外は省略しました。私のgrepの仕方も悪かった…)

「TelephonyManager」でgrep

#find ./ -type f -print | xargs grep "TelephonyManager" /dev/null
(略)
./com/adserver/adview/AdserverRequest.smali: invoke-virtual {v3}, Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;
(略)
./com/adserver/adview/AdServerView.smali: invoke-virtual {v15}, Landroid/telephony/TelephonyManager;->getNetworkOperator()Ljava/lang/String;
(略)
./com/amobee/onlineHapi/AmobeeAdView.smali: invoke-virtual {v2}, Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;
(略)
./com/jumptap/adtag/utils/JtAdManager.smali: invoke-virtual {v1}, Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;
(略)
./com/jumptap/adtag/utils/JtAdManager.smali: invoke-virtual {v2}, Landroid/telephony/TelephonyManager;->getNetworkType()I
(略)
./com/jumptap/adtag/utils/JtAdManager.smali: invoke-virtual {v1}, Landroid/telephony/TelephonyManager;->getNetworkOperatorName()Ljava/lang/String;
(略)
./com/jumptap/adtag/utils/JtAdManager.smali: invoke-virtual {v2}, Landroid/telephony/TelephonyManager;->getPhoneType()I
(略)
./com/jumptap/adtag/utils/JtAdManager.smali: invoke-virtual {v1}, Landroid/telephony/TelephonyManager;->getSubscriberId()Ljava/lang/String;
(略)
./com/mdotm/android/ads/MdotMManager.smali: invoke-virtual {v0}, Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;
(略)
./com/millennialmedia/android/MMAdViewSDK.smali: invoke-virtual {v2}, Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;
(略)
./com/mobclix/android/sdk/Mobclix.smali: invoke-virtual {v13}, Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;
./com/mobclix/android/sdk/Mobclix.smali: invoke-virtual {v13}, Landroid/telephony/TelephonyManager;->getNetworkOperator()Ljava/lang/String;
(略)
./com/mobclix/android/sdk/Mobclix.smali: invoke-virtual {v5}, Landroid/telephony/TelephonyManager;->getNetworkType()I
(略)
#

「LocationManager」でgrep

#find ./ -type f -print | xargs grep "LocationManager" /dev/null
(略)
./com/adserver/adview/AdServerViewCore.smali: invoke-virtual/range {v0 .. v6}, Landroid/location/LocationManager;->requestLocationUpdates(Ljava/lang/String;JFLandroid/location/LocationListener;Landroid/os/Looper;)V
(略)
./com/adserver/adview/ormma/listeners/LocListener.smali: invoke-virtual/range {v0 .. v5}, Landroid/location/LocationManager;->requestLocationUpdates(Ljava/lang/String;JFLandroid/location/LocationListener;)V
(略)
./com/adserver/adview/ormma/OrmmaLocationController.smali: invoke-virtual {v4, v3}, Landroid/location/LocationManager;->getLastKnownLocation(Ljava/lang/String;)Landroid/location/Location;
(略)
./com/adwhirl/AdWhirlManager.smali: invoke-virtual {v1, v3}, Landroid/location/LocationManager;->getLastKnownLocation(Ljava/lang/String;)Landroid/location/Location;
(略)
./com/flurry/android/FlurryAgent.smali: invoke-virtual {v0, v1}, Landroid/location/LocationManager;->getLastKnownLocation(Ljava/lang/String;)Landroid/location/Location;
(略)
./com/inmobi/androidsdk/impl/UserInfo.smali: invoke-virtual {v2, v4}, Landroid/location/LocationManager;->getLastKnownLocation(Ljava/lang/String;)Landroid/location/Location;
(略)
./com/jumptap/adtag/utils/JtLocation.smali: invoke-virtual {v0, v1}, Landroid/location/LocationManager;->getLastKnownLocation(Ljava/lang/String;)Landroid/location/Location;
(略)
./com/mobclix/android/sdk/MobclixJavascriptInterface.smali: invoke-virtual {v2, v3}, Landroid/location/LocationManager;->getLastKnownLocation(Ljava/lang/String;)Landroid/location/Location;
(略)
./com/mobclix/android/sdk/MobclixJavascriptInterface.smali: invoke-virtual {v2, v3}, Landroid/location/LocationManager;->getLastKnownLocation(Ljava/lang/String;)Landroid/location/Location;
(略)
./com/mobclix/android/sdk/MobclixLocation$GetLastLocation.smali: invoke-virtual {v2, v3}, Landroid/location/LocationManager;->getLastKnownLocation(Ljava/lang/String;)Landroid/location/Location;
(略)
./com/mobclix/android/sdk/MobclixLocation$GetLastLocation.smali: invoke-virtual {v2, v3}, Landroid/location/LocationManager;->getLastKnownLocation(Ljava/lang/String;)Landroid/location/Location;
(略)
#

上記の結果をまとめると以下の通りとなります。

Permission

多くのアプリがDeviceIDとLocationを取得している事がわかると思います。
さらにこの中で突出しているのがJumpTapというモジュールです。不正クリックの防止でDeviceIDを使うとかそういうレベルではなく、ユーザの属性情報を取得する目的があるように思われます。

結論

  • 「超光懐中電灯」は、多数の広告モジュールを組み込んでいました。(おかげで広告モジュールの実態をある程度把握することができました)
  • 今回調べた限りでは、広告モジュールの多くがDeviceIDと位置情報の取得を行っていることがわかりました
  • また、一部の広告モジュールは詳細な端末情報を収集していることがわかりました

初日の解析はここで終了です。
この段階では、広告モジュールがどのような情報を端末内で収集しているかが判りました。
その後、この収集した情報がが広告ベンダに送信されているかを調査することになります。これについては前述の「「超光懐中電灯」を解析してみた(後編)」を参照ください。

0 件のコメント:

コメントを投稿