Android 检查C/本机代码中的.apk签名
我开发了一个Android应用程序,其中还包含一个用C编写的本机部分(不依赖于应用程序) 如果共享库不执行其工作,则应用程序本身是无用的 我只想让本机部件(共享库)完成它的工作,如果它附带的应用程序(.apk)存在未修改的版本 对我来说,最好的方法是:Android 检查C/本机代码中的.apk签名,android,c,signature,verification,Android,C,Signature,Verification,我开发了一个Android应用程序,其中还包含一个用C编写的本机部分(不依赖于应用程序) 如果共享库不执行其工作,则应用程序本身是无用的 我只想让本机部件(共享库)完成它的工作,如果它附带的应用程序(.apk)存在未修改的版本 对我来说,最好的方法是: 安装应用程序 共享库检查应用程序/.apk的签名/哈希 只有当签名与已知签名匹配时,它才起作用 这样,我想保护我的应用程序免受修改和盗版 有什么建议吗?我刚刚找到了一些用java检查自己签名的帖子,但如果你能对应用程序进行反编译和重新编译,那就没
有什么建议吗?我刚刚找到了一些用java检查自己签名的帖子,但如果你能对应用程序进行反编译和重新编译,那就没什么好笑的了。因为我被要求发布一些代码,我现在是如何从C中检查java应用程序的CRC代码的,下面是一些代码片段 由于性能原因,我无法发布完整的工作解决方案,因为它分布在多条线路上,但我希望这是最完整和最有效的: 在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
在您的C代码中:
#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, "<init>",
"(Ljava/lang/String;)V");
if (!ZipFile_ConstructorMethodId) {
LOGEH("Unable to find the constructor method");
return false;
}
CheckedInputStream_ConstructorMethodId = (*env)->GetMethodID(env,
CheckedInputStream, "<init>",
"(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, "<init>",
"()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;
}
#定义日志标签“您的日志标签”
#定义LOGD(…)\uuuuuAndroid\uLog\uPrint(android\uLog\uDebug、log\uTag、\uuuu VA\uArgs\uuuuu)
#定义LOGI(…)\uuuuuAndroid\uLog\uPrint(android\uLog\uInfo、log\uTag、VA\uArgs\uuuu)
#定义日志(…)\uuuuuAndroid\uLog\uPrint(android\uLog\uError,log\uTag,\uuuU VA\uArgs\uuuuu)
#如果是调试模式
#定义LOGDH(…)LOGD(_VA_ARGS)
#定义LOGIH(…)LOGI(_VA_ARGS__)
#定义LOGEH(…)LOGE(_VA_ARGS)
#否则
#定义LOGDH(…)//
#定义LOGIH(…)//
#定义LOGEH(…)//
#恩迪夫
int isSecure=-1;
jclass MyApplication;
jclass上下文;
jclass应用信息;
jclass ZipFile;
jclass ZipEntry;
jclass CheckedInputStream;
jclass Adler32;
jclass校验和;
jmethodID MyApplication_getAppContextMethodId;
jmethodID上下文_getApplicationInfoMethodId;
jMethodide ZipFile_Constructor Methodide;
jmethodID检查了InputStream_Constructor MethodId;
jmethodID Adler32_Constructor Methodid;
jmethodID ZipFile_getEntryMethodId;
jmethodID ZipFile_getInputStreamMethodId;
jmethodID检查了InputStream_readMethodId;
jmethodID CheckedInputStream_getChecksumMethodId;
jmethodID校验和_getValueMethodId;
jfieldID应用程序信息标志字段DID;
jfieldID ApplicationInfo_FLAG_DEBUGGABLEFieldId;
jfieldID应用程序信息\u sourceDirFieldId;
静态长getClassesCRC(JNIEnv*env){
jobject appContextInstance=(*env)->CallStaticObjectMethod(env,
MyApplication,MyApplication_getAppContextMethodId);
如果(!appContextInstance){
LOGEH(“无法获取AppContext的实例”);
返回false;
}
jobject ApplicationInfo实例=(*env)->CallObjectMethod(env,
appContextInstance,Context_getApplicationInfoMethodId);
如果(!appContextInstance){
LOGEH(“无法获取ApplicationInfo的实例”);
返回false;
}
jobject-zipFileInstance=(*env)->NewObject(env,ZipFile,
ZipFile_ConstructorMethod,
(*env)->GetObjectField(env,ApplicationInfo实例,
ApplicationInfo_sourceDirFieldId);
如果(!zipFileInstance){
LOGEH(“无法获取ZipFile实例”);
返回-1;
}
jstring classesDexString=(*env)->NewStringUTF(env,“classes.dex”);
jobject ZipPentrInstance=(*env)->CallObjectMethod(env,zipFileInstance,
ZipFile_getEntryMethodId,classesDexString);
如果(!zipFileInstance){
LOGEH(“无法获取ZipEntry实例”);
返回-1;
}
(*env)->DeleteLocalRef(env,classesDexString);
jobject adler32Instance=(*env)->NewObject(env,Adler32,
Adler32_ConstructorMethodi);
如果(!adler32Instance){
LOGEH(“无法获取Adler32的实例”);
返回-1;
}
jobject inputStreamInstance=(*env)->CallObjectMethod(env,zipFileInstance,
ZipFile_getInputStreamMethodId,ZipPentrInstance);
如果(!inputStreamInstance){
LOGEH(“无法获取InputStream的实例”);
返回-1;
}
jobject checkedInputStreamInstance=(*env)->NewObject(env,
CheckedInputStream,CheckedInputStream\u Constructor方法,
inputStreamInstance、adler32Instance);
如果(!checkedInputStreamInstance){
LOGEH(“无法获取CheckedInputStream的实例”);
返回-1;
}
int bufferSize=128;
jbyterarray bufferBytes=(*env)->NewByteArray(env,bufferSize);
而((*env)->CallIntMethod(env,checkedInputStreamInstance,
CheckedInputStream_readMethodId,bufferBytes)>0){
}
(*env)->DeleteLocalRef(env,bufferBytes);
jobject checksumInstance=(*env)->CallObjectMethod(env,
checkedInputStreamInstance,CheckedInputStream_getChecksumMethodId);
如果(!checksumInstance){
LOGEH(“无法获取校验和实例”);
返回-1;
}
return(*env)->CallLongMethod(env,checksumInstance,
校验和(getValueMethodId);
}
静态bool是可编辑的(JNIEnv*env){
jobject appContextInstance=(*env)->CallStaticObjectMethod(env,
MyApplication,Application_getAppContextMethodId);
如果(!appContextInstance){
LOGEH(“无法获取AppContext的实例”);
返回false;
}
jobject ApplicationInfo实例=(*env)->CallObjectMethod(env,
appContextInstance,Context_getApplicationInfoMethodId);
如果(!appContextInstance){
LOGEH(“无法获取ApplicationInfo的实例”);
返回false;
}
int FLAG_DEBUGGABLE=(*env)->GetStaticIntField(env,ApplicationInfo,
ApplicationInfo_FLAG_DEBUGGABLEFieldId);
int flags=(*env)->GetIntField(env,ApplicationInfo实例,
ApplicationInfo_flagsfieldd);
返回(0!=(标志&=FLAG_可调试));
}
静态bool是安全的环境(JNIEnv*env){