返回列表 发新帖

【安卓开发】常用签名验证

  [复制链接]

6

主题

183

回帖

515

积分

初中生

Rank: 3Rank: 3

金币
258
好评
1
信誉
100
发表于 2021-9-9 18:06:13 | 显示全部楼层 | 阅读模式  来自 江西
本帖最后由 菜菜大人. 于 2021-9-15 19:54 编辑

说来惭愧,本来是想去为我的项目atools https://wwi.lanzoui.com/b00z7gd1i
着手hook强力签名验证的,但是一时间不知道从何开始

结果之后就开始写签名验证了

1.还是老生常谈的ApplicationInfo.signatures

private void checkSignatureAndHash() {
        try {
            @SuppressLint("PackageManagerGetSignatures") var sign = getPackageManager()
                    .getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES).signatures[0];
            @SuppressLint("PackageManagerGetSignatures") Signature[] signatures = getPackageManager().getPackageInfo(getPackageName(),
                    PackageManager.GET_SIGNATURES).signatures;
            this.signature = signatures[0].toCharsString();
            this.signHash = signature.hashCode() + "";
//            Log.i(TAG, "signature==>" + this.signature + "\n");
//            Log.i(TAG, "signHash==>" + this.signHash + "\n");
            //Log.i(TAG,"sign==>"+sign+"...\n");
            //308202e4308201cc020101300d06092a864886f70d01010
            // Log.i(TAG, "sign2CharsString==>" + sign.toCharsString() + "\n");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

优点:常用
这个api已经被玩烂了,光靠这个完全不够

2.通过安卓9新增的API SigningInfo,一样去验证signatures
//只在安卓9以上起作用,当不起作用时则直接返回true
    private boolean checkSigningInfo() {
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                var info = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNING_CERTIFICATES);
                SigningInfo signingInfo = info.signingInfo;
                Signature[] signatures = signingInfo.getApkContentsSigners();
                signingSign = signatures[0].toCharsString();
                return signingSign.startsWith("308202c1308201a9a003");
            }
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            return false;
        }//安卓版本太低不支持获取signingInfo
        return true;
    }


3.验证AndroidManifest.xml的applicationName属性
private boolean checkApplicationName() {
        return getApplicationInfo().name.equals("caicai.App");
    }
优点:可以验证是否被破解
缺点:返回值亦可被Hook


4.验证文件MD5值
//每次更新代码时值都会改变,因此比较困难才能拿到md5值并准确验证
    private String myMD5() {
        try {
            //获取apk安装路径还有getPackageCodePath
            var srcdir = getPackageManager().getPackageInfo(getPackageName(), 0).applicationInfo.sourceDir;
            //获取文件md5值
            var md5 = FileUtils.getMd5(new File(srcdir));
            Log.i(TAG, "APK的md5值==" + md5);
            return md5;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            System.exit(-1);
        }
        return "";
    }

优点:md5值几乎不能被伪造
缺点:每次增删代码都会更改md5值,不推荐

5.验证软件最新修改时间,如
private final String apkLastModifyTime = "2021-09-09";
    private boolean checkLastModifiedTime(Context ctx) {
        try {
            ZipFile zipFile = new ZipFile(ctx.getPackageCodePath());
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                FileTime lastModifiedTime = zipFile.getEntry("classes.dex").getLastModifiedTime();
                var timeResult = lastModifiedTime.to(TimeUnit.MILLISECONDS);
                Date date = new Date(timeResult);
//                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                var modifyTime = simpleDateFormat.format(date);
                Log.i(TAG, "classes.dex修改时间:" + modifyTime);
            }
            File file = new File(ctx.getPackageCodePath());
            var fileLastModifiedTime = file.lastModified();
            Date date = new Date(fileLastModifiedTime);
//            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            var fileModifyTime = simpleDateFormat.format(date);
            Log.i(TAG, "apk修改时间:" + fileModifyTime);
            return fileModifyTime.equals(apkLastModifyTime);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }


优点:不会像检测MD5值一样难以把控
不足:开发时需要经常去修改apkLastModifyTime

