Android App安全防范措施的小结

本文只是对最近工作的一些小结,方便以后的查询。

飞奔.jpg

关闭日志的打印

关闭打印的日志,防止日志中的调试信息被看到。如果在网络框架中使用了日志,那就更加需要关闭了。

代码混淆

代码混淆是最基本的做法,至少能让App在被反编译之后不那么顺畅地阅读源码。

当然,即使是混淆之后的代码,只要花费一定的时间,仍然是可以厘清代码之间的逻辑。

混淆字典的使用

如果对代码中的类名、变量名变成a、b、c还不爽,那可以自定义一些字符来替代它们。此时需要用到混淆字典。

推荐一个github上的库:https://github.com/ysrc/AndroidObfuseDictionary

使用混淆字典之后反编译的效果.png

在proguard-rules.pro中添加混淆字典的配置

#混淆字典
-obfuscationdictionary dic.txt
-classobfuscationdictionary dic.txt
-packageobfuscationdictionary dic.txt

native层校验

除了混淆之外,App还需要防止被别人进行二次打包。

由于release签名的唯一性,可以考虑在native层进行签名的校验。如果签名不正确,直接让App crash。

我们重写JNI_OnLoad()函数,在此处进行校验。

jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env = NULL;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
        return JNI_ERR;
    }
    if (verifySign(env) == JNI_OK) {
        return JNI_VERSION_1_4;
    }
    LOGE("签名不一致!");
    return JNI_ERR;
}

verifySign()函数会执行真正的校验,将存放在native层的签名字符串和当前App的签名进行比对。

static int verifySign(JNIEnv *env) {
    // Application object
    jobject application = getApplication(env);
    if (application == NULL) {
        return JNI_ERR;
    }
    // Context(ContextWrapper) class
    jclass context_clz = env->GetObjectClass(application);
    // getPackageManager()
    jmethodID getPackageManager = env->GetMethodID(context_clz, "getPackageManager",
                                                   "()Landroid/content/pm/PackageManager;");
    // android.content.pm.PackageManager object
    jobject package_manager = env->CallObjectMethod(application, getPackageManager);
    // PackageManager class
    jclass package_manager_clz = env->GetObjectClass(package_manager);
    // getPackageInfo()
    jmethodID getPackageInfo = env->GetMethodID(package_manager_clz, "getPackageInfo",
                                                "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
    // context.getPackageName()
    jmethodID getPackageName = env->GetMethodID(context_clz, "getPackageName",
                                                "()Ljava/lang/String;");
    // call getPackageName() and cast from jobject to jstring
    jstring package_name = (jstring) (env->CallObjectMethod(application, getPackageName));
    // PackageInfo object
    jobject package_info = env->CallObjectMethod(package_manager, getPackageInfo, package_name, 64);
    // class PackageInfo
    jclass package_info_clz = env->GetObjectClass(package_info);
    // field signatures
    jfieldID signatures_field = env->GetFieldID(package_info_clz, "signatures",
                                                "[Landroid/content/pm/Signature;");
    jobject signatures = env->GetObjectField(package_info, signatures_field);
    jobjectArray signatures_array = (jobjectArray) signatures;
    jobject signature0 = env->GetObjectArrayElement(signatures_array, 0);
    jclass signature_clz = env->GetObjectClass(signature0);

    jmethodID toCharsString = env->GetMethodID(signature_clz, "toCharsString",
                                               "()Ljava/lang/String;");
    // call toCharsString()
    jstring signature_str = (jstring) (env->CallObjectMethod(signature0, toCharsString));

    // release
    env->DeleteLocalRef(application);
    env->DeleteLocalRef(context_clz);
    env->DeleteLocalRef(package_manager);
    env->DeleteLocalRef(package_manager_clz);
    env->DeleteLocalRef(package_name);
    env->DeleteLocalRef(package_info);
    env->DeleteLocalRef(package_info_clz);
    env->DeleteLocalRef(signatures);
    env->DeleteLocalRef(signature0);
    env->DeleteLocalRef(signature_clz);

    const char *sign = env->GetStringUTFChars(signature_str, NULL);
    if (sign == NULL) {
        LOGE("分配内存失败");
        return JNI_ERR;
    }

    int result = strcmp(sign, RELEASE_SIGN);
    // 使用之后要释放这段内存
    env->ReleaseStringUTFChars(signature_str, sign);
    env->DeleteLocalRef(signature_str);
    if (result == 0) { // 签名一致
        return JNI_OK;
    }

    return JNI_ERR;
}

JNI_OnLoad()函数是只有使用了JNI,才会被调用。为了确保App一启动就能够进行验证签名。

我还写了一个方法:

jstring Java_io_merculet_core_utils_EncryptUtils_nativeCheck(JNIEnv *env, jclass type) {
    return env->NewStringUTF("Security str from native.");
}

在App的MainActivity的onCreate()中使用。

        EncryptUtils.nativeCheck()

EncryptUtils是一个工具类,用于调用native层的方法。

/**
 * @version V1.0 <描述当前版本功能>
 * @FileName: io.merculet.core.utils.EncryptUtils.java
 * @author: Tony Shen
 * @date: 2018-05-21 20:53
 */
public class EncryptUtils {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("codec");
    }

    public static native String nativeCheck();

    ...
}

