0
0

More than 1 year has passed since last update.

Kotlinプロジェクトでどこまでキーを隠蔽化できるか(その4:C++での文字列難読化)

Posted at

Kotlinを使ってAndroidアプリを作った際に、NCMBのアプリケーションキーとクライアントキーをどこまで隠蔽化できるのか試しています。前回はC++を使ってコンパイル、隠蔽化する方法を試しました。そのままだとHEXエディタでキーを見つけられてしまうので、C++上での難読化を試してみました。

難読化ツール

今回はC/C++ Obfuscator - Obfuscate your C/C++ source code for free and onlineを利用しています。オンラインでC/C++のコードを難読化してくれるサービスです。

image.png

これを使ってキーを難読化し、C++のコード中に埋め込んでみます。

Android SDKの導入周りは前回と変わりませんが、念のため書いておきます。

Androidプロジェクトを作る

C++に対応するため、Androidプロジェクトを作成する際にNative C++を選択します。

ScreenShot_ 2021-11-04 18.17.47.png

言語はKotlinで問題ありません。

ScreenShot_ 2021-11-04 18.18.06.png

native-lib.cppの編集

app/cpp ディレクトリにnative-lib.cppというファイルがありますので、これを編集します。

ScreenShot_ 2021-11-05 11.53.03.png

今回はアプリケーションキーとクライアントキーを返却する関数を追加します。それぞれC/C++ Obfuscator - Obfuscate your C/C++ source code for free and onlineで生成した難読化文字列に変換します。

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_kotlinhiddenkey_MainActivity_applicationKey(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "\x48""e\154l\x6F"" \127o\x72""l\144!";
    return env->NewStringUTF(hello.c_str());
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_kotlinhiddenkey_MainActivity_clientKey(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "\x48""e\154l\x6F"" \127o\x72""l\144!";
    return env->NewStringUTF(hello.c_str());
}

これで関数の追加が完了です。

Android SDKを導入する

次にNCMBのAndroid SDKを導入します。これはイントロダクション (Android) : クイックスタート | ニフクラ mobile backendに沿って進めてもらえば問題ありません。具体的には次の手順を行います。

  1. GitHubのリリースページからSDKをダウンロードして展開
  2. NCMB.jarをapp/libsディレクトリに入れる
  3. app/build.gradle の編集
  4. app/src/main/AndroidManifest.xml の編集

ScreenShot_ 2021-11-05 11.55.42.png

コードを修正する

MainActivity.kt を修正します。まずSDKを読み込みます。

import com.nifcloud.mbaas.core.NCMB;

次にC++ファイルで設定した関数を定義します。

class MainActivity : AppCompatActivity() {
  // 省略
  external fun applicationKey(): String
  external fun clientKey(): String
}

そしてNCMBの初期化時に呼び出します。

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    NCMB.initialize(this.getApplicationContext(),applicationKey(),clientKey());
    // 省略
}

これで完了です。

実行する

初期化が終われば、後は普段のNCMB利用と同じく使えます。

// クラスのNCMBObjectを作成
val obj = NCMBObject("TestClass")
// オブジェクトの値を設定
try {
    obj.put("message", "Hello, NCMB!")
} catch (e: NCMBException) {
    e.printStackTrace()
}
// データストアへの登録
obj.saveInBackground { e ->
    if (e != null) {
        //保存に失敗した場合の処理
        Log.d("Main", "Data creates failed.");
    } else {
        //保存に成功した場合の処理
        Log.d("Main", "Data creates successful.");
    }
}

これで完了です。

ビルドする

後は普段通りAndroidアプリをビルドします。

HEXエディタで見てみる

C++のコード上では難読化されているのですが、コンパイルされた結果を見てみると、元の文字列が復元されてしまっているのが分かります。単純に検索しても引っかかるので、難読化ツールの導入は意味がなさそうです。

ScreenShot__2021-11-11_10_36_14.jpg

関数を分割する

苦肉の策ですが、例えば関数を2つに分割してみます。

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_kotlinhiddenkey_MainActivity_applicationKey1(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "アプリケーションキーの前半";
    return env->NewStringUTF(hello.c_str());
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_kotlinhiddenkey_MainActivity_clientKey1(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "クライアントキーの前半";
    return env->NewStringUTF(hello.c_str());
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_kotlinhiddenkey_MainActivity_applicationKey2(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "アプリケーションキーの後半";
    return env->NewStringUTF(hello.c_str());
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_kotlinhiddenkey_MainActivity_clientKey2(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "クライアントキーの後半";
    return env->NewStringUTF(hello.c_str());
}

Kotlin側でも関数を2つ分定義します。

external fun applicationKey1(): String
external fun applicationKey2(): String
external fun clientKey1(): String
external fun clientKey2(): String

そして呼び出し側で文字列を連結します。

var applicationKey = applicationKey1() + applicationKey2();
var clientKey = clientKey1() + clientKey2();
NCMB.initialize(this.getApplicationContext(),applicationKey,clientKey);

このように分けた状態でビルドすると、HEXエディタ上で見ても分割されています。こうなっていれば、見つけづらくなるかも知れません。

ScreenShot__2021-11-11_10_43_10.jpg

まとめ

Androidアプリでのキー隠蔽化については、C++を利用するのが一番だと思いますが、キーを関数に直書きしているとHEXエディタでそれっぽい文字列を探される可能性があります。文字列を分割して呼び出すなど、多少の工夫がいりそうです。

イントロダクション (Android) : クイックスタート | ニフクラ mobile backend

0
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0