6.native验证apk签名
// cpp/jni code
jboolean checkSignNative(JNIEnv *env, jobject instance, jobject context) {
    jclass context_cls = env->GetObjectClass(context);
    jmethodID getPackageManager_mid = env->GetMethodID
            (context_cls, "getPackageManager", "()Landroid/content/pm/PackageManager;");
    jobject packageManager_instance = env->CallObjectMethod(context, getPackageManager_mid);
    jclass packageManager_cls = env->GetObjectClass(packageManager_instance);
    //获取getPackageInfo方法
    jmethodID getPackageInfo_mid = env->GetMethodID
            (packageManager_cls, "getPackageInfo",
             "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");

    jmethodID getPackageName_mid = env->GetMethodID
            (context_cls, "getPackageName", "()Ljava/lang/String;");
    auto pkgName = static_cast<jstring>((env->CallObjectMethod(context, getPackageName_mid)));
    jobject packageInfo = env->CallObjectMethod(packageManager_instance, getPackageInfo_mid,
                                                pkgName, 64);
    //获取pkgInfo
    jclass pkgInfo_cls = env->GetObjectClass(packageInfo);
    //获取signatures字段
    jfieldID signatures_fid = env->GetFieldID(pkgInfo_cls, "signatures",
                                              "[Landroid/content/pm/Signature;");
    jobject signatures_instance = env->GetObjectField(packageInfo, signatures_fid);
    jobjectArray signatures = reinterpret_cast<jobjectArray>(signatures_instance);
//获取签名
    jobject signature = env->GetObjectArrayElement(signatures, 0);
    jclass string_calss = env->FindClass("java/lang/String");
    jstring src_signature_str = env->NewStringUTF("308202c1308201a9a003");
    jclass signature_calss = env->FindClass("android/content/pm/Signature");
    jmethodID toCharsString_methodID = env->
            GetMethodID(signature_calss, "toCharsString", "()Ljava/lang/String;");

    jstring sign_str = (jstring) env->CallObjectMethod(signature, toCharsString_methodID);
//因为我们比较前20位,所以截取前20位字符串
    jmethodID startWith_mid = env->GetMethodID(string_calss, "startsWith",
                                               "(Ljava/lang/String;)Z");
    jmethodID subString_mid = env->GetMethodID(string_calss, "substring",
                                               "(II)Ljava/lang/String;");
//jmethodID equals_mid=env->GetMethodID(string_calss,"equals", "(Ljava/lang/Object;)Z");
    jstring sign20 = (jstring) env->CallObjectMethod(sign_str, subString_mid, 0, 20);
    bool yes=env->CallBooleanMethod(sign20,startWith_mid,src_signature_str);
    if(yes){
        //签名正确
        return JNI_TRUE;
    }else{
        //签名错误
        return JNI_FALSE;
    }
}
private native boolean checkSignNative(Context ctx);
优点:需要电脑端ida进行破解!!!
缺点:仅使用Java API一样能被hook,且代码繁琐


7.验证软件大小,当用户破解软件时无可避免会引起软件大小的变化,所以
private boolean checkApkSize(){
var apk=new File(getPackageCodePath());
var size=apk.length();
var realSize=4231000;
//4231000
Log.i(TAG, "apk大小:" +size);
//总不可能大于原先的两倍吧?
return size<realSize*2&size>=realSize;
}
缺点:需要经常关注软件大小
样本也在链接中
...暂时想不到了看了这么多了还不关注我?
如有其他验证手段也可以拿出分享









已有1人评分好评 金币 理由
佛说我很笨 + 1 + 1 赞一个!

查看全部评分 总评分:好评 +1  金币 +1 

回复

使用道具 举报

6

主题

183

回帖

515

积分

初中生

Rank: 3Rank: 3

金币
258
好评
1
信誉
100
发表于 2021-9-9 18:09:58 | 显示全部楼层  来自 江西
给自己暖一个
回复

使用道具 举报

32

主题

4259

回帖

1万

积分

