android id c.apk,android - Check .apk-signature in C/native Code - Stack Overflow

As I have been asked to publish some code how I'm now checking the CRC-code of my Java-application from within C, here are some snippets.

I cannot post a complete working solution as it's spread over multiple lines due to performance-reasons, but I hope this is most complete and working:

In your MyApplication.java:

public class MyApplication extends Application {

private static Context context;

public static Context getAppContext() {

return MyApplication.context;

}

@Override

public void onCreate() {

super.onCreate();

MyApplication.context = getApplicationContext();

}

}

Android.mk:

LOCAL_CFLAGS += -O3 -DDEBUG_MODE=0 -DCLASSES_CRC=2331492378

Inside your C-code:

#define LOG_TAG "Your Log Tag"

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

#if DEBUG_MODE

#define LOGDH(...) LOGD(__VA_ARGS__)

#define LOGIH(...) LOGI(__VA_ARGS__)

#define LOGEH(...) LOGE(__VA_ARGS__)

#else

#define LOGDH(...) //

#define LOGIH(...) //

#define LOGEH(...) //

#endif

int isSecure = -1;

jclass MyApplication;

jclass Context;

jclass ApplicationInfo;

jclass ZipFile;

jclass ZipEntry;

jclass CheckedInputStream;

jclass Adler32;

jclass Checksum;

jmethodID MyApplication_getAppContextMethodId;

jmethodID Context_getApplicationInfoMethodId;

jmethodID ZipFile_ConstructorMethodId;

jmethodID CheckedInputStream_ConstructorMethodId;

jmethodID Adler32_ConstructorMethodId;

jmethodID ZipFile_getEntryMethodId;

jmethodID ZipFile_getInputStreamMethodId;

jmethodID CheckedInputStream_readMethodId;

jmethodID CheckedInputStream_getChecksumMethodId;

jmethodID Checksum_getValueMethodId;

jfieldID ApplicationInfo_flagsFieldId;

jfieldID ApplicationInfo_FLAG_DEBUGGABLEFieldId;

jfieldID ApplicationInfo_sourceDirFieldId;

static long getClassesCRC(JNIEnv *env) {

jobject appContextInstance = (*env)->CallStaticObjectMethod(env,

MyApplication, MyApplication_getAppContextMethodId);

if (!appContextInstance) {

LOGEH("Unable to get instance of AppContext");

return false;

}

jobject applicationInfoInstance = (*env)->CallObjectMethod(env,

appContextInstance, Context_getApplicationInfoMethodId);

if (!appContextInstance) {

LOGEH("Unable to get instance of ApplicationInfo");

return false;

}

jobject zipFileInstance = (*env)->NewObject(env, ZipFile,

ZipFile_ConstructorMethodId,

(*env)->GetObjectField(env, applicationInfoInstance,

ApplicationInfo_sourceDirFieldId));

if (!zipFileInstance) {

LOGEH("Unable to get instance of ZipFile");

return -1;

}

jstring classesDexString = (*env)->NewStringUTF(env, "classes.dex");

jobject zipEntryInstance = (*env)->CallObjectMethod(env, zipFileInstance,

ZipFile_getEntryMethodId, classesDexString);

if (!zipFileInstance) {

LOGEH("Unable to get instance of ZipEntry");

return -1;

}

(*env)->DeleteLocalRef(env, classesDexString);

jobject adler32Instance = (*env)->NewObject(env, Adler32,

Adler32_ConstructorMethodId);

if (!adler32Instance) {

LOGEH("Unable to get instance of Adler32");

return -1;

}

jobject inputStreamInstance = (*env)->CallObjectMethod(env, zipFileInstance,

ZipFile_getInputStreamMethodId, zipEntryInstance);

if (!inputStreamInstance) {

LOGEH("Unable to get instance of InputStream");

return -1;

}

jobject checkedInputStreamInstance = (*env)->NewObject(env,

CheckedInputStream, CheckedInputStream_ConstructorMethodId,

inputStreamInstance, adler32Instance);

if (!checkedInputStreamInstance) {

LOGEH("Unable to get instance of CheckedInputStream");

return -1;

}

int bufferSize = 128;

jbyteArray bufferBytes = (*env)->NewByteArray(env, bufferSize);

while ((*env)->CallIntMethod(env, checkedInputStreamInstance,

CheckedInputStream_readMethodId, bufferBytes) > 0) {

}

(*env)->DeleteLocalRef(env, bufferBytes);

jobject checksumInstance = (*env)->CallObjectMethod(env,

checkedInputStreamInstance, CheckedInputStream_getChecksumMethodId);

if (!checksumInstance) {

LOGEH("Unable to get instance of CheckSum");

return -1;

}

return (*env)->CallLongMethod(env, checksumInstance,

Checksum_getValueMethodId);

}

