AndroidのLVL(License Verification Library) とりあえず導入編

※ ここに書いてあることは全部間違っている可能性があります。頑張ってますが間違ってたらごめんなさい。Twitterかコメントなどで教えていただけるとうれしいです。

LVLってなんなの?

Googleが提供しているライセンス認証とかできる物体。
このライブラリを利用して、自分のプログラム内で利用者が購入者かどうか確認することができます。
有料アプリでしか使うことができません。

どういう時に使えなくできるの?

  • アプリケーションの利用者が購入している人ではないとき(正規ユーザではないとき)。
  • 最新のバージョンじゃないとき。(VersionCode と VersionName がMarketにある最新版と一致しないとだめ)

まぁ、○○のとき、××する、というのは自分で書くので、適当ですね。

どうやって検証するの?

  1. vending(Marketアプリ)のサービスに検証を依頼する
  2. 検証結果を受け取り、どういう動作にするか決定する

何が難しいの?

実装するだけなら、特に難しくない。
Googleの中の人とかが口をすっぱくして言っているのは、クラッカー対策をちゃんとしないといけないよ!ということ。

Lv.1

LVLを導入だけする。
カジュアルクラッカー(という用語があるらしい)対策にはこれでOK。
簡単に言うと、rootedな端末でadb pullして、別の端末にadb install Hoge.apk で不正にコピーしようとする人は倒せるレベル
apkをデコンパイルして、dexのバイトコード書き換えて検証コードをバイパスなりして、再署名までできるクラッカーは防げない(かもしれない)

Lv.2

モノホンのクラッカー対策。
オブファスケータ(コード難読化ツール=proguardとか)を使って、メソッド名をverifyLicense()からa()に変えたりして、シンボルから推測させにくくしたり、検証コードを重要なロジックの一部に紛れ込ませて除去する手間を膨大にしたり…バージョンアップを頻繁にしたり、バージョンアップのためにコードを組み替えて毎回クラックする手間が死ぬほどかかるようにしたり、とにかく諦めさせるための努力をしましょう!ということらしい。
概要を理解するための参考書籍としてはhttp://amzn.to/d9M5F3がよさそう(特に前半部分)。

Lv.3

この先もあるのかもしれないけど僕は知らない。

やってみよう!!

まず、LVLのライブラリをインストールできてないとだめです。SDKのManagerみたいなアレからダウンロードできます。


market_licensingディレクトリのlibraryを適当なトコにコピーして、以下のような感じでライブラリプロジェクトとして取り込んでください。


market_licensingディレクトリのsampleを適当なトコにコピーして、同様にEclipseに取り込みます。
取り込んだsampleプロジェクトに対して、先のlibraryプロジェクトをリンクさせます。プロジェクトのプロパティとかから。


公開鍵の設定とか、レスポンスコードの設定とか。


プロフィールの編集のリンク(左上のほうにあるやつ)をクリックした先のページ下部に、LVLに関するパネルがあります。


自分の公開鍵。これをMainActivity#BASE64_PUBLIC_KEYのとこにコピペしてください。

これで動くはず?
で、ライブラリプロジェクトをリンクすると、default.propertiesに以下みたいな行が追加されているはず

android.library.reference.1=./LVL/

僕はDropboxシンボリックリンクで置いてたので、以下のような行が追加された。

android.library.reference.1=../../Dropbox/work/BillingTest/LVL/

でも、なぜかこれだと駄目で、手でシンボリックリンク元に書き換えました…。そしたらうまくいきました。
謎です。わかる人教えてください…。

最小構成

githubに最小構成のコード置いといたんで、みてみてください。
上記手順は全て無視して、持ってきてEclipseにimportするだけで試せるかと思います。
どういうコード書けば動くのか、程度はわかると思います。言うまでもなく、この実装は安全じゃない(Lv.1)です。
動作としては、検証だけして、動作を変えたりはしないようになっています。(logcatで動作だけ確認できます。)
LicensingUtil.javaBASE64_PUBLIC_KEYというところだけは自分用に書き換えてください。

com.android.vending.* の*.aidlやら*.javaやらはサンプルからコピーしてきたもので、手を加えていません。(ResponseDataだけはclassのスコープをpackageからpublicに変更しましたが。)

その他、気をつけること。

@zaki50 先生曰く、ライセンス認証の結果を端末に保存する場合、データの難読化、暗号化、端末の固有化をきっちりしないと、ライセンスデータのキャッシュを改竄する方向で破られるかもわからんから注意せんとあかん。らしいです。
ぐぐる先生のサンプルコードのServerManagedPolicyとかは1回認証したらしばらく認証したことをキャッシュするために、なんか色々頑張ってるっぽい。

要望があれば…

どういう実装にすればそれなりに安全か(Lv.1だとどのくらい簡単に破れるか)を検証した記事を書こうかと思います。
多分あんま需要ないだろうし、すごい大変そうだしこれで終わりにしておきたい…。