更新代码
This commit is contained in:
@@ -1,4 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="cn.android.security"/>
|
||||
package="cn.android.security">
|
||||
<application>
|
||||
<!--android:authorities="${applicationId}.library-installer"
|
||||
android:authorities="cn.android.security.InitProvider"-->
|
||||
<provider
|
||||
android:name=".InitProvider"
|
||||
android:authorities="${applicationId}.InitProvider"
|
||||
android:exported="false"
|
||||
android:multiprocess="true" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.android.security;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
@@ -21,6 +22,7 @@ import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@@ -49,15 +51,15 @@ public class APISecurity {
|
||||
* 被Native调用的Java方法
|
||||
*/
|
||||
public void javaMethod(String msg) {
|
||||
Log.e("错误代码", msg);
|
||||
Log.e("mhyLog错误代码", msg);
|
||||
// System.exit(1);
|
||||
}
|
||||
|
||||
public static void verify(Context context) {
|
||||
Log.e("mhyLog", "hash"+AppSigning.getSignatureHash(context));
|
||||
runCommand();
|
||||
Log.e("包路径文件签名", getApkSignatures(context, context.getPackageName()));
|
||||
Log.e("已安装APP签名", getInstalledAPKSignature(context, context.getPackageName()));
|
||||
Log.e("mhyLog", "hash:"+AppSigning.getSignatureHash(context));
|
||||
//runCommand();
|
||||
Log.e("mhyLog包文件签名", getApkSignatures(context,context.getPackageName()));
|
||||
Log.e("mhyLog已安装签名", getInstalledAPKSignature(context, context.getPackageName()));
|
||||
//通过获取其他应用的签名 如果一样那么被hook了
|
||||
}
|
||||
|
||||
@@ -67,7 +69,7 @@ public class APISecurity {
|
||||
public static String getInstalledAPKSignature(Context context, String packageName) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
PackageInfo appInfo = pm.getPackageInfo(packageName.trim(), PackageManager.GET_SIGNING_CERTIFICATES);
|
||||
if (appInfo == null || appInfo.signingInfo == null)
|
||||
return "";
|
||||
@@ -86,47 +88,91 @@ public class APISecurity {
|
||||
|
||||
/** 防破签名 2
|
||||
* C调用Java 从源安装文件获取签名信息
|
||||
* 有bug
|
||||
* */
|
||||
public static String getApkSignatures(Context context, String packname) {
|
||||
String sign = "";
|
||||
String path = null;
|
||||
// try {//获取此包安装路径
|
||||
// //第一种方法
|
||||
// ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(packname, 0);
|
||||
// path = applicationInfo.sourceDir;
|
||||
// //第二种方法
|
||||
//// ApplicationInfo applicationInfo = context.getPackageManager().getPackageInfo(packname, PackageManager.GET_META_DATA).applicationInfo;
|
||||
//// path = applicationInfo.publicSourceDir;//sourceDir; // 获取当前apk包的绝对路径
|
||||
// Log.e("其他已知包名apk的安装路径", applicationInfo.sourceDir+ "&---&" + applicationInfo.publicSourceDir);
|
||||
// } catch (PackageManager.NameNotFoundException e) {
|
||||
// e.printStackTrace();
|
||||
// //第三中方法
|
||||
// path=context.getPackageResourcePath();
|
||||
// Log.e("在apk中获取自身安装路径", path);
|
||||
// }
|
||||
String path="";
|
||||
if (!TextUtils.isEmpty(packname)) {
|
||||
try {//获取此包安装路径
|
||||
//第一种方法
|
||||
ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(packname, 0);
|
||||
path = applicationInfo.sourceDir;
|
||||
//第二种方法
|
||||
// ApplicationInfo applicationInfo = context.getPackageManager().getPackageInfo(packname, PackageManager.GET_META_DATA).applicationInfo;
|
||||
// path = applicationInfo.publicSourceDir;//sourceDir; // 获取当前apk包的绝对路径
|
||||
// Log.e("mhyLog其他已知包名apk的安装路径", applicationInfo.sourceDir + "&---&" + applicationInfo.publicSourceDir);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
//第三中方法
|
||||
// path = context.getPackageResourcePath();
|
||||
path= context.getApplicationInfo().sourceDir;
|
||||
// Log.e("mhyLOg在apk中获取自身安装路径", path);
|
||||
}
|
||||
}else {
|
||||
//第三中方法
|
||||
path=context.getPackageResourcePath();
|
||||
// Log.e("在apk中获取自身安装路径", path);
|
||||
// path= context.getApplicationInfo().sourceDir;
|
||||
path=context.getPackageResourcePath();
|
||||
}
|
||||
File apkFile = new File(path);
|
||||
if (apkFile != null && apkFile.exists()) {
|
||||
Log.e("包安装路径", apkFile.getAbsolutePath());
|
||||
if (apkFile.exists()) {
|
||||
Log.e("mhyLog包安装路径", apkFile.getAbsolutePath());
|
||||
PackageManager pm = context.getPackageManager();
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
PackageInfo pkgInfo = pm.getPackageArchiveInfo(apkFile.getAbsolutePath(), PackageManager.GET_SIGNING_CERTIFICATES);
|
||||
if (pkgInfo != null && pkgInfo.signingInfo != null && pkgInfo.signingInfo.getApkContentsSigners().length > 0) {
|
||||
sign = AppSigning.getSignatureString(pkgInfo.signingInfo.getApkContentsSigners(), AppSigning.SHA1);
|
||||
if (pkgInfo != null && pkgInfo.signingInfo != null) {
|
||||
return AppSigning.getSignatureString(pkgInfo.signingInfo.getApkContentsSigners(), AppSigning.SHA1);
|
||||
}
|
||||
} else {
|
||||
PackageInfo pkgInfo = pm.getPackageArchiveInfo(apkFile.getAbsolutePath(), PackageManager.GET_SIGNATURES);
|
||||
if (pkgInfo != null && pkgInfo.signatures != null && pkgInfo.signatures.length > 0) {
|
||||
sign = AppSigning.getSignatureString(pkgInfo.signatures, AppSigning.SHA1);
|
||||
if (pkgInfo != null && pkgInfo.signatures != null) {
|
||||
return AppSigning.getSignatureString(pkgInfo.signatures, AppSigning.SHA1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sign;
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动构建 Context
|
||||
*/
|
||||
@SuppressLint({"DiscouragedPrivateApi","PrivateApi"})
|
||||
public static Context createContext() throws ClassNotFoundException,
|
||||
NoSuchMethodException,
|
||||
InvocationTargetException,
|
||||
IllegalAccessException,
|
||||
NoSuchFieldException,
|
||||
NullPointerException{
|
||||
|
||||
// 反射获取 ActivityThread 的 currentActivityThread 获取 mainThread
|
||||
Class activityThreadClass = Class.forName("android.app.ActivityThread");
|
||||
Method currentActivityThreadMethod =
|
||||
activityThreadClass.getDeclaredMethod("currentActivityThread");
|
||||
currentActivityThreadMethod.setAccessible(true);
|
||||
Object mainThreadObj = currentActivityThreadMethod.invoke(null);
|
||||
|
||||
// 反射获取 mainThread 实例中的 mBoundApplication 字段
|
||||
Field mBoundApplicationField = activityThreadClass.getDeclaredField("mBoundApplication");
|
||||
mBoundApplicationField.setAccessible(true);
|
||||
Object mBoundApplicationObj = mBoundApplicationField.get(mainThreadObj);
|
||||
|
||||
// 获取 mBoundApplication 的 packageInfo 变量
|
||||
if (mBoundApplicationObj == null) throw new NullPointerException("mBoundApplicationObj 反射值空");
|
||||
Class mBoundApplicationClass = mBoundApplicationObj.getClass();
|
||||
Field infoField = mBoundApplicationClass.getDeclaredField("info");
|
||||
infoField.setAccessible(true);
|
||||
Object packageInfoObj = infoField.get(mBoundApplicationObj);
|
||||
|
||||
// 反射调用 ContextImpl.createAppContext(ActivityThread mainThread, LoadedApk packageInfo)
|
||||
if (mainThreadObj == null) throw new NullPointerException("mainThreadObj 反射值空");
|
||||
if (packageInfoObj == null) throw new NullPointerException("packageInfoObj 反射值空");
|
||||
Method createAppContextMethod = Class.forName("android.app.ContextImpl").getDeclaredMethod(
|
||||
"createAppContext",
|
||||
mainThreadObj.getClass(),
|
||||
packageInfoObj.getClass());
|
||||
createAppContextMethod.setAccessible(true);
|
||||
return (Context) createAppContextMethod.invoke(null, mainThreadObj, packageInfoObj);
|
||||
|
||||
}
|
||||
|
||||
//需要读取应用列表权限
|
||||
public void getAppList(Context context) {
|
||||
@@ -146,8 +192,6 @@ public class APISecurity {
|
||||
|
||||
/**
|
||||
* 通过指令获取已安装的包
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private static ArrayList<String> runCommand() {
|
||||
list.clear();
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
import android.os.Build;
|
||||
import android.util.Base64;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -54,29 +55,31 @@ public class AppSigning {
|
||||
* 获取相应的类型的签名信息(把签名的byte[]信息转换成16进制)
|
||||
*/
|
||||
public static String getSignatureString(Signature[] sigs, @SigniType String type) {
|
||||
for (Signature sig : sigs) {
|
||||
Log.e("mhyLog","getSignatureString:"+sig.toCharsString());
|
||||
}
|
||||
byte[] hexBytes = sigs[0].toByteArray();
|
||||
String fingerprint = "error!";
|
||||
try {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
MessageDigest digest = MessageDigest.getInstance(type);
|
||||
if (digest != null) {
|
||||
digest.reset();
|
||||
digest.update(hexBytes);
|
||||
byte[] byteArray = digest.digest();
|
||||
for (int i = 0; i < byteArray.length; i++) {
|
||||
if (Integer.toHexString(0xFF & byteArray[i]).length() == 1) {
|
||||
buffer.append("0").append(Integer.toHexString(0xFF & byteArray[i])); //补0,转换成16进制
|
||||
} else {
|
||||
buffer.append(Integer.toHexString(0xFF & byteArray[i]));//转换成16进制
|
||||
}
|
||||
}
|
||||
fingerprint = buffer.toString().toLowerCase()/*.toUpperCase()*/; //转换成大写
|
||||
if (sigs.length>0) {
|
||||
for (Signature sig : sigs) {
|
||||
Log.e("mhyLog", "Signature64:" + Base64.encodeToString(sig.toCharsString().getBytes(),Base64.DEFAULT));
|
||||
}
|
||||
byte[] hexBytes = sigs[0].toByteArray();
|
||||
try {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
MessageDigest digest = MessageDigest.getInstance(type);
|
||||
if (digest != null) {
|
||||
digest.reset();
|
||||
digest.update(hexBytes);
|
||||
byte[] byteArray = digest.digest();
|
||||
for (int i = 0; i < byteArray.length; i++) {
|
||||
if (Integer.toHexString(0xFF & byteArray[i]).length() == 1) {
|
||||
buffer.append("0").append(Integer.toHexString(0xFF & byteArray[i])); //补0,转换成16进制
|
||||
} else {
|
||||
buffer.append(Integer.toHexString(0xFF & byteArray[i]));//转换成16进制
|
||||
}
|
||||
}
|
||||
fingerprint = buffer.toString().toLowerCase()/*.toUpperCase()*/; //转换成大写
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return fingerprint;
|
||||
}
|
||||
@@ -168,10 +171,11 @@ public class AppSigning {
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
/** 防破签名 3 使原生检测签名不被hook 助力防破签名1而存在
|
||||
/** 防破签名 3 使原生检测签名能获取真实值 助力防破签名1而存在
|
||||
* 通过重置PackageManager防止getPackageInfo方法被代理设置
|
||||
* 亲测MT管理器(当前2.9.1)的一键去签名校验(包括加强版)无效!
|
||||
* 当然如果别人反编译把代码删除的话那就没办法了
|
||||
* getBaseContext()
|
||||
*/
|
||||
public static void resetPackageManager(Context baseContext) {
|
||||
try {
|
||||
@@ -207,7 +211,7 @@ public class AppSigning {
|
||||
* 检测 PackageManager 代理
|
||||
*/
|
||||
@SuppressLint("PrivateApi")
|
||||
private boolean checkPMProxy(Context context){
|
||||
public static boolean checkPMProxy(Context context){
|
||||
String truePMName = "android.content.pm.IPackageManager$Stub$Proxy";
|
||||
String nowPMName = "";
|
||||
try {
|
||||
@@ -227,7 +231,9 @@ public class AppSigning {
|
||||
|
||||
/** 防破签名 2
|
||||
* 安装路径获取签名
|
||||
* PackageParser 28新api
|
||||
*/
|
||||
@SuppressLint("PrivateApi")
|
||||
public static String getAPKSignatures(String apkPath) {
|
||||
String PATH_PackageParser = "android.content.pm.PackageParser";
|
||||
try {
|
||||
@@ -252,7 +258,7 @@ public class AppSigning {
|
||||
Object pkgParserPkg = pkgParser_parsePackageMtd.invoke(pkgParser, new File(apkPath), PackageManager.GET_SIGNATURES);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 28) {
|
||||
Method pkgParser_collectCertificatesMtd = pkgParserCls.getDeclaredMethod("collectCertificates", pkgParserPkg.getClass(), Boolean.TYPE);
|
||||
Method pkgParser_collectCertificatesMtd = pkgParserCls.getDeclaredMethod("collectCertificates", pkgParserPkg.getClass(), Boolean.TYPE);//true skipVerify
|
||||
pkgParser_collectCertificatesMtd.invoke(pkgParser, pkgParserPkg, Build.VERSION.SDK_INT > 28);
|
||||
|
||||
// Method pkgParser_collectCertificatesMtd = pkgParserCls.getDeclaredMethod("collectCertificates", pkgParserPkg.getClass(), Boolean.TYPE);
|
||||
|
||||
115
apisecurity/src/main/java/cn/android/security/InitProvider.java
Normal file
115
apisecurity/src/main/java/cn/android/security/InitProvider.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021. 安卓
|
||||
* FileName: ${NAME}
|
||||
* Author: ${USER}
|
||||
* Date: ${DATE} ${TIME}
|
||||
* Description: ${DESCRIPTION}
|
||||
* History:
|
||||
* <author> <time> <version> <desc>
|
||||
* 作者姓名 修改时间 版本号 描述
|
||||
* 本代码未经许可,不得私自修改何使用
|
||||
*/
|
||||
|
||||
package cn.android.security;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Application;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Created By Mahongyin
|
||||
* Date 2021/3/2 17:24
|
||||
* ContentProvider的onCreate会先于Appliction的onCreate调用 防止application被掉包后 仍有这里可以重置pm代理+检测
|
||||
*/
|
||||
public class InitProvider extends ContentProvider {
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
Context application = getContext().getApplicationContext();
|
||||
if (application == null) {
|
||||
application = getApplicationByReflect();
|
||||
}
|
||||
Log.e("mhyLog", "initContentProvider:");
|
||||
// chekSignature(application);
|
||||
checkApplication();
|
||||
return true;
|
||||
}
|
||||
void chekSignature(Context application){
|
||||
//防hook 并检测
|
||||
if (AppSigning.checkPMProxy(application)) {
|
||||
AppSigning.resetPackageManager(application);
|
||||
String sing = APISecurity.getInstalledAPKSignature(application, application.getPackageName());
|
||||
Log.e("mhyLog手动InitProvider", sing);
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* 校验 application
|
||||
*/
|
||||
private boolean checkApplication(){
|
||||
//在这里使用反射 获取比较靠谱 如果 被替换换 就查出来了
|
||||
Application nowApplication = getApplicationByReflect();
|
||||
String trueApplicationName = "MyApplication";//自己的Application类名 防止替换
|
||||
String nowApplicationName = nowApplication.getClass().getSimpleName();
|
||||
Log.e("mhyLogAppName", "反射获取:"+nowApplicationName);
|
||||
return trueApplicationName.equals(nowApplicationName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过反射获取 当前application
|
||||
*/
|
||||
@SuppressLint("PrivateApi")
|
||||
public Application getApplicationByReflect() {
|
||||
try {
|
||||
Class<?> activityThread = Class.forName("android.app.ActivityThread");
|
||||
Object thread = activityThread.getMethod("currentActivityThread").invoke(null);
|
||||
Object app = activityThread.getMethod("getApplication").invoke(thread);
|
||||
if (app == null) {
|
||||
throw new NullPointerException("you should init first");
|
||||
}
|
||||
return (Application) app;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new NullPointerException("you should init first");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
|
||||
return query(uri, projection, selection, selectionArgs, sortOrder);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getType(@NonNull Uri uri) {
|
||||
return getType(uri);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
|
||||
return insert(uri, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
|
||||
return delete(uri, selection, selectionArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
|
||||
return update(uri, values, selection, selectionArgs);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user