static bool isDebuggable(JNIEnv *env) {

jobject appContextInstance = (*env)->CallStaticObjectMethod(env,

MyApplication, Application_getAppContextMethodId);

if (!appContextInstance) {

LOGEH("Unable to get instance of AppContext");

return false;

}

jobject applicationInfoInstance = (*env)->CallObjectMethod(env,

appContextInstance, Context_getApplicationInfoMethodId);

if (!appContextInstance) {

LOGEH("Unable to get instance of ApplicationInfo");

return false;

}

int FLAG_DEBUGGABLE = (*env)->GetStaticIntField(env, ApplicationInfo,

ApplicationInfo_FLAG_DEBUGGABLEFieldId);

int flags = (*env)->GetIntField(env, applicationInfoInstance,

ApplicationInfo_flagsFieldId);

return (0 != (flags &= FLAG_DEBUGGABLE));

}

static bool isSecureEnvironment(JNIEnv *env) {

//isSecure = true; // TODO remove this

if (isSecure == -1) {

isSecure = true;

if (isDebuggable(env)) {

// someone used the app in debug-mode

#if DEBUG_MODE != 1

// TODO report

#endif

LOGEH("App IS DEBUGGABLE!");

isSecure = false;

} else {

// check CRC

long classesCRC = getClassesCRC(env);

if (classesCRC != (long) CLASSES_CRC) {

#if DEBUG_MODE != 1

// TODO report

#endif

LOGEH("CRC-CHECK FAILED: %lu", classesCRC);

isSecure = false;

}

}

}

return isSecure;

}

static bool initJavaClasses(JNIEnv * env) {

jclass local = (*env)->FindClass(env, "eu/my/MyApplication");

MyApplication = (*env)->NewGlobalRef(env, local);

if (!MyApplication) {

LOGEH("Unable to find the MyApplication class");

return false;

}

local = (*env)->FindClass(env, "android/content/Context");

Context = (*env)->NewGlobalRef(env, local);

(*env)->DeleteLocalRef(env, local);

if (!Context) {

LOGEH("Unable to find the Context class");

return false;

}

local = (*env)->FindClass(env, "android/content/pm/ApplicationInfo");

ApplicationInfo = (*env)->NewGlobalRef(env, local);

(*env)->DeleteLocalRef(env, local);

if (!ApplicationInfo) {

LOGEH("Unable to find the ApplicationInfo class");

return false;

}

local = (*env)->FindClass(env, "java/util/zip/ZipFile");

ZipFile = (*env)->NewGlobalRef(env, local);

(*env)->DeleteLocalRef(env, local);

if (!ZipFile) {

LOGEH("Unable to find the ZipFile class");

return false;

}

local = (*env)->FindClass(env, "java/util/zip/ZipEntry");

ZipEntry = (*env)->NewGlobalRef(env, local);

(*env)->DeleteLocalRef(env, local);

if (!ZipEntry) {

LOGEH("Unable to find the ZipEntry class");

return false;

}

local = (*env)->FindClass(env, "java/util/zip/CheckedInputStream");

CheckedInputStream = (*env)->NewGlobalRef(env, local);

(*env)->DeleteLocalRef(env, local);

if (!CheckedInputStream) {

LOGEH("Unable to find the CheckedInputStream class");

return false;

}

local = (*env)->FindClass(env, "java/util/zip/Adler32");

Adler32 = (*env)->NewGlobalRef(env, local);

(*env)->DeleteLocalRef(env, local);

if (!Adler32) {

LOGEH("Unable to find the Adler32 class");

return false;

}

local = (*env)->FindClass(env, "java/util/zip/Checksum");

Checksum = (*env)->NewGlobalRef(env, local);

(*env)->DeleteLocalRef(env, local);

if (!Checksum) {

LOGEH("Unable to find the Checksum class");

return false;

}

return true;

}