博士生

Rank: 7Rank: 7Rank: 7

金币
7894
好评
22
信誉
107

MT论坛最佳新人

发表于 2021-9-9 18:12:18 来自手机  | 显示全部楼层  来自 河南
谢谢分享
回复

使用道具 举报

3

主题

1676

回帖

6971

积分

硕士生

Rank: 6Rank: 6

金币
5576
好评
2
信誉
101
发表于 2021-9-9 18:12:54 来自手机  | 显示全部楼层  来自 广西
先看看能不能把的用
已有1人评分好评 理由
天美Mate + 1 赞一个!

查看全部评分 总评分:好评 +1 

回复

使用道具 举报

2

主题

684

回帖

6024

积分

硕士生

Rank: 6Rank: 6

金币
2197
好评
0
信誉
100
发表于 2021-9-9 18:17:56 来自手机  | 显示全部楼层  来自 山西
看看     
回复

使用道具 举报

74

主题

776

回帖

3184

积分

禁止发言

金币
773
好评
6
信誉
98
发表于 2021-9-9 18:20:20 来自手机  | 显示全部楼层  来自 广东
学习强国
回复

使用道具 举报

23

主题

959

回帖

6431

积分

硕士生

Rank: 6Rank: 6

金币
2284
好评
30
信誉
100
发表于 2021-9-9 18:21:28 来自手机  | 显示全部楼层  来自 湖北
学习学习
回复

使用道具 举报

0

主题

2793

回帖

1万

积分

博士生

Rank: 7Rank: 7Rank: 7

金币
688
好评
1
信誉
100
发表于 2021-9-9 18:23:01 来自手机  | 显示全部楼层  来自 广西
感谢分享
回复

使用道具 举报

39

主题

718

回帖

2854

积分

大学生

人间ོ࿆烟火

Rank: 5Rank: 5

金币
1050
好评
5
信誉
100
发表于 2021-9-9 18:25:44 来自手机  | 显示全部楼层  来自 四川
谢谢大佬分享
回复

使用道具 举报

3

主题

1181

回帖

4798

积分

大学生

Rank: 5Rank: 5

金币
3364
好评
0
信誉
100

MT论坛帅哥MT论坛新人考神MT论坛最佳新人

发表于 2021-9-9 18:28:26 | 显示全部楼层  来自 广东
感谢分享
回复

使用道具 举报

162

主题

8064

回帖

2万

积分

博士后

滑稽

Rank: 8Rank: 8

金币
754
好评
474
信誉
210

MT论坛新人MT论坛最佳新人MT论坛活跃会员考神MT论坛帅哥MT论坛灌水老大

QQ
发表于 2021-9-9 18:32:54 来自手机  | 显示全部楼层  来自 广东
看看      
回复

使用道具 举报

32

主题

1830

回帖

6660

积分

硕士生

Rank: 6Rank: 6

金币
338
好评
13
信誉
100

考神MT论坛帅哥MT论坛最佳新人MT论坛新人

QQ
发表于 2021-9-9 18:36:09 来自手机  | 显示全部楼层  来自 吉林
感谢分享
回复

使用道具 举报

0

主题

40

回帖

153

积分

小学生

Rank: 2

金币
58
好评
0
信誉
100
发表于 2021-9-9 18:36:47 来自手机  | 显示全部楼层  来自 四川
感谢分享
回复

使用道具 举报

16

主题

1605

回帖

5138

积分

硕士生

Rank: 6Rank: 6

金币
2960
好评
8
信誉
100

考神MT论坛活跃会员

QQ
发表于 2021-9-9 18:42:50 来自手机  | 显示全部楼层  来自 广西
看一下哦
回复

使用道具 举报

90

主题

4149

回帖

1万

积分

博士生

Rank: 7Rank: 7Rank: 7

金币
6201
好评
120
信誉
146

考神MT论坛新人MT论坛最佳新人MT论坛活跃会员MT论坛侠客

发表于 2021-9-9 18:43:31 来自手机  | 显示全部楼层  来自 湖北
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表