更新代码

This commit is contained in:
mahongyin
2021-03-03 18:02:36 +08:00
parent a8c51116b8
commit d0c4367180
22 changed files with 1040 additions and 268 deletions

View File

@@ -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>

View File

@@ -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();

View File

@@ -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);

View 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);
}
}