static bool initJavaMethods(JNIEnv * env) {

MyApplication_getAppContextMethodId = (*env)->GetStaticMethodID(env,

MyApplication, "getAppContext", "()Landroid/content/Context;");

if (!MyApplication_getAppContextMethodId) {

LOGEH("Unable to find the getAppContext method");

return false;

}

Context_getApplicationInfoMethodId = (*env)->GetMethodID(env, Context,

"getApplicationInfo", "()Landroid/content/pm/ApplicationInfo;");

if (!Context_getApplicationInfoMethodId) {

LOGEH("Unable to find the getApplicationInfo method");

return false;

}

ZipFile_ConstructorMethodId = (*env)->GetMethodID(env, ZipFile, "",

"(Ljava/lang/String;)V");

if (!ZipFile_ConstructorMethodId) {

LOGEH("Unable to find the constructor method");

return false;

}

CheckedInputStream_ConstructorMethodId = (*env)->GetMethodID(env,

CheckedInputStream, "",

"(Ljava/io/InputStream;Ljava/util/zip/Checksum;)V");

if (!CheckedInputStream_ConstructorMethodId) {

LOGEH("Unable to find the constructor method");

return false;

}

Adler32_ConstructorMethodId = (*env)->GetMethodID(env, Adler32, "",

"()V");

if (!Adler32_ConstructorMethodId) {

LOGEH("Unable to find the constructor method");

return false;

}

ZipFile_getEntryMethodId = (*env)->GetMethodID(env, ZipFile, "getEntry",

"(Ljava/lang/String;)Ljava/util/zip/ZipEntry;");

if (!ZipFile_getEntryMethodId) {

LOGEH("Unable to find the getEntry method");

return false;

}

ZipFile_getInputStreamMethodId = (*env)->GetMethodID(env, ZipFile,

"getInputStream", "(Ljava/util/zip/ZipEntry;)Ljava/io/InputStream;");

if (!ZipFile_getInputStreamMethodId) {

LOGEH("Unable to find the getInputStream method");

return false;

}

CheckedInputStream_readMethodId = (*env)->GetMethodID(env, CheckedInputStream,

"read", "([B)I");

if (!CheckedInputStream_readMethodId) {

LOGEH("Unable to find the read method");

return false;

}

CheckedInputStream_getChecksumMethodId = (*env)->GetMethodID(env,

CheckedInputStream, "getChecksum", "()Ljava/util/zip/Checksum;");

if (!CheckedInputStream_getChecksumMethodId) {

LOGEH("Unable to find the getChecksum method");

return false;

}

Checksum_getValueMethodId = (*env)->GetMethodID(env, Checksum, "getValue",

"()J");

if (!Checksum_getValueMethodId) {

LOGEH("Unable to find the getValue method");

return false;

}

return true;

}

static bool initJavaFields(JNIEnv * env) {

ApplicationInfo_flagsFieldId = (*env)->GetFieldID(env, ApplicationInfo, "flags",

"I");

if (!ApplicationInfo_flagsFieldId) {

LOGEH("Unable to find the flags field");

return false;

}

ApplicationInfo_FLAG_DEBUGGABLEFieldId = (*env)->GetStaticFieldID(env,

ApplicationInfo, "FLAG_DEBUGGABLE", "I");

if (!ApplicationInfo_FLAG_DEBUGGABLEFieldId) {

LOGEH("Unable to get static field FLAG_DEBUGGABLE");

return false;

}

ApplicationInfo_sourceDirFieldId = (*env)->GetFieldID(env, ApplicationInfo,

"sourceDir", "Ljava/lang/String;");

if (!ApplicationInfo_sourceDirFieldId) {

LOGEH("Unable to get static field sourceDir");

return false;

}

return true;

}

jint JNI_OnLoad(JavaVM* vm, void* reserved) {

(void) reserved; // Suppress the warning.

JNIEnv * env;

if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK) {

return -1;

}

if (!initJavaClasses(env)) {

return -1;

}

if (!initJavaMethods(env)) {

return -1;

}

if (!initJavaFields(env)) {

return -1;

}

return JNI_VERSION_1_6;

}

Don't forget to add the methods of the MyApplication into the Proguard-settings to prevent their remove!

Usage:

Create your APK with -DDEBUG_MODE=1

start the APK on your Android

read the value inside "CRC-check failed:xxx"

take that value and insert it into CLASSES_CRC=xxxx

switch to -DDEBUG_MODE=0

rebuild your APK

check if your app is running well

publish

This method is a little more complicated as it requires 2 builds to get a valid APK.

But as the CRC is checked inside C and not just the dummy-signature of the APK-file is taken, this check is nearly bullet-proof.

In my situation, I'm for exampling not even doing the setup of the license-mechanisms in case the signature is invalid.

Additionally, as this method only uses numbers and not chars, it's fully compiled.

Hope this helps someone!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值