关键的密码不要明文传输

例如登录、支付相关的密码,最好不要明文传输,需要进行加密。如果在Java层来做加密容易被反编译,那么可以考虑使用C++来实现。

总结

这些措施也只是冰山一角,因为安全一直是永恒的话题。我们还可以考虑使用加壳、反动态调试等等。

参考资料:

  1. http://qbeenslee.com/article/about-wandoujia-proguard-config/
  2. https://github.com/Qrilee/AndroidObfuseDictionary
  3. https://www.jianshu.com/p/2576d064baf1

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏菩提树下的杨过

Flash/Flex学习笔记(33):如何用As3协同Flash CS IDE控制MovieClip实例

AS3历经若干年的成长,已经完全进化为一门面向对象的(动态)语言,但很多介绍AS3的书籍上往往只注意了AS3语言本身,而淡化了如何跟Flash IDE协同开发。...

2238
来自专栏有刻

Java 小记 — RabbitMQ 的实践与思考

38610
来自专栏Linux驱动

34.QT-制作串口助手(并动态检测在线串口,附带源码)

将qextserialport-1.2rc.zip解压,将解压后的src目录拷贝到项目里的子目录SerialSrc下,在项目pro文件中增加下面这行

1593
来自专栏小樱的经验随笔

自己手动复现一个熊猫烧香病毒

最近逛了一下 bilibili ,偶然的一次机会,我在 bilibili 上看到了某个 up 主分享了一个他自己仿照熊猫病毒的原型制作的一个病毒的演示视频,虽然...

6352
来自专栏郭霖

巧用Android网络通信技术,在网络上直接传输对象

要做一个优秀的Android应用,使用到网络通信技术是必不可少的,很难想象一款没有网络交互的软件最终能发展得多成功。那么我们来看一下,一般Android应用程序...

2256
来自专栏blackheart的专栏

[信息安全] 4.一次性密码 && 身份认证三要素

在信息安全领域,一般把Cryptography称为密码,而把Password称为口令。日常用户的认知中,以及我们开发人员沟通过程中,绝大多数被称作密码的东西其...

2986
来自专栏知识分享

android的PowerManager和PowerManager.WakeLock

  学习android一段时间了,为了进一步了解android的应用是如何设计开发的,决定详细研究几个开源的android应用。从一些开源应用中吸收点东西,一边...

1032
来自专栏JavaEE

Java调用微信登录以及eclipse 远程调试前言:一、微信测试号的连接与申请:二、eclipse远程调试:总结:

3415
来自专栏osc同步分享

springboot Actuator

springboot Actuator只需要加入依赖即可使用: <dependency> <groupId>org.springframework.bo...

2996
来自专栏刘望舒

Android PMS处理APK的复制

在上一篇文章Android包管理机制之PackageInstaller安装APK中,我们学习了PackageInstaller是如何安装APK的,最后会将APK...

2135

扫码关注云+社区

领取腾讯云代金券