android 资源被窜改,Android 防止App升级过程被劫持和换包

很多情况App在下载安装,同时app再升级过程中,遭到劫持。根据用户反映更新后是一个未知的App。针对此类情况,特做了app防劫持安装防护,稍作分析只要在本地对apk文件进行包名、应用名和签名校验,如果包名和签名不一致,那么就是伪装程序,这个漏洞显而易见!废话不多说直接上代码。

public class ReadApkMessageUtils {

private static String appName;

private static String packageName;

public static String apkInfoPackageName(String absPath, Context context) {

PackageManager pm = context.getPackageManager();

PackageInfo pkgInfo = pm.getPackageArchiveInfo(absPath, PackageManager.GET_ACTIVITIES);

if (pkgInfo != null) {

ApplicationInfo appInfo = pkgInfo.applicationInfo;

/* 必须加这两句,不然下面icon获取是default icon而不是应用包的icon */

appInfo.sourceDir = absPath;

appInfo.publicSourceDir = absPath;

// 得到包名

packageName = appInfo.packageName;

}

return packageName;

}

//获取程序自身的签名

public static String getSign(Context context) {

PackageManager pm = context.getPackageManager();

List apps = pm.getInstalledPackages(PackageManager.GET_SIGNATURES);

Iterator iter = apps.iterator();

while (iter.hasNext()) {

PackageInfo info = iter.next();

String packageName = info.packageName;

//按包名读取签名

if (packageName.equals(SystemToolUtils.getAppPackageName(context))) { //根据你自己的包名替换

return getPublicKey(info.signatures[0].toByteArray());

}

}

return null;

}

//获取新下载还未安装APK的签名信息

@SuppressWarnings({"unchecked", "rawtypes"})

public static String getPackageArchiveInfo(String apkFile, int flags) {

//这个是与显示有关的, 里面涉及到一些像素显示等等, 我们使用默认的情况

DisplayMetrics metrics = new DisplayMetrics();

metrics.setToDefaults();

Object pkgParserPkg = null;

Class[] typeArgs = null;

Object[] valueArgs = null;

try {

Class> packageParserClass = Class.forName("android.content.pm.PackageParser");

Constructor> packageParserConstructor = null;

Object packageParser = null;

//由于SDK版本问题,这里需做适配,来生成不同的构造函数

if (Build.VERSION.SDK_INT > 20) {

//无参数 constructor

packageParserConstructor = packageParserClass.getDeclaredConstructor();

packageParser = packageParserConstructor.newInstance();

packageParserConstructor.setAccessible(true);//允许访问

typeArgs = new Class[2];

typeArgs[0] = File.class;

typeArgs[1] = int.class;

Method pkgParser_parsePackageMtd = packageParserClass.getDeclaredMethod("parsePackage", typeArgs);

pkgParser_parsePackageMtd.setAccessible(true);

valueArgs = new Object[2];

valueArgs[0] = new File(apkFile);

valueArgs[1] = PackageManager.GET_SIGNATURES;

pkgParserPkg = pkgParser_parsePackageMtd.invoke(packageParser, valueArgs);

} else {

//低版本有参数 constructor

packageParserConstructor = packageParserClass.getDeclaredConstructor(String.class);

Object[] fileArgs = {apkFile};

packageParser = packageParserConstructor.newInstance(fileArgs);

packageParserConstructor.setAccessible(true);//允许访问

typeArgs = new Class[4];

typeArgs[0] = File.class;

typeArgs[1] = String.class;

typeArgs[2] = DisplayMetrics.class;

typeArgs[3] = int.class;

Method pkgParser_parsePackageMtd = packageParserClass.getDeclaredMethod("parsePackage", typeArgs);

pkgParser_parsePackageMtd.setAccessible(true);

valueArgs = new Object[4];

valueArgs[0] = new File(apkFile);

valueArgs[1] = apkFile;

valueArgs[2] = metrics;

valueArgs[3] = PackageManager.GET_SIGNATURES;

pkgParserPkg = pkgParser_parsePackageMtd.invoke(packageParser, valueArgs);

}

typeArgs = new Class[2];

typeArgs[0] = pkgParserPkg.getClass();

typeArgs[1] = int.class;

Method pkgParser_collectCertificatesMtd = packageParserClass.getDeclaredMethod("collectCertificates", typeArgs);

valueArgs = new Object[2];

valueArgs[0] = pkgParserPkg;

valueArgs[1] = PackageManager.GET_SIGNATURES;

pkgParser_collectCertificatesMtd.invoke(packageParser, valueArgs);

// 应用程序信息包, 这个公开的, 不过有些函数变量没公开

Field packageInfoFld = pkgParserPkg.getClass().getDeclaredField("mSignatures");

Signature[] info = (Signature[]) packageInfoFld.get(pkgParserPkg);

return getPublicKey(info[0].toByteArray());

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (Exception e) {

e.printStackTrace();

}

return null;

}

private static String getPublicKey(byte[] signature) {

try {

/**

* Created by zeng

* 想要了解更多关于X509,请自行百度

* 创建X509证书工厂类

*/

CertificateFactory certFactory = CertificateFactory.getInstance("X.509");

//创建证书对象

X509Certificate cert = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(signature));

//得到证书公钥

return cert.getPublicKey().toString();

} catch (CertificateException e) {

e.printStackTrace();

}

return null;

}

}

以上是防劫持相应做本地apk校验的一种方法

针对App防劫持有以下方法:

1.升级api加入https 这个肯定不用再过多介绍,看了我介绍的retrofit 的https就明白了。

2.下载Api也需要加入https,也不用再做介绍 ,这里强调的是需要对服务器返回的文件进行Hash值校验,防止文件被篡改,通过对文件的Hash值,还要对服务端返回的自定义key的值进行校验,防止不是自己服务器返回错误的文件。

3.安装过程也必须对Apk文件进行包名和签名验证,防止Apk被恶意植入木马,或替换。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值