- 投稿日:2020-12-08T23:28:26+09:00
【Android】root判定によるチート対策
PONOS Advent Calendar 2020 9日目の記事です。
昨日は@nissy_gpさんのNode.js+Sequelizeで楽観的ロックを使って動作を確認するでした。
はじめに
![]()
前回の記事で「Android開発者向けオプションを使ったチート対策」を紹介しました。
今回は、「root判定によるチート対策」を紹介します。この記事の対象者
![]()
・アプリ開発者
・Android開発者root化された端末の判定
メモリハックによる値書き換えなどのチート行為は
root化された端末を使用して行われるケースが多いです。今回はアプリ側から
su
コマンドを実行して
IOException
の有無で判定してみましょう。
・IOException
発生の場合はroot権限なし ー> 通常端末
・IOException
発生しない場合はroot権限あり ー> root端末java.lang.Runtimeクラスの
exec(String command)メソッドを使用します。boolean isRoot = false; try { Process process = Runtime.getRuntime().exec("su"); process.destroy(); isRoot = true; Log.d(TAG, "Root!!"); } catch (IOException e) { Log.d(TAG, "NotRoot!!"); } catch (Exception e){ e.printStackTrace(); } if(isRoot){ //root権限ありの時の処理 //例:情報をサーバーに送信し、root化解除を促すポップアップ表示 }メリット
アプリのセキュリティーレベルを上げることができる。
実装コストが軽いデメリット
マニアックな海外製端末で初期出荷状態から
root権限が付与されているケースなどがあり、健全ユーザーがチート扱いされてしまう場合もある。
※経験則になってしまいますが、このパターンはかなりレアケースでした。注意点
リバースエンジニアリングによるコード改竄で今回のコードを無効化されてしまう恐れもあります。
root対策と同時にリパッケージされた不正アプリ対策を実装するのがお勧めです。
不正アプリ対策
・メモリシャッフル
・難読化
・SafetyNet導入
などがあり、SafetyNet の Attestation APIを使用してリパッケージされていないか判定することができます。SafetyNetの紹介
SafetyNetでできること
SafetyNet Attestation API:
正規の Android デバイスで、正規のアプリかどうか判定できるSafetyNet Safe Browsing API:
URL が Google によって既知の脅威としてマークされているかどうかを判定できるSafetyNet reCAPTCHA API:
悪意のあるトラフィックを検知することができるSafetyNet Verify Apps API:
有害なアプリから端末を保護することができるSafetyNet Attestation API
実装方法は公式に記載されているので省略しますが
以下の手順で正規アプリかどうか判定することができます。
1.SafetyNet 構成証明をリクエスト2.SafetyNet 構成認証レスポンスを各種検証
3.apkPackageName: 呼び出し元のアプリのパッケージ名のチェック
4.APK証明書のSHA-256ハッシュ:署名に使用したAPK証明書を検証
5.APKのSHA-256ハッシュ:APKがリリースしたものから改ざんされていないことを確認するために、APKのSHA-256ハッシュが同一か検証
6.BasicIntegrityがtrueであることを確認
※検証処理はサーバー側で行うこと
まとめ
今回紹介したroot判定は自前で実装する手法でしたが
SafetyNet Attestation API
を使用してでも判定することができます。
構成認証レスポンスのBasicIntegrityがfalseの場合はroot端末です他にもSafetyNetを使用したチート対策があるので
公式ドキュメントを読んでおくことをお勧めします。明日は@blockの記事です。
お楽しみに!!
- 投稿日:2020-12-08T22:10:44+09:00
DroidScriptを(windows10)NoxPlayerでインストールして、自作javascriptを実行してみた。
大丈夫ですか?
(参考)NoxPlayerに危険性はある?利用時に考えられる3つの可能性
https://mayonez.jp/topic/1088522環境:
windows10
NoxPlayer バージョン7.0.0.7 2020/11/27
DroidScript バージョン1.80(Android 要件4.1 以上) 更新日2020年1月20日自作javascript:
DroidScriptで、3行3列のボタンのレイアウトをループや配列を使って、短くなりますか?
https://ja.stackoverflow.com/questions/72486/droidscript%e3%81%a7-3%e8%a1%8c3%e5%88%97%e3%81%ae%e3%83%9c%e3%82%bf%e3%83%b3%e3%81%ae%e3%83%ac%e3%82%a4%e3%82%a2%e3%82%a6%e3%83%88%e3%82%92%e3%83%ab%e3%83%bc%e3%83%97%e3%82%84%e9%85%8d%e5%88%97%e3%82%92%e4%bd%bf%e3%81%a3%e3%81%a6-%e7%9f%ad%e3%81%8f%e3%81%aa%e3%82%8a%e3%81%be%e3%81%99%e3%81%8b?noredirect=1&lq=1
- 投稿日:2020-12-08T21:58:02+09:00
【Android】DaggerなんもわからんかったけどHiltをやりました
この記事はand factory Advent Calendar 2020の9日目の記事です。
昨日は@hagmonさんのエンジニアリングマネージャーについて考えるでした。
メンバーの自走のサポートを中心に考えるマネジメントで、上位者、下位者ともに能力を発揮できる良い組織になりそうですね??(自社自賛)はじめに
お世話になっております。
1年くらい前にDaggerを導入しようとして「なんもわからん・・・」となり、
一時Koinに甘えたりしていた者です。近頃、Dagger-Hilt、並びに同ライブラリのAndroidStudio上でのサポートなどが新たに登場し、情勢の変化が起きております。
これらの事情を踏まえ、弊開発環境でも今一度Google社製DIライブラリとの親善に向き合うため、アドベントカレンダーの舞台を機会として筆を執っております。という感じでこういう記事です。↓
- はなすこと
- 「Hiltのチュートリアルをやってみたよ」
- はなさないこと
- 「DIってなんやねん」系のアレ
- Koinについて
- 別ライブラリからの移行とかの話
(Koinからの移行は供給が少なそうな気がするので、そのうちやったら別で書いてみたい)「わからんかった」人間の記事なので、ツッコミどころがあればなんなりとマサカリを頂けると助かります。本当に。
導入
ほとんど思考停止でやっておく部分です。
project_root/build.gradle// きっと他にも書いてある ext.hilt_version = '2.28-alpha' dependencies { // きっと他にも書いてある classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" }バージョンは良い感じのを選んでくれよな!?(まだalphaしかないんすねって思いました)
project_root/module/build.gradle// きっと他にも書いてある apply plugin: 'kotlin-kapt' apply plugin: 'dagger.hilt.android.plugin' // きっと android {...} とかが書いてある dependencies { // きっと他にも書いてある implementation "com.google.dagger:hilt-android:$hilt_version" kapt "com.google.dagger:hilt-android-compiler:$hilt_version" }ここまで外部依存関係系。
MyApplication.kt@HiltAndroidApp class MyApplication : Application() { // きっと他にも書いてある }で、Applicationクラスへのアノテーションで、アプリ全体へのコンテナ(Component)を生成してくれる様子。
基本的な使い方
「Fragmentで使うクラス、生成の処理書くんメンドいなあ」
「Hiltくん経由で生成して注入できるで」MainActivity.kt@AndroidEntryPoint class LogsFragment : Fragment() { @Inject lateinit var dateFormatter: DateFormatter // 他の記述 }Androidのクラス(ちゃんとした対象一覧はここ)に
@AndroidEntryPoint
アノテーションを付けると、そのクラスのライフサイクルに従うDIコンテナを生成してくれます。(このあたり、Daggerからかなり楽になった所っぽいです)
その上で、@Inject
でフィールドインジェクションが可能です。
注意として、@Inject
の対象はprivate
にすることが出来ません。「そんで、注入したいクラスの生成方法もちゃんと書いといてな」
DateFormatter.ktclass DateFormatter @Inject constructor() { // 他の記述 }コンストラクタに
@Inject
をつけることでHiltがクラスの生成方法を理解します。
コンストラクタにパラメータがある場合は、パラメータのクラスのコンストラクタを...と続けて依存グラフを生成します。(このあたりはDI自体の概念として基本)とりあえずこれで一番シンプルな利用ができます。
インスタンスの共有
「このInjectいうやつ、毎回新しいインスタンスが生成されるん?」
「せやで」
「シングルトンとかで扱いたいんやけど」DateFormatter.kt@Singleton class DateFormatter @Inject constructor() { // 他の記述 }いわゆるスコープの件です。スコープも、生成対象にアノテーションを付けて表現します。
他にも@ActivityScoped
や@FragmentScoped
などがあります。一覧はここ。ちなみに、
@Singleton
は、実際のところ「Applicationレベルのスコープ」と言えます。コンストラクタ以外を利用した注入
「ファクトリメソッドとか通さないといけないフィールドだと、コンストラクタ呼べなくて登録できひん・・・」
「Moduleいうのを使うんよ」DatabaseModule.kt@InstallIn(ApplicationComponent::class) @Module object DatabaseModule { @Provides fun provideLogDao(database: AppDatabase): LogDao { return database.logDao() } }
@Module
をコンテナとして、その中に関数のイン・アウトとして生成方法を示します。
このときの関数に、@Provides
アノテーションを使用します。Interfaceに対する実装を利用した注入
「フィールドの型にはインターフェースを指定して、インスタンスはその実装を使う時はクラスが違うやん。どうすんの?」
「それもModuleやけど、専用のアノテーションがあるね」NavigationModule.kt@InstallIn(ActivityComponent::class) @Module abstract class NavigationModule { @Binds abstract fun bindNavigator(impl: AppNavigatorImpl): AppNavigator }
@Module
を付与した抽象クラスの中で、抽象関数として入力:実装/出力:インターフェースの定義をします。
このときに@Bind
アノテーションを使用します。
@Provides
と似ていますが、@Bind
は抽象関数にしか使えません。よって、親のModuleクラスも抽象クラスである必要があります。(同一のModuleに両方定義できません。)
@Provides
で入力:実装/出力:インターフェースの関数を用意して、入力をそのままreturn
する関数を実装しても同じことになるかと思います。そのほか
Componentクラスを作らなくて良い
@AndroidEntryPoint
アノテーションを付けると、そのクラスのライフサイクルに従うDIコンテナを生成してくれますと記載しましたが、Androidで使いそうなスコープごとのComponentは標準で用意されています。
それぞれ、どのコンテナに属するかを記載すれば利用できるようになります。
(ActivityやFragmentは@AndroidEntryPoint
により自動、Moduleはしれっと書いていた@InstallIn
アノテーションにより「どのコンテナに属するか」を示します)Qualifierをクラスで分けることができる
同じクラスを指定しつつ、別のインスタンスを利用したい場合の話です。
Daggerでは文字列で名称を指定して別のインスタンスであることを示していましたが、
Hiltではアノテーションクラスを定義して、それを付与することで区別します。
こっちのが型安全的で好きですね。参考
Google Codelabs android-hilt
https://codelabs.developers.google.com/codelabs/android-hiltあとがき
正直に言いまして、ここ2日くらいで初めてHiltについて学びました。
そして手を付けてみたら
具体的なプロジェクトに使えていないこともあり「え、簡単では・・・?」となり、
「逆にこれDaggerとの比較の観点が無いと何が嬉しいのか説明できねえやつだわ」と困ったりしていました。結果、少しDagger側の話も学び直したりもしまして、もしかしたら今なら1年前よりもMaster of Daggerがすんなり読めるのでは・・・?とか思っています。勢いで参加に名乗りを上げたアドカレでしたが、またひとつ勉強の機会になったと思います。ありがとうございました。
- 投稿日:2020-12-08T20:47:17+09:00
【Kotlin】SharedFlowとStateFlowを読み解く
前置き
ACCESS Advent Calendar 2020 の9日目です。
初学者向けKotlin Coroutines Flowの続きで、SharedFlowとStateFlowに関する記事です。Flowの復習
Flowはこういうやつでしたね。
View | ViewModel | UseCase〜深層 ----------------------------------------------- | | イベント → Coroutine起動 → 時間のかかる処理(非同期) | | ↓↓↓ 描画 ←←← 出力データ加工 ←←← 出力データ送信(複数回) | |CounterUseCase.ktsuspend fun countStream(): Flow<Int> = flow { repeat(100) { count -> delay(100) emit(count) // 0 1 2 3 4 ... 99 } }※View/ViewModelのコードは省略。こちらに載ってます。
Flowでの値の更新は、上記UseCaseの
flow { ... }
ラムダ式中でしかできません。
つまりViewModel側では値を更新できず、また.value
みたいに値の参照もできません。
subscribeしてる数だけflow { ... }
ラムダ式が呼ばれてしまうのも特徴です。それだと状態保持とか処理リソースの節約には向いてないってことで、ホットストリームなFlowとして登場したのが、今回紹介するSharedFlowとStateFlowです。
SharedFlowとは
複数箇所でのsubscribeでデータや状態を共有できるFlowで、処理リソースの節約に向いてます。
ただのFlowと違う点は以下。sharedFlow.onEach { println("1") }.launchIn(scope) sharedFlow.onEach { println("2") }.launchIn(scope)
- こんな感じで複数subscribeしてても
flow { ... }
ラムダ式側は1回しか呼ばれない- 処理開始タイミングを選択できる(後述)
- ちゃんと止めるまでsubscribeされ続ける
- このサンプル (
LatestNewsActivity
のとこ)みたいにLiveData
に変換し、observe
引数にLifecycleOwner
を設定すれば、表示中だけのsubscribeは可能- 色々高機能
- replay: subscribeした瞬間、過去のn回の値を受信する
- buffer: 複数subscribeかつ処理に時間がかかるとき、1回目に行われた処理をバッファリングして、2回目以降を早くしてくれる(一言では説明しにくい…こちらがわかりやすい)
StateFlowとは
状態保持に特化したSharedFlowです。LiveDataに似ています、というか実質の後継機能です。
- 初期値が必須
- 現在の状態を
.value
で受け取れる- MutableStateFlowを使えば、
.value
への代入も可能
- その際Coroutines Scopeは不要
launchIn
で直近の値を1つ受信する- 同じ値の代入は受信しない
- waitとかを挟まず連続して値が変更されたとき、最後の値しか受信しない
- つまり「状態」が「保持」されないと「状態変化」とみなされない
LiveDataとの違いは、こちらの記事がわかりやすいです。
初期化
MutableSharedFlow
(link)、MutableStateFlow
(link)を使い、このように初期化します。Flowからの変換
shareIn
(link)、stateIn
(link)を使い、このように変換します。処理開始タイミングの指定
flow { ... }
ラムダ式の処理開始タイミングは、shareIn
のSharingStartedオプションで、変換時すぐ開始するか、subscribeが行われてから開始するかを選択できます。参考文献
- 投稿日:2020-12-08T01:23:37+09:00
Xamarin.Android で Unity as a Library (うまくいった話)
この記事は、Xamarin Advent Calendar 2020の8日目の記事です。
はじめに
Xamarin.Android で Unity as a Library (をやろうとしてうまくいかなった話) の記事を読んで、できないことはないよなと思い、自分でも試してみることにしました。
結果
記事の手順でできました。
試した環境は以下の通りです。
- macOS Big Sur
- Unity 2019.4.16f1
- Android Studio 4.1.1
- Visual Studio for Mac 8.8.3
実機(UMIDIGI A7 Pro)で試しています。また、デバッグ実行だとUnityの画面が表示されなかったのですが、デバッグなし実行だとうまくいきました。
コード
こちら
記事にあったコードを拝借させていただきました。おわりに
どうしてうまくいかなかったのかは定かではありませんが、ひとまず、Xamarin.Androidでも、Unity as a Libraryは使えそうです。