文章目录[x]
- 1:混淆代码
- 2:Native方法加密
- 3:Native进行签名校验
- 4:反Xposed调试
要防止逆向工程师反编译自己的App获取核心算法或其他功能,App核心代码或者功能加密便非常重要。假如需要在App端将请求服务器的参数进行MD5加密生成签名,然后带上签名发起请求。
混淆代码
最基础的加密便是通过配置proguard-rules.pro对App中的代码进行混淆,这种可以使App中的类名、方法名等变成不易识别的代码。但是,这种弊端很大,对专门的逆向工程师而言就跟直接看源代码一样。而且四大组件、JNI Native方法都不能混淆,从一定意义上来将,还是属于源代码裸奔状态。因此,Java层做加密(可以防止别人抓包,但是无法防止别人反编译),在Java层进行MD5加密生成签名将毫无意义。
Native方法加密
通过调用Native方法将参数进行加密而生成签名:
external fun signatureParams(info:String):String
这样,逆向工程师就不容易找到加密相关的代码。但是这样还是有弊端的,还是无法防止别人反编译apk,因为Native方法本身原因无法对方法进行混淆,只要匹配好包名和方法名拿到apk中的so包照样可以调用。
Native进行签名校验
要处理上面的这种情况,可以在app启动时在Native层进行包名和签名校验。验证过,在进行MD5加密才进行加密,否则可以直接退出app或者返回一个错误的字符串。
package com.melrose1994.jni3
import android.content.Context
/**
* @author Melrose
* @since 1.0.0
*/
object SignatureUtils {
init {
System.loadLibrary("native-lib")
}
external fun signatureParams(info:String):String
/**
* 只允许自己的app使用so ;
*/
external fun signatureVerify(context:Context)
}
在Native中实现如下,在进行MD5进行加密时is_verify为1时才进行加密操作:
//
// Created by Melrose on 2020-05-21.
//
#include "android/log.h"
#include <string>
#include <jni.h>
static const char* PACKET_NAME="com.melrose1994.jni3";
static const char* SIGN="xxxxxx";
static int is_verify = 0;
static const char* JNI_TAG= "JNI_TAG";
extern "C" JNIEXPORT void JNICALL
Java_com_melrose1994_jni3_SignatureUtils_signatureVerify(
JNIEnv *env,
jclass jclz,jobject context) {
//校验包名
jclass jclass1 = env->GetObjectClass(context);
const char* sig1 = "()Ljava/lang/String;";
jmethodID jmethodId = env->GetMethodID(
jclass1,"getPackageName",sig1);
jstring package = static_cast<jstring>(env->CallObjectMethod(context, jmethodId));
const char * c_package = const_cast<char *>(env->GetStringUTFChars(package, NULL));
if(strcmp(PACKET_NAME,c_package)!=0){
return;
}
__android_log_print(ANDROID_LOG_INFO,JNI_TAG,"包名一致");
//校验签名
const char* sig2 = "()Landroid/content/pm/PackageManager;";
jmethodId = env->GetMethodID(jclass1,"getPackageManager",sig2);
jobject manager = env->CallObjectMethod(context,jmethodId);
jclass1 = env->GetObjectClass(manager);
const char* sig3 = "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;";
jmethodId = env->GetMethodID(jclass1,"getPackageInfo",sig3);
jobject package_info = env->CallObjectMethod(manager,jmethodId,package,0x00000040);
jclass1 = env->GetObjectClass(package_info);
jfieldID jfieldId = env->GetFieldID(jclass1,"signatures","[Landroid/content/pm/Signature;");
jobjectArray arr = static_cast<jobjectArray>(env->GetObjectField(package_info, jfieldId));
jobject info =env->GetObjectArrayElement(arr,0);
jclass1 = env->GetObjectClass(info);
const char* sig4 = "()Ljava/lang/String;";
jmethodId = env->GetMethodID(jclass1,"toCharsString",sig4);
jstring j_sign = static_cast<jstring>(env->CallObjectMethod(info, jmethodId));
const char* c_sign =env->GetStringUTFChars(j_sign,NULL);
__android_log_print(ANDROID_LOG_INFO,JNI_TAG,"签名成功:%s",c_sign);
if (strcmp(c_sign,SIGN) == 0){
//签名成功
is_verify = 1;
}
}
反Xposed调试
在Xposed框架中,逆向工程师可以对App进行各种Hook操作来获取App中相关重要的信息。可以在Native方法中通过/proc/{Process.myPid()}/maps读取App自身加载的库中的jar和so文件查看是否含有XposedBridge.jar文件。