android jni签名验证(二)
2015-11-08 16:39
585 查看
此方法主要是应对hook框架,目前比较流行的API hook框架有xposed,cydia substrate,这两个都可以对系统的api进行hook,
由于上述框架都是系统层次上进行Hook,很难进行检测。下面给出一个简单的例子,可以简单的防hook框架。
说明:
使用libzip库,可以自行到网上下载
可以防止对apk安装路径的hook,如getPackageResourcePath();,Application.getApplicationInfo().sourceDir等方法
不采用系统api进行签名获取,通过内建相关方法获取签名信息。防Hook。如网上流传“空道大神”提供的HOOK模块。
暂时就这些,基本可以防止签名进行破解,相关介绍和代码如下
由于上述框架都是系统层次上进行Hook,很难进行检测。下面给出一个简单的例子,可以简单的防hook框架。
说明:
使用libzip库,可以自行到网上下载
可以防止对apk安装路径的hook,如getPackageResourcePath();,Application.getApplicationInfo().sourceDir等方法
不采用系统api进行签名获取,通过内建相关方法获取签名信息。防Hook。如网上流传“空道大神”提供的HOOK模块。
暂时就这些,基本可以防止签名进行破解,相关介绍和代码如下
#include <jni.h> #include <dlfcn.h> #include <fcntl.h> #include <signal.h> #include <stdlib.h> #include <string.h> #include<sys/types.h> #include <stdio.h> #include <android/log.h> #include "libzip/zip.h" /* author:xiaobaiyey date:2015年11月7日20:52:00 email:xiaobaiyey@outlook.com */ #define LOG_TAG __FILE__ ":" STRINGIFY(__LINE__) #define LOGE(format, ...) __android_log_print(ANDROID_LOG_ERROR, "xiaobai", format, ##__VA_ARGS__); #define LOGI(format, ...) __android_log_print(ANDROID_LOG_INFO, "xiaobai", format, ##__VA_ARGS__); int ECsigoffset = 0; int signlength = 0; unsigned char *g_sig = NULL; struct zip* APKArchive; char * findApkSignFile(const char * apkPath, char * sigdir, char * pOut); void verifySign(JNIEnv *env, jobject obj); jstring getentyString(); //获取app包名 int PidToName(int pid, char *lpOutBuf) { if (lpOutBuf == NULL) { return 0; } int nLen = 0; char filename[256] = { 0 }; char cmdline[0x200] = { 0 }; sprintf(filename, "/proc/%d/cmdline", pid); FILE *fp = fopen(filename, "r"); if (fp) { if (fgets(cmdline, sizeof(cmdline), fp) != NULL) { char *p = strchr(cmdline, ':'); if (p) { *p = 0; } strcpy(lpOutBuf, cmdline); nLen = strlen(cmdline); } else { nLen = 0; } fclose(fp); } return nLen; } //获取apk的安装路径,不用系统api是为了防止hook char * getpacknameTopath(char *packname, char *pOut) { FILE *fr = fopen("/proc/self/maps", "r"); if (NULL == fr) { return NULL; } char szfindbuf[256] = "/data/app/"; char szbuf[256] = { 0 }; strncat(szfindbuf, packname, sizeof(szfindbuf)); char *ppath = NULL; char *ptmp = NULL; while (!feof(fr)) //当文件有多行时要做的判断 判断是否到末尾 { memset(szbuf, 0, sizeof(szbuf)); if (fgets(szbuf, sizeof(szbuf), fr)) { if ((ppath = strstr(szbuf, szfindbuf)) && (ptmp = strstr(szbuf, "apk"))) { ptmp[strlen("apk")] = 0; strcpy(pOut, ppath); fclose(fr); return pOut; } } } fclose(fr); return NULL; } char* findApkSignFile(const char* apkPath, char *sigdir, char *pOut) { // LOGI("Loading APK %s", apkPath); APKArchive = zip_open(apkPath, 0, NULL); if (APKArchive == NULL) { //LOGI("Error loading APK"); return NULL; } //Just for debug, print APK contents int numFiles = zip_get_num_files(APKArchive); int i = 0; for (i = 0; i < numFiles; i++) { const char* name = zip_get_name(APKArchive, i, 0); if (name == NULL) { //LOGI("Error reading zip file name at index %i : %s", zip_strerror(APKArchive)); return NULL; } // LOGI("File %i : %s\n", i, name); if (0 == memcmp(sigdir, name, strlen(sigdir)) && strrchr(name, '.') && (0 == memcmp("RSA", strrchr(name, '.') + 1, strlen("RSA")) || 0 == memcmp("DSA", strrchr(name, '.') + 1, strlen("DSA")) || 0 == memcmp("EC", strrchr(name, '.') + 1, strlen("EC")))) { if (0 == memcmp("EC", strrchr(name, '.') + 1, strlen("EC"))) { ECsigoffset = 4; } strcpy(pOut, name); return pOut; } } return NULL; } static JNINativeMethod gMethods[] = { { "verifySign", "()V", (void *)verifySign },{ "getentyString", "(I)Ljava/lang/String;", (jstring *)getentyString }, }; static int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *gMethods, int numMethods) { jclass clazz; clazz = env->FindClass(className); if (clazz == NULL) { return JNI_FALSE; } if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) { return JNI_FALSE; } return JNI_TRUE; } static int registerNatives(JNIEnv *env) { const char *kClassName = "com/example/dump/MainActivity"; //指定要注册的类 即nativie方法所在的类 return registerNativeMethods(env, kClassName, gMethods, sizeof(gMethods) / sizeof(gMethods[0])); } //读取签名信息 int zipreadbuf(char *fname, char **ppbuf) { int nfilesize = 0; struct zip_stat fstat; struct zip_file* file = zip_fopen(APKArchive, fname, 0); if (file) { zip_stat(APKArchive, fname, 0, &fstat); } char *buffer = (char *)malloc(fstat.size + 1); buffer[fstat.size] = 0; int numBytesRead = zip_fread(file, buffer, fstat.size); ; nfilesize = buffer[0x36 + ECsigoffset] * 0x100 + buffer[0x37 + ECsigoffset]; if (buffer[0x36 + ECsigoffset + 2] >= 0x80) { ECsigoffset += 3; nfilesize = buffer[0x36 + ECsigoffset] * 0x100 + buffer[0x37 + ECsigoffset]; } *ppbuf = (char *)malloc(nfilesize + 1); memset(*ppbuf, 0, nfilesize + 1); memcpy(*ppbuf, buffer + 0x38 + ECsigoffset, nfilesize); free(buffer); zip_fclose(file); return nfilesize; } //android.content.pm.Signature中的 parseHexDigit方法,备用 static int parseHexDigit(int nibble) { if ('0' <= nibble && nibble <= '9') { return nibble - '0'; } else if ('a' <= nibble && nibble <= 'f') { return nibble - 'a' + 10; } else if ('A' <= nibble && nibble <= 'F') { return nibble - 'A' + 10; } else { LOGI("what fuck!!!!"); } } void verifySign(JNIEnv *env, jobject obj) { char PackName[256] = { 0 }; char ApkPath[256] = { 0 }; //获取包名和路径 if (PidToName(getpid(), PackName) && getpacknameTopath(PackName, ApkPath)) { LOGI("packName:%s apkPath:%s", PackName, ApkPath); char szSigPath[256] = { 0 }; if (findApkSignFile(ApkPath, "META-INF", szSigPath)) { //将签名文件读取到 g_sig signlength = zipreadbuf(szSigPath, (char**)&g_sig); } else { LOGI("zip Not Find %s", "META-INF"); } if (signlength) { //char* 转jbyte[] jbyteArray array = env->NewByteArray(signlength); env->SetByteArrayRegion(array, 0, signlength, (jbyte*)g_sig); LOGI("the signtrue length is:%d", signlength); //下面方法将签名信息转字符并输出 char *text = new char[signlength * 2]; int N = signlength; for (int j = 0; j < N; j++) { char v = g_sig[j]; char d = (v >> 4) & 0xf; text[j * 2] = (char)(d >= 10 ? ('a' + d - 10) : ('0' + d)); d = v & 0xf; text[j * 2 + 1] = (char)(d >= 10 ? ('a' + d - 10) : ('0' + d)); } //输出签名字符串 LOGI("sign string is: %s", text); //简单比较签名 if (strcmp(text, "这里是原的签名") { LOGI("verifySign success!!!"); } else { LOGI("verifySign fail!!!"); kill(getpid(), SIGABRT) } } } } jstring getentyString() { return NULL; } JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv *env = NULL; jint result = -1; //LOGI("in jni onload"); if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK) { return -1; } //LOGI("register natives"); if (!registerNatives(env)) { //注册 //LOGI("register failed"); return -1; } //成功 result = JNI_VERSION_1_4; //LOGI("register success"); return result; }android.mk文件
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_C_INCLUDES := \ $(LOCAL_PATH) \ $(LOCAL_PATH)/libzip include $(CLEAR_VARS) LOCAL_MODULE := sign LOCAL_SRC_FILES := sign.cpp LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -ldl -llog -lz #打印日志 LOCAL_STATIC_LIBRARIES := libc \ libzip include $(BUILD_SHARED_LIBRARY) include $(call all-makefiles-under,$(LOCAL_PATH))
相关文章推荐
- android获得sd卡和本机内存大小
- android85 短信防火墙
- ubuntu上配置android环境
- android jni签名验证(一)
- 对Android动画中Martix和Camera的一些理解
- Android笔记(五十四) Android四大组件之一——ContentProvider(一)
- 【Android】Android工具函数整理
- 野人学Android第二弹——自定义ListView第二课
- Android(10):时间与日期TimePicker、DatePicker、模拟时钟(非数字时钟)AnalogcClock
- android studio 如何设置代码区域的背景色
- 如何反编译APK?
- Android 效率开发之EventBus新使用方法
- android视图的一些总结
- Android读书笔记-----自定义View(1)原理
- Android中的View
- Android SlideMenu基本属性介绍
- 在Windows下搭建Android开发环境
- android应用1之计算器
- 疗伤之设计模式
- Android M 部分API变动研究