はじめに
Androidは通常ProGuardで難読化が行われますが、暗号化ではないためにソースコードやxml内の文字列は残ってしまいます。そのため、そこにパスワードやsecret keyなどの秘匿情報を記述していると、リバースエンジニアリングによって漏洩してしまうリスクがあります。
そこで、この記事ではNDK側に秘匿情報(文字列)を持たせ、情報を隠蔽化する方法について書きます。
実装方法
サンプルはこちらに置いておきます
https://github.com/shcahill/NDKSample
Nativeファイルの用意
任意の場所にcpp
ディレクトリを用意し、Cファイルをaddします。
ここに秘匿情報を記載してください。
# include <string.h>
# include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_shcahill_ndksample_MainActivity_stringFromJNI(JNIEnv *env, jobject thiz) {
return (*env)->NewStringUTF(env,
// 秘匿情報の文字列(ここのコメントは残ってしまうので、実際には書かない)
"string from JNI!");
}
関数名は命名規則があります。
- 先頭に
Java_
をつける - パッケージ名を
_
繋ぎでつける - 呼び出すKotlin/Javaコードのファイル名をつける(拡張子は付けない)
- 関数名をつける
この例だと、MainActivityからstringFromJNIという名前で呼び出せます。
また、この例の場合、thiz
が未使用だとwarningが出ますが、消せませんのでご注意ください。
※パッケージ名にアンダースコアが含まれると、アンダースコアの後ろに1
を付与する必要があります。
パッケージにアンダースコアが入っていた場合にJNI関連でハマったのでメモ
次にMakeファイルを同じ場所に追加します。
add_library(
# library name using at Kotlin code
jni-lib-name
# as a shared library
SHARED
# relative path to C/C++ file
jni-sample.c)
add_library
の第一引数は、Kotlin側からsoファイルをloadするときのライブラリ名ですので、任意の名前を付与してください。
第三引数はC/C++ファイルの相対パスです。(ここではMakeFileと同じディレクトリに格納しているため、ファイル名だけになっています)
gradleの設定
Cファイルを読み込むためにはgradleで指定を行い、syncする必要があります。
android {
...
externalNativeBuild {
cmake {
version '3.10.2'
path "src/main/cpp/CMakeLists.txt"
}
}
}
sync後、Android Studio上にも先ほど追加したファイルが表示されるようになります。
Kotlin側の実装
soファイルのロードします。MakeFileで指定した第一引数の名前です。
このクラス実行時の一番最初にやりたいため、companion objectのinitで実行します。
companion object {
init {
System.loadLibrary("jni-lib-name")
}
}
ここで、soファイル名をtypoしたりするとこのファイルを呼んだタイミングで、soファイルがロードできないとエラーが出てクラッシュします。
最後に、ロードしたsoファイルから呼び出しを行います。関数名、戻り値はjni-sample.c
で定義したとおりにします。
private external fun stringFromJNI(): String
あとは、使いたいところで普通の関数としてstringFromJNI()
を呼べます。
.gitignore
app/.externalNativeBuild
を追加しておくと中間生成物をignoreできます。
References
公式ドキュメントも充実しています。
公式ドキュメント