hook getPackageArchiveInfo无效
hook 参数区分 64 & ((Integer) objArr[1]).intValue()
This commit is contained in:
15
README.md
15
README.md
@@ -53,7 +53,7 @@ Android API Security(.so),安卓APP/API安全加密so库,防二次打包,
|
||||
APISecurity.init(context);
|
||||
//计算签名
|
||||
String val = "POST https://www.xxx.com/login?id=1&pwd=xxx......";
|
||||
String sign = MGAPISecurity.sign(aptStr)
|
||||
String sign = APISecurity.sign(aptStr)
|
||||
```
|
||||
App.hook(context);//hook签名验证
|
||||
//在这里 重置PackageManager 只要在验证前重置即可
|
||||
@@ -409,9 +409,18 @@ JNIEXPORT jstring JNICALL Java_com_test_JniTest_testChineseOut
|
||||
|
||||
|
||||
|
||||
|
||||
SystemProperties.getInt("ro.build.version.sdk", 0);
|
||||
// 获取jdk位数
|
||||
String bits = System.getProperty("sun.arch.data.model");
|
||||
String ver = System.getProperty("ro.build.version.sdk");
|
||||
// 获取os名称
|
||||
String ops = System.getProperty("os.name");
|
||||
logger.info("jdk bits=" + bits);
|
||||
logger.info("option sysetm=" + ops);
|
||||
Build.VERSION.SDK_INT > Build.VERSION_CODES.Q
|
||||
SystemProperties.getInt("ro.build.version.sdk", 0);
|
||||
|
||||
|
||||
|
||||
###C++代码取Android系统版本号:
|
||||
```
|
||||
#include <jni.h>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cn.android.security;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
@@ -31,6 +32,7 @@ import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class APISecurity {
|
||||
@@ -44,28 +46,30 @@ public class APISecurity {
|
||||
* @param str
|
||||
*/
|
||||
public static native String sign(String str);
|
||||
|
||||
public static native void verifyApp(Application applicationByReflect);
|
||||
public static native boolean init(Context context);
|
||||
|
||||
/**
|
||||
* 被Native调用的Java方法
|
||||
*/
|
||||
public void javaMethod(String msg) {
|
||||
Log.e("mhyLog错误代码", msg);
|
||||
Log.e("mhyLog错误", msg);
|
||||
// System.exit(1);
|
||||
}
|
||||
|
||||
public static void verify(Context context) {
|
||||
Log.e("mhyLog", "hash:"+AppSigning.getSignatureHash(context));
|
||||
// Log.e("mhyLog", "hash:" + AppSigning.getSignatureHash(context));
|
||||
// Log.e("mhyLog", "sha1:" + getSignSha1(context));
|
||||
//runCommand();
|
||||
Log.e("mhyLog包文件签名", getApkSignatures(context,context.getPackageName()));
|
||||
Log.e("mhyLog已安装签名", getInstalledAPKSignature(context, context.getPackageName()));
|
||||
Log.e("mhyLog包文件", "签名:"+getApkSignatures(context, context.getPackageName()));
|
||||
//Log.e("mhyLog已安装", "签名:"+getInstalledAPKSignature(context, context.getPackageName()));
|
||||
//通过获取其他应用的签名 如果一样那么被hook了
|
||||
}
|
||||
|
||||
/** 防破签名 1
|
||||
/**
|
||||
* 防破签名 1
|
||||
* 获取已安装的app签名
|
||||
* */
|
||||
*/
|
||||
public static String getInstalledAPKSignature(Context context, String packageName) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
try {
|
||||
@@ -74,7 +78,7 @@ public class APISecurity {
|
||||
if (appInfo == null || appInfo.signingInfo == null)
|
||||
return "";
|
||||
return AppSigning.getSignatureString(appInfo.signingInfo.getApkContentsSigners(), AppSigning.SHA1);
|
||||
} else {
|
||||
}else {
|
||||
PackageInfo appInfo = pm.getPackageInfo(packageName.trim(), PackageManager.GET_SIGNATURES);
|
||||
if (appInfo == null || appInfo.signatures == null)
|
||||
return "";
|
||||
@@ -86,62 +90,81 @@ public class APISecurity {
|
||||
return "";
|
||||
}
|
||||
|
||||
/** 防破签名 2
|
||||
/**
|
||||
* 防破签名 2
|
||||
* C调用Java 从源安装文件获取签名信息
|
||||
* 有bug
|
||||
* */
|
||||
*/
|
||||
public static String getApkSignatures(Context context, String packname) {
|
||||
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.getApplicationInfo().sourceDir;
|
||||
path=context.getPackageResourcePath();
|
||||
}
|
||||
String path = getApkPath(context, packname);
|
||||
File apkFile = new File(path);
|
||||
if (apkFile.exists()) {
|
||||
Log.e("mhyLog包安装路径", apkFile.getAbsolutePath());
|
||||
PackageManager pm = context.getPackageManager();
|
||||
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) {
|
||||
return AppSigning.getSignatureString(pkgInfo.signingInfo.getApkContentsSigners(), AppSigning.SHA1);
|
||||
//TODO 这里获取的signingInfo 为空 猜想是flag不对 但看源码好像 目前只能使【GET_SIGNATURES 对应signatures】
|
||||
PackageInfo packageInfo = pm.getPackageArchiveInfo(path, PackageManager.GET_SIGNING_CERTIFICATES);
|
||||
if (packageInfo != null&&packageInfo.signingInfo!=null) {
|
||||
Signature[] signatures = packageInfo.signingInfo.getApkContentsSigners();
|
||||
return AppSigning.getSignatureString(signatures, AppSigning.SHA1);
|
||||
}else {
|
||||
return AppSigning.getAPKSignatures(path);
|
||||
}
|
||||
} else {
|
||||
PackageInfo pkgInfo = pm.getPackageArchiveInfo(apkFile.getAbsolutePath(), PackageManager.GET_SIGNATURES);
|
||||
if (pkgInfo != null && pkgInfo.signatures != null) {
|
||||
return AppSigning.getSignatureString(pkgInfo.signatures, AppSigning.SHA1);
|
||||
//如果获取失败就用下面方法喽
|
||||
}else {
|
||||
PackageInfo packageInfo = pm.getPackageArchiveInfo(path, PackageManager.GET_SIGNATURES);
|
||||
if (packageInfo != null) {
|
||||
Signature[] signatures = packageInfo.signatures;
|
||||
return AppSigning.getSignatureString(signatures, AppSigning.SHA1);
|
||||
}else {
|
||||
return AppSigning.showUninstallAPKSignatures(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* //获取此包安装路径
|
||||
*/
|
||||
public static String getApkPath(Context context, String packname) {
|
||||
String path = "";
|
||||
if (!TextUtils.isEmpty(packname)) {
|
||||
try {
|
||||
//第一种方法
|
||||
ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(packname, 0);
|
||||
path = applicationInfo.sourceDir;
|
||||
//第二种方法
|
||||
// Log.e("mhyLog其他已知包名apk的安装路径", applicationInfo.sourceDir + "&---&" + applicationInfo.publicSourceDir);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
try {
|
||||
ApplicationInfo applicationInfo = context.getPackageManager().getPackageInfo(packname, PackageManager.GET_META_DATA).applicationInfo;
|
||||
path = applicationInfo.publicSourceDir;//sourceDir; // 获取当前apk包的绝对路径
|
||||
} catch (PackageManager.NameNotFoundException exception) {
|
||||
exception.printStackTrace();
|
||||
//第三中方法 本包
|
||||
path = context.getApplicationInfo().sourceDir;
|
||||
}
|
||||
// Log.e("mhyLOg在apk中获取自身安装路径", path);
|
||||
}
|
||||
} else {
|
||||
//第四中方法 本包
|
||||
path = context.getPackageResourcePath();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动构建 Context
|
||||
*/
|
||||
@SuppressLint({"DiscouragedPrivateApi","PrivateApi"})
|
||||
@SuppressLint({"DiscouragedPrivateApi", "PrivateApi"})
|
||||
public static Context createContext() throws ClassNotFoundException,
|
||||
NoSuchMethodException,
|
||||
InvocationTargetException,
|
||||
IllegalAccessException,
|
||||
NoSuchFieldException,
|
||||
NullPointerException{
|
||||
NullPointerException {
|
||||
|
||||
// 反射获取 ActivityThread 的 currentActivityThread 获取 mainThread
|
||||
Class activityThreadClass = Class.forName("android.app.ActivityThread");
|
||||
@@ -156,7 +179,8 @@ public class APISecurity {
|
||||
Object mBoundApplicationObj = mBoundApplicationField.get(mainThreadObj);
|
||||
|
||||
// 获取 mBoundApplication 的 packageInfo 变量
|
||||
if (mBoundApplicationObj == null) throw new NullPointerException("mBoundApplicationObj 反射值空");
|
||||
if (mBoundApplicationObj == null)
|
||||
throw new NullPointerException("mBoundApplicationObj 反射值空");
|
||||
Class mBoundApplicationClass = mBoundApplicationObj.getClass();
|
||||
Field infoField = mBoundApplicationClass.getDeclaredField("info");
|
||||
infoField.setAccessible(true);
|
||||
@@ -175,25 +199,58 @@ public class APISecurity {
|
||||
}
|
||||
|
||||
//需要读取应用列表权限
|
||||
public void getAppList(Context context) {
|
||||
public static List<String> getAppList(Context context) {
|
||||
List<String> list = new ArrayList<>();
|
||||
PackageManager pm = context.getPackageManager();
|
||||
List<PackageInfo> packages = pm.getInstalledPackages(0);
|
||||
// pm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);// GET_UNINSTALLED_PACKAGES代表已删除,但还有安装目录的
|
||||
for (PackageInfo packageInfo : packages) {
|
||||
// 判断系统/非系统应用
|
||||
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {// 非系统应用
|
||||
System.out.println("MainActivity.getAppList, packageInfo=" + packageInfo.packageName);
|
||||
Log.e("mhyLog", "packageInfo=" + packageInfo.packageName);
|
||||
list.add(packageInfo.packageName);
|
||||
} else {
|
||||
// 系统应用
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过已安装app 获取当前app签名
|
||||
*/
|
||||
private static String getSignSha1(Context context) {
|
||||
List<PackageInfo> apps;
|
||||
PackageManager pm = context.getPackageManager();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
apps = pm.getInstalledPackages(PackageManager.GET_SIGNING_CERTIFICATES);
|
||||
} else {
|
||||
apps = pm.getInstalledPackages(PackageManager.GET_SIGNATURES);
|
||||
}
|
||||
for (PackageInfo packageinfo : apps) {
|
||||
String packageName = packageinfo.packageName;
|
||||
if (packageName.equals(context.getPackageName())) {
|
||||
Log.e("mhyLog", "packageInfo=" + packageinfo.packageName);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
if (packageinfo.signingInfo != null) {
|
||||
return AppSigning.getSignatureString(packageinfo.signingInfo.getApkContentsSigners(), AppSigning.SHA1);
|
||||
}
|
||||
} else {
|
||||
if (packageinfo.signatures != null) {
|
||||
return AppSigning.getSignatureString(packageinfo.signatures, AppSigning.SHA1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static ArrayList<String> list = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 通过指令获取已安装的包
|
||||
*/
|
||||
private static ArrayList<String> runCommand() {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.clear();
|
||||
try {
|
||||
Process process = Runtime.getRuntime().exec("pm list package -3");
|
||||
|
||||
@@ -56,13 +56,13 @@ public class AppSigning {
|
||||
*/
|
||||
public static String getSignatureString(Signature[] sigs, @SigniType String type) {
|
||||
String fingerprint = "error!";
|
||||
if (sigs.length>0) {
|
||||
if (sigs.length > 0) {
|
||||
for (Signature sig : sigs) {
|
||||
Log.e("mhyLog", "Signature64:" + Base64.encodeToString(sig.toCharsString().getBytes(),Base64.DEFAULT));
|
||||
Log.e("mhyLog", "Signature64:" + Base64.encodeToString(sig.toCharsString().getBytes(), Base64.DEFAULT));
|
||||
}
|
||||
byte[] hexBytes = sigs[0].toByteArray();
|
||||
try {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
StringBuilder buffer = new StringBuilder();//单线程 无所谓
|
||||
MessageDigest digest = MessageDigest.getInstance(type);
|
||||
if (digest != null) {
|
||||
digest.reset();
|
||||
@@ -85,93 +85,41 @@ public class AppSigning {
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("PackageManagerGetSignatures")
|
||||
public static int getSignatureHash(Context context) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
PackageInfo pi;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int flags = PackageManager.GET_SIGNATURES;
|
||||
try {
|
||||
pi = pm.getPackageInfo(context.getPackageName(), flags);
|
||||
Signature[] signatures = pi.signatures;
|
||||
for (Signature signature : signatures) {
|
||||
sb.append(signature.toCharsString());
|
||||
Signature[] signatures;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNING_CERTIFICATES);
|
||||
if (pi != null && pi.signingInfo != null) {
|
||||
signatures = pi.signingInfo.getApkContentsSigners();
|
||||
for (Signature signature : signatures) {
|
||||
sb.append(signature.toCharsString());
|
||||
}
|
||||
return sb.toString().hashCode();
|
||||
}
|
||||
//如果 失败了继续
|
||||
}
|
||||
pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
|
||||
if (pi != null) {
|
||||
signatures = pi.signatures;
|
||||
for (Signature signature : signatures) {
|
||||
sb.append(signature.toCharsString());
|
||||
}
|
||||
return sb.toString().hashCode();
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return sb.toString().hashCode();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//这个是获取SHA1的方法 上面那个方法是获取签名的hash值 这个和cmd里面获取的是一样的
|
||||
public static String getCertificateSHA1Fingerprint(Context context) {
|
||||
//获取包管理器
|
||||
PackageManager pm = context.getPackageManager();
|
||||
//获取当前要获取SHA1值的包名,也可以用其他的包名,但需要注意,
|
||||
//在用其他包名的前提是,此方法传递的参数Context应该是对应包的上下文。
|
||||
String packageName = context.getPackageName();
|
||||
//返回包括在包中的签名信息
|
||||
int flags = PackageManager.GET_SIGNATURES;
|
||||
PackageInfo packageInfo = null;
|
||||
try {
|
||||
//获得包的所有内容信息类
|
||||
packageInfo = pm.getPackageInfo(packageName, flags);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//签名信息
|
||||
Signature[] signatures = packageInfo.signatures;
|
||||
byte[] cert = signatures[0].toByteArray();
|
||||
//将签名转换为字节数组流
|
||||
InputStream input = new ByteArrayInputStream(cert);
|
||||
//证书工厂类,这个类实现了出厂合格证算法的功能
|
||||
CertificateFactory cf = null;
|
||||
try {
|
||||
cf = CertificateFactory.getInstance("X509");
|
||||
} catch (CertificateException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//X509证书,X.509是一种非常通用的证书格式
|
||||
X509Certificate c = null;
|
||||
try {
|
||||
c = (X509Certificate) cf.generateCertificate(input);
|
||||
} catch (CertificateException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
String hexString = null;
|
||||
try {
|
||||
//加密算法的类,这里的参数可以使MD4,MD5等加密算法
|
||||
MessageDigest md = MessageDigest.getInstance("SHA1");
|
||||
//获得公钥
|
||||
byte[] publicKey = md.digest(c.getEncoded());
|
||||
//字节到十六进制的格式转换
|
||||
hexString = byte2HexFormatted(publicKey);
|
||||
} catch (NoSuchAlgorithmException e1) {
|
||||
e1.printStackTrace();
|
||||
} catch (CertificateEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return hexString;
|
||||
}
|
||||
|
||||
//这里是将获取到得编码进行16进制转换
|
||||
private static String byte2HexFormatted(byte[] arr) {
|
||||
StringBuilder str = new StringBuilder(arr.length * 2);
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
String h = Integer.toHexString(arr[i]);
|
||||
int l = h.length();
|
||||
if (l == 1)
|
||||
h = "0" + h;
|
||||
if (l > 2)
|
||||
h = h.substring(l - 2, l);
|
||||
str.append(h.toUpperCase());
|
||||
if (i < (arr.length - 1))
|
||||
str.append(':');
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
/** 防破签名 3 使原生检测签名能获取真实值 助力防破签名1而存在
|
||||
/**
|
||||
* 防破签名 3 使原生检测签名能获取真实值 助力防破签名1而存在
|
||||
* 通过重置PackageManager防止getPackageInfo方法被代理设置
|
||||
* 亲测MT管理器(当前2.9.1)的一键去签名校验(包括加强版)无效!
|
||||
* 当然如果别人反编译把代码删除的话那就没办法了
|
||||
@@ -207,11 +155,12 @@ public class AppSigning {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测 PackageManager 代理
|
||||
*/
|
||||
@SuppressLint("PrivateApi")
|
||||
public static boolean checkPMProxy(Context context){
|
||||
public static boolean checkPMProxy(Context context) {
|
||||
String truePMName = "android.content.pm.IPackageManager$Stub$Proxy";
|
||||
String nowPMName = "";
|
||||
try {
|
||||
@@ -229,7 +178,8 @@ public class AppSigning {
|
||||
return truePMName.equals(nowPMName);
|
||||
}
|
||||
|
||||
/** 防破签名 2
|
||||
/**
|
||||
* 防破签名 2
|
||||
* 安装路径获取签名
|
||||
* PackageParser 28新api
|
||||
*/
|
||||
@@ -257,9 +207,9 @@ public class AppSigning {
|
||||
Method pkgParser_parsePackageMtd = pkgParserCls.getDeclaredMethod("parsePackage", File.class, int.class);
|
||||
Object pkgParserPkg = pkgParser_parsePackageMtd.invoke(pkgParser, new File(apkPath), PackageManager.GET_SIGNATURES);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 28) {
|
||||
if (Build.VERSION.SDK_INT >= 28){
|
||||
Method pkgParser_collectCertificatesMtd = pkgParserCls.getDeclaredMethod("collectCertificates", pkgParserPkg.getClass(), Boolean.TYPE);//true skipVerify
|
||||
pkgParser_collectCertificatesMtd.invoke(pkgParser, pkgParserPkg, Build.VERSION.SDK_INT > 28);
|
||||
pkgParser_collectCertificatesMtd.invoke(pkgParser, pkgParserPkg, Build.VERSION.SDK_INT >= 28);
|
||||
|
||||
// Method pkgParser_collectCertificatesMtd = pkgParserCls.getDeclaredMethod("collectCertificates", pkgParserPkg.getClass(), Boolean.TYPE);
|
||||
// pkgParser_collectCertificatesMtd.invoke(pkgParser, pkgParserPkg, false);
|
||||
@@ -271,15 +221,14 @@ public class AppSigning {
|
||||
Field infoField = mSigningDetails.getClass().getDeclaredField("signatures");
|
||||
infoField.setAccessible(true);
|
||||
Signature[] info = (Signature[]) infoField.get(mSigningDetails);
|
||||
return info[0].toCharsString();
|
||||
|
||||
} else {
|
||||
return AppSigning.getSignatureString(info,AppSigning.SHA1);
|
||||
}else {
|
||||
Method pkgParser_collectCertificatesMtd = pkgParserCls.getDeclaredMethod("collectCertificates", pkgParserPkg.getClass(), Integer.TYPE);
|
||||
pkgParser_collectCertificatesMtd.invoke(pkgParser, pkgParserPkg, PackageManager.GET_SIGNATURES);
|
||||
|
||||
Field packageInfoFld = pkgParserPkg.getClass().getDeclaredField("mSignatures");
|
||||
Signature[] info = (Signature[]) packageInfoFld.get(pkgParserPkg);
|
||||
return info[0].toCharsString();
|
||||
return AppSigning.getSignatureString(info,AppSigning.SHA1);
|
||||
}
|
||||
|
||||
|
||||
@@ -293,7 +242,7 @@ public class AppSigning {
|
||||
// 应用程序信息包, 这个公开的, 不过有些函数, 变量没公开
|
||||
Field packageInfoFld = pkgParserPkg.getClass().getDeclaredField("mSignatures");
|
||||
Signature[] info = (Signature[]) packageInfoFld.get(pkgParserPkg);
|
||||
return info[0].toCharsString();
|
||||
return AppSigning.getSignatureString(info,AppSigning.SHA1);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e("getAPKSignatures", e.getMessage());
|
||||
@@ -302,5 +251,60 @@ public class AppSigning {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String showUninstallAPKSignatures(String apkPath) {
|
||||
String PATH_PackageParser = "android.content.pm.PackageParser";
|
||||
try {
|
||||
// apk包的文件路径
|
||||
// 这是一个Package 解释器, 是隐藏的
|
||||
// 构造函数的参数只有一个, apk文件的路径
|
||||
// PackageParser packageParser = new PackageParser(apkPath);
|
||||
Class pkgParserCls = Class.forName(PATH_PackageParser);
|
||||
Class[] typeArgs = new Class[1];
|
||||
typeArgs[0] = String.class;
|
||||
Constructor pkgParserCt = pkgParserCls.getConstructor(typeArgs);
|
||||
Object[] valueArgs = new Object[1];
|
||||
valueArgs[0] = apkPath;
|
||||
Object pkgParser = pkgParserCt.newInstance(valueArgs);
|
||||
// MediaApplication.logD(DownloadApk.class, "pkgParser:" + pkgParser.toString());
|
||||
// 这个是与显示有关的, 里面涉及到一些像素显示等等, 我们使用默认的情况
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
metrics.setToDefaults();
|
||||
// PackageParser.Package mPkgInfo = packageParser.parsePackage(new
|
||||
// File(apkPath), apkPath,
|
||||
// metrics, 0);
|
||||
typeArgs = new Class[4];
|
||||
typeArgs[0] = File.class;
|
||||
typeArgs[1] = String.class;
|
||||
typeArgs[2] = DisplayMetrics.class;
|
||||
typeArgs[3] = Integer.TYPE;
|
||||
Method pkgParser_parsePackageMtd = pkgParserCls.getDeclaredMethod("parsePackage",
|
||||
typeArgs);
|
||||
valueArgs = new Object[4];
|
||||
valueArgs[0] = new File(apkPath);
|
||||
valueArgs[1] = apkPath;
|
||||
valueArgs[2] = metrics;
|
||||
valueArgs[3] = PackageManager.GET_SIGNATURES;
|
||||
Object pkgParserPkg = pkgParser_parsePackageMtd.invoke(pkgParser, valueArgs);
|
||||
|
||||
typeArgs = new Class[2];
|
||||
typeArgs[0] = pkgParserPkg.getClass();
|
||||
typeArgs[1] = Integer.TYPE;
|
||||
Method pkgParser_collectCertificatesMtd = pkgParserCls.getDeclaredMethod("collectCertificates",
|
||||
typeArgs);
|
||||
valueArgs = new Object[2];
|
||||
valueArgs[0] = pkgParserPkg;
|
||||
valueArgs[1] = PackageManager.GET_SIGNATURES;
|
||||
pkgParser_collectCertificatesMtd.invoke(pkgParser, valueArgs);
|
||||
// 应用程序信息包, 这个公开的, 不过有些函数, 变量没公开
|
||||
Field packageInfoFld = pkgParserPkg.getClass().getDeclaredField("mSignatures");
|
||||
Signature[] info = (Signature[]) packageInfoFld.get(pkgParserPkg);
|
||||
// MediaApplication.logD(DownloadApk.class, "size:"+info.length);
|
||||
// MediaApplication.logD(DownloadApk.class, info[0].toCharsString());
|
||||
return AppSigning.getSignatureString(info,AppSigning.SHA1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public class InitProvider extends ContentProvider {
|
||||
}
|
||||
Log.e("mhyLog", "initContentProvider:");
|
||||
// chekSignature(application);
|
||||
checkApplication();
|
||||
//checkApplication();
|
||||
return true;
|
||||
}
|
||||
void chekSignature(Context application){
|
||||
@@ -54,11 +54,13 @@ public class InitProvider extends ContentProvider {
|
||||
/**
|
||||
* 校验 application
|
||||
*/
|
||||
|
||||
private boolean checkApplication(){
|
||||
//在这里使用反射 获取比较靠谱 如果 被替换换 就查出来了
|
||||
Application nowApplication = getApplicationByReflect();
|
||||
String trueApplicationName = "MyApplication";//自己的Application类名 防止替换
|
||||
String nowApplicationName = nowApplication.getClass().getSimpleName();
|
||||
APISecurity.verifyApp(nowApplication);
|
||||
String trueApplicationName = "cn.android.sample.MyApplication";//getSimpleName()自己的Application类名 防止替换
|
||||
String nowApplicationName = nowApplication.getClass().getName();
|
||||
Log.e("mhyLogAppName", "反射获取:"+nowApplicationName);
|
||||
return trueApplicationName.equals(nowApplicationName);
|
||||
}
|
||||
|
||||
@@ -17,13 +17,14 @@
|
||||
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG,__VA_ARGS__)
|
||||
|
||||
//此处改为你的APP签名
|
||||
#define SHA1 "a8e3d91a4f77dd7ccb8d43ee5046a4b6833f4785"//真实test.keystore
|
||||
//#define SHA1 "04c1411b0662acd9e4aa300559677e5f106a5255"//区分da小写
|
||||
//#define SHA1 "a8e3d91a4f77dd7ccb8d43ee5046a4b6833f4785"//真实test.keystore
|
||||
#define SHA1 "04c1411b0662acd9e4aa300559677e5f106a5255"//区分da小写 55
|
||||
#define ALGORITHM_SHA1 "SHA1"
|
||||
#define ALGORITHM_MD5 "MD5"
|
||||
|
||||
//此处改为你的APP包名
|
||||
#define APP_PKG "cn.android.sample"
|
||||
#define APPLICATION_NAME "cn.android.sample.MyApplication"
|
||||
//此处填写API盐值
|
||||
#define API_SECRET "ABC1234567"//设置api 密钥 MD5加盐
|
||||
|
||||
@@ -109,9 +110,14 @@ jobject getPackageInfo(JNIEnv *env, jobject package_manager, jstring package_nam
|
||||
jmethodID methodId = env->GetMethodID(pack_manager_class, "getPackageInfo",
|
||||
"(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
|
||||
env->DeleteLocalRef(pack_manager_class);
|
||||
|
||||
jobject package_info = env->CallObjectMethod(package_manager, methodId, package_name,
|
||||
0x40);//安卓10 0x80
|
||||
jobject package_info;
|
||||
if (version() >= 28) {
|
||||
package_info = env->CallObjectMethod(package_manager, methodId, package_name,
|
||||
0x08000000);//安卓9 0x08000000
|
||||
} else {
|
||||
package_info = env->CallObjectMethod(package_manager, methodId, package_name,
|
||||
0x00000040);//安卓9 0x08000000
|
||||
}
|
||||
return package_info;
|
||||
}
|
||||
|
||||
@@ -123,7 +129,8 @@ jobject getPackageInfoArchive(JNIEnv *env, jobject package_manager, jstring apkP
|
||||
jmethodID methodId = env->GetMethodID(pack_manager_class, "getPackageArchiveInfo",
|
||||
"(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
|
||||
env->DeleteLocalRef(pack_manager_class);
|
||||
jobject package_info = env->CallObjectMethod(package_manager, methodId, apkPath, 0x40);
|
||||
jobject package_info = env->CallObjectMethod(package_manager, methodId, apkPath,
|
||||
0x00000040);//0x08000000
|
||||
return package_info;
|
||||
}
|
||||
|
||||
@@ -177,19 +184,26 @@ jstring getAbsolutePath(JNIEnv *env, jobject package_info) {
|
||||
|
||||
/**
|
||||
* 获取签名信息
|
||||
* ;
|
||||
//jint sdk = getDeviceVersion(env);
|
||||
jint sdk = version();
|
||||
if (sdk >= 28) {
|
||||
LOGE("sdk版本%d", sdk);
|
||||
signature_object = getSignature28(env, package_info);
|
||||
}
|
||||
*/
|
||||
//需要sdk28 新API
|
||||
jobject getSignature28(JNIEnv *env, jobject package_info) {
|
||||
jclass package_info_class = env->GetObjectClass(package_info);
|
||||
jclass package_info_class = env->FindClass("android/content/pm/PackageInfo");
|
||||
jfieldID signingInfo = env->GetFieldID(package_info_class, "signingInfo",
|
||||
"Landroid/content/pm/SigningInfo;");
|
||||
"Landroid/content/pm/SigningInfo;");
|
||||
env->DeleteLocalRef(package_info_class);
|
||||
jobject signingInfo_object = env->GetObjectField(package_info, signingInfo);
|
||||
LOGE("%s", "fieldId:signingInfo");
|
||||
if (signingInfo_object == nullptr) {
|
||||
LOGE("fsigningInfo_object空");
|
||||
return nullptr;//为空咋回事?
|
||||
}
|
||||
// jclass signingInfo_class = env->GetObjectClass(signingInfo_object);
|
||||
jclass signingInfo_class = env->FindClass("android/content/pm/SigningInfo");
|
||||
jmethodID methodId = env->GetMethodID(signingInfo_class, "getApkContentsSigners",
|
||||
"()[Landroid/content/pm/Signature;");
|
||||
@@ -197,17 +211,14 @@ jobject getSignature28(JNIEnv *env, jobject package_info) {
|
||||
jobjectArray signature_object_array = (jobjectArray) env->CallObjectMethod(signingInfo_object,
|
||||
methodId);
|
||||
LOGE("%s", "methodId:getApkContentsSigners");
|
||||
if (signature_object_array == nullptr)
|
||||
if (signature_object_array == nullptr){
|
||||
LOGE("signature_object_array空");
|
||||
return nullptr;
|
||||
}
|
||||
return env->GetObjectArrayElement(signature_object_array, 0);
|
||||
}
|
||||
|
||||
jobject getSignature(JNIEnv *env, jobject package_info) {
|
||||
// jint sdk = getDeviceVersion(env);
|
||||
// if (sdk >= 28) {
|
||||
// LOGE("sdk版本%d", sdk);
|
||||
// return getSignature28(env, package_info);
|
||||
// }
|
||||
jclass package_info_class = env->GetObjectClass(package_info);
|
||||
jfieldID fieldId = env->GetFieldID(package_info_class, "signatures",
|
||||
"[Landroid/content/pm/Signature;");
|
||||
@@ -315,14 +326,22 @@ Java_cn_android_security_APISecurity_init(
|
||||
|
||||
//获取PackageInfo对象
|
||||
jobject package_info = getPackageInfo(env, package_manager, package_name);
|
||||
if (package_info == nullptr)
|
||||
if (package_info == nullptr){
|
||||
LOGE("package_info空");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
env->DeleteLocalRef(package_manager);
|
||||
|
||||
//获取签名信息
|
||||
jobject signature_object = getSignature(env, package_info);
|
||||
if (signature_object == nullptr)
|
||||
//获取签名信息
|
||||
jobject signature_object;
|
||||
if (version() >= 28) {
|
||||
signature_object = getSignature28(env, package_info);
|
||||
} else {
|
||||
signature_object = getSignature(env, package_info);
|
||||
}
|
||||
if (signature_object == nullptr){
|
||||
LOGE("signature_object空");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
env->DeleteLocalRef(package_info);
|
||||
jbyteArray cert_byte = getSHA1(env, signature_object);
|
||||
|
||||
@@ -356,8 +375,8 @@ Java_cn_android_security_APISecurity_init(
|
||||
return JNI_FALSE;
|
||||
}
|
||||
//调用Java方法
|
||||
jstring sigin = static_cast<jstring>(env->CallStaticObjectMethod(cls_util, mtd_static_method,
|
||||
context_object, package_name));
|
||||
jstring sigin = (jstring) env->CallStaticObjectMethod(cls_util, mtd_static_method,
|
||||
context_object, package_name);
|
||||
const char *ss = env->GetStringUTFChars(sigin, nullptr);
|
||||
//删除引用
|
||||
env->DeleteLocalRef(cls_util);
|
||||
@@ -432,66 +451,42 @@ Java_cn_android_security_APISecurity_sign(
|
||||
return env->NewStringUTF(sign);
|
||||
}
|
||||
|
||||
//extern "C"
|
||||
//JNIEXPORT jboolean JNICALL
|
||||
//Java_cn_android_security_APISecurity_check(JNIEnv *env, jclass clazz, jstring str) {
|
||||
// const char *sx;
|
||||
// sx = env->GetStringUTFChars(str, nullptr);
|
||||
// char name[512];
|
||||
// strcpy(name, sx);
|
||||
//
|
||||
// return 0 == strcmp(SHA1, "md5");
|
||||
//}
|
||||
|
||||
//APISecurity.adbshell("pm list package -3",getFilesDir().getPath() + File.separator + "files"+File.separator + "adbshell.txt");
|
||||
//extern "C" JNIEXPORT jstring JNICALL
|
||||
//Java_cn_android_security_APISecurity_adbshell(JNIEnv *env, jclass clazz, jstring str,
|
||||
// jstring path) {
|
||||
// int ret = system("pm list package -3");//获取安装应用
|
||||
// char *str2 = (char *) env->GetStringUTFChars(str, nullptr);
|
||||
// char *path2 = (char *) env->GetStringUTFChars(path, nullptr);
|
||||
// strcat(str2, " > ");
|
||||
// strcat(str2, path2);
|
||||
// system(str2);
|
||||
// return env->NewStringUTF(str2);
|
||||
//}
|
||||
|
||||
/*1.调试端口检测
|
||||
读取/proc/net/tcp,查找IDA远程调试所用的23946端口,若发现说明进程正在被IDA调试。*/
|
||||
void CheckPort23946ByTcp() {
|
||||
/**1.调试端口检测 读取/proc/net/tcp,查找IDA远程调试所用的23946端口,若发现说明进程正在被IDA调试。*/
|
||||
void checkPort23946ByTcp() {
|
||||
FILE *pfile = nullptr;
|
||||
char buf[0x1000] = {0};
|
||||
// 执行命令
|
||||
char *strCatTcp = "cat /proc/net/tcp |grep :5D8A";//5D8A转化成十进制就是23946
|
||||
//char* strNetstat="netstat |grep :23946";
|
||||
// 执行命令//5D8A转化成十进制就是23946
|
||||
char *strCatTcp = "cat /proc/net/tcp |grep :5D8A";
|
||||
//打开进程 去执行 char* strNetstat="netstat |grep :23946";
|
||||
pfile = popen(strCatTcp, "r");
|
||||
if (nullptr == pfile) {
|
||||
LOGD("CheckPort23946ByTcp popen打开命令失败!\n");
|
||||
LOGD("checkPort23946ByTcp popen打开命令失败!\n");
|
||||
return;
|
||||
}
|
||||
// 获取结果
|
||||
while (fgets(buf, sizeof(buf), pfile)) {
|
||||
// 执行到这里,判定为调试状态
|
||||
LOGD("执行cat /proc/net/tcp |grep :5D8A的结果:\n");
|
||||
LOGD("%s", buf);
|
||||
LOGD("执行cat strCatTcp的结果:\n %s", buf);
|
||||
isInit = false;
|
||||
}//while
|
||||
pclose(pfile);
|
||||
pclose(pfile);//关闭由popen打开的进程
|
||||
}
|
||||
|
||||
|
||||
/*5.APK线程检测
|
||||
/**5.APK线程检测
|
||||
正常apk进程一般会有十几个线程在运行(比如会有jdwp线程),
|
||||
自己写可执行文件加载so一般只有一个线程,
|
||||
可以根据这个差异来进行调试环境检测*/
|
||||
可以根据这个差异来进行调试环境检测
|
||||
*/
|
||||
|
||||
void CheckTaskCount() {
|
||||
void checkTaskCount() {
|
||||
char buf[0x100] = {0};
|
||||
char *str = "/proc/%d/task";
|
||||
snprintf(buf, sizeof(buf), str, getpid());
|
||||
// 打开目录:
|
||||
DIR *pdir = opendir(buf);
|
||||
if (!pdir) {
|
||||
perror("CheckTaskCount open() fail.\n");
|
||||
perror("checkTaskCount open() fail.\n");
|
||||
return;
|
||||
}
|
||||
// 查看目录下文件个数:
|
||||
@@ -507,9 +502,28 @@ void CheckTaskCount() {
|
||||
LOGD("线程个数为:%d", Count);
|
||||
if (1 >= Count) {
|
||||
// 此处判定为调试状态.
|
||||
LOGD("调试状态!\n");
|
||||
LOGD("调试状态!");
|
||||
isInit = false;
|
||||
}
|
||||
int i = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Application.getClass().getName();
|
||||
*/
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_cn_android_security_APISecurity_verifyApp(JNIEnv *env, jclass clazz,
|
||||
jobject application_by_reflect) {
|
||||
// jclass application_clazz=env->GetObjectClass(application_by_reflect);
|
||||
jclass object_clazz = env->FindClass("java/lang/Object");
|
||||
jmethodID getClass = env->GetMethodID(object_clazz, "getClass", "()Ljava/lang/Class;");
|
||||
jobject clazz_object = env->CallObjectMethod(application_by_reflect, getClass);
|
||||
jclass mClazz = env->FindClass("java/lang/Class");
|
||||
jmethodID getNameId = env->GetMethodID(mClazz, "getName", "()Ljava/lang/String;");
|
||||
jstring appname = (jstring) env->CallObjectMethod(clazz_object, getNameId);
|
||||
const char *ss = env->GetStringUTFChars(appname, nullptr);
|
||||
if (strcmp(ss, APPLICATION_NAME) != 0) {
|
||||
LOGE("非法调用5,SHA1: %s", ss);
|
||||
isInit = false;
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,6 @@ import cn.android.security.APISecurity;
|
||||
public class MyApplication extends Application implements InvocationHandler {
|
||||
private static final int GET_SIGNATURES = 64;
|
||||
private String appPkgName = "";
|
||||
private String appPath = "";
|
||||
private Object base;
|
||||
private byte[][] sign;
|
||||
static MyApplication app;
|
||||
@@ -63,7 +62,7 @@ public class MyApplication extends Application implements InvocationHandler {
|
||||
@Override
|
||||
protected void attachBaseContext(Context context) {
|
||||
//在这里hook 签名校验被
|
||||
// hook(context);
|
||||
hook(context);
|
||||
super.attachBaseContext(context);
|
||||
}
|
||||
|
||||
@@ -71,10 +70,7 @@ public class MyApplication extends Application implements InvocationHandler {
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
app = this;
|
||||
Application nowApplication = app;
|
||||
// SystemProperties.getInt("ro.build.version.sdk", 0);
|
||||
//再这看 不一定靠谱
|
||||
Log.e("mhyLog","检查App名:"+nowApplication.getClass().getSimpleName());
|
||||
//在签名校验被hook 之后重置PackageManager
|
||||
/*在这里 重置PackageManager 只要在验证前重置即可*/
|
||||
// AppSigning.resetPackageManager(getBaseContext());
|
||||
@@ -107,7 +103,6 @@ public class MyApplication extends Application implements InvocationHandler {
|
||||
this.base = obj;
|
||||
this.sign = bArr;
|
||||
this.appPkgName = context.getPackageName();
|
||||
this.appPath = context.getPackageResourcePath();
|
||||
Object newProxyInstance = Proxy.newProxyInstance(cls2.getClassLoader(), new Class[]{cls2}, this);
|
||||
declaredField.set(invoke, newProxyInstance);
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
@@ -126,102 +121,58 @@ public class MyApplication extends Application implements InvocationHandler {
|
||||
public Object invoke(Object obj, Method method, Object[] objArr) throws Throwable {
|
||||
if ("getPackageInfo".equals(method.getName())) {//方法名对上
|
||||
Log.e("mhyLogHook","getPackageInfo");
|
||||
String str = (String) objArr[0];
|
||||
if ((((Integer) objArr[1]).intValue() & 64) != 0 && this.appPkgName.equals(str)) {
|
||||
String packageName = (String) objArr[0];//64 134217728
|
||||
// int flag=((Integer) objArr[1]).intValue();
|
||||
if (this.appPkgName.equals(packageName)) {
|
||||
PackageInfo packageInfo = (PackageInfo) method.invoke(this.base, objArr);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
//packageInfo.signingInfo.getApkContentsSigners();//mSigningDetails.signatures
|
||||
//mSigningDetails.signatures;//PackageParser.SigningDetails
|
||||
SigningInfo signingInfo= packageInfo.signingInfo;
|
||||
// Class<?> sgInfo_clazz=SigningInfo.class;//getClass()&Class.forName(“类完整的路径”)仅限于引用类型的对象
|
||||
// Field mSigningDetails_f=sgInfo_clazz.getDeclaredField("mSigningDetails");
|
||||
// mSigningDetails_f.setAccessible(true);
|
||||
// Object mSigningDetails = mSigningDetails_f.get(signingInfo);//PackageParser.SigningDetails
|
||||
|
||||
Class<?> pkgParserCls = Class.forName("android.content.pm.PackageParser");
|
||||
Constructor<?> pkgParserCt = pkgParserCls.getConstructor();//null;
|
||||
Object pkgParser = pkgParserCt.newInstance();//null;
|
||||
// pkgParserCt =
|
||||
// pkgParser =
|
||||
Method pkgParser_parsePackageMtd = pkgParserCls.getDeclaredMethod("parsePackage", File.class, int.class);
|
||||
Object pkgParserPkg = pkgParser_parsePackageMtd.invoke(pkgParser, new File(getPackageResourcePath()), PackageManager.GET_SIGNING_CERTIFICATES);
|
||||
|
||||
Method pkgParser_collectCertificatesMtd = pkgParserCls.getDeclaredMethod("collectCertificates", pkgParserPkg.getClass(), Boolean.TYPE);
|
||||
pkgParser_collectCertificatesMtd.invoke(pkgParser, pkgParserPkg, true);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P &&(((Integer) objArr[1]).intValue() & 134217728) != 0) {
|
||||
//packageInfo.signingInfo.getApkContentsSigners();//mSigningDetails.signatures
|
||||
//mSigningDetails.signatures;//PackageParser.SigningDetails
|
||||
SigningInfo signingInfo= packageInfo.signingInfo;//有坑空
|
||||
/*1*/
|
||||
Class<?> sgInfo_clazz=Class.forName("android.content.pm.SigningInfo");//getClass()&Class.forName(“类完整的路径”)仅限于引用类型的对象
|
||||
Field mSigningDetails_f=sgInfo_clazz.getDeclaredField("mSigningDetails");
|
||||
mSigningDetails_f.setAccessible(true);
|
||||
Object mSigningDetails = mSigningDetails_f.get(signingInfo);//PackageParser.SigningDetails
|
||||
/*2*/
|
||||
// Class<?> pkgParserCls = Class.forName("android.content.pm.PackageParser");
|
||||
// Constructor<?> pkgParserCt = pkgParserCls.getConstructor();
|
||||
// Object pkgParser = pkgParserCt.newInstance();
|
||||
// Method pkgParser_parsePackageMtd = pkgParserCls.getDeclaredMethod("parsePackage", File.class, int.class);
|
||||
// Object pkgParserPkg = pkgParser_parsePackageMtd.invoke(pkgParser, new File(getPackageResourcePath()), PackageManager.GET_SIGNING_CERTIFICATES);
|
||||
//
|
||||
// Method pkgParser_collectCertificatesMtd = pkgParserCls.getDeclaredMethod("collectCertificates", pkgParserPkg.getClass(), Boolean.TYPE);
|
||||
// pkgParser_collectCertificatesMtd.invoke(pkgParser, pkgParserPkg, false);
|
||||
|
||||
Field mSigningDetailsField = pkgParserPkg.getClass().getDeclaredField("mSigningDetails"); // SigningDetails
|
||||
mSigningDetailsField.setAccessible(true);
|
||||
Object mSigningDetails = mSigningDetailsField.get(pkgParserPkg);
|
||||
|
||||
Field infoField = mSigningDetails.getClass().getDeclaredField("signatures");
|
||||
infoField.setAccessible(true);
|
||||
//
|
||||
//// Method pkgParser_collectCertificatesMtd = pkgParserCls.getDeclaredMethod("collectCertificates", pkgParserPkg.getClass(), Boolean.TYPE);
|
||||
//// pkgParser_collectCertificatesMtd.invoke(pkgParser, pkgParserPkg, false);
|
||||
//
|
||||
// Field mSigningDetailsField = pkgParserPkg.getClass().getDeclaredField("mSigningDetails"); // SigningDetails
|
||||
// mSigningDetailsField.setAccessible(true);
|
||||
// Object mSigningDetails = mSigningDetailsField.get(pkgParserPkg);
|
||||
/*end*/
|
||||
Class<?> sd=Class.forName("android.content.pm.PackageParser$SigningDetails");
|
||||
//PackageParser.SigningDetails.signatures 这是一个final属性 只有在 new SigningDetails(...)时
|
||||
Field infoField = /*mSigningDetails.getClass()*/sd.getField("signatures");
|
||||
Signature[] info = new Signature[this.sign.length];
|
||||
for (int i = 0; i < this.sign.length; i++) {
|
||||
info[i] = new Signature(this.sign[i]);
|
||||
}
|
||||
// Signature[] info = (Signature[]) infoField.get(mSigningDetails);//获取属性值
|
||||
infoField.set(mSigningDetails, info);
|
||||
}// else { //双hook
|
||||
Signature[] info2 = signingInfo.getApkContentsSigners();//获取属性值
|
||||
if (info2.length>0){
|
||||
Log.e("mhyLogHook2",info2[0].toCharsString());}
|
||||
} else { //双hook
|
||||
// if ((((Integer) objArr[1]).intValue() & 64) != 0){
|
||||
packageInfo.signatures = new Signature[this.sign.length];
|
||||
for (int i = 0; i < packageInfo.signatures.length; i++) {
|
||||
packageInfo.signatures[i] = new Signature(this.sign[i]);
|
||||
// }
|
||||
}
|
||||
return packageInfo;
|
||||
}
|
||||
|
||||
}
|
||||
if ("getPackageArchiveInfo".equals(method.getName())) {//从安装路径获取apk签名方法
|
||||
Log.e("mhyLogHook","getPackageArchiveInfo");
|
||||
// getPackageArchiveInfo(String archiveFilePath, @PackageInfoFlags int flags)
|
||||
String str = (String) objArr[0];//第一个参数
|
||||
if ((((Integer) objArr[1]).intValue() & 64) != 0 && this.appPath.equals(str)) {
|
||||
PackageInfo packageInfo = (PackageInfo) method.invoke(this.base, objArr);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
SigningInfo signingInfo= packageInfo.signingInfo;
|
||||
// Class<?> sgInfo_clazz=SigningInfo.class;
|
||||
// Field mSigningDetails_f=sgInfo_clazz.getDeclaredField("mSigningDetails");
|
||||
// mSigningDetails_f.setAccessible(true);
|
||||
// Object mSigningDetails = mSigningDetails_f.get(signingInfo);
|
||||
|
||||
Class<?> pkgParserCls = Class.forName("android.content.pm.PackageParser");
|
||||
Constructor<?> pkgParserCt = pkgParserCls.getConstructor();//null;
|
||||
Object pkgParser = pkgParserCt.newInstance();//null;
|
||||
// pkgParserCt =
|
||||
// pkgParser =
|
||||
Method pkgParser_parsePackageMtd = pkgParserCls.getDeclaredMethod("parsePackage", File.class, int.class);
|
||||
Object pkgParserPkg = pkgParser_parsePackageMtd.invoke(pkgParser, new File(getPackageResourcePath()), PackageManager.GET_SIGNING_CERTIFICATES);
|
||||
|
||||
Method pkgParser_collectCertificatesMtd = pkgParserCls.getDeclaredMethod("collectCertificates", pkgParserPkg.getClass(), Boolean.TYPE);
|
||||
pkgParser_collectCertificatesMtd.invoke(pkgParser, pkgParserPkg, true);
|
||||
|
||||
// Method pkgParser_collectCertificatesMtd = pkgParserCls.getDeclaredMethod("collectCertificates", pkgParserPkg.getClass(), Boolean.TYPE);
|
||||
// pkgParser_collectCertificatesMtd.invoke(pkgParser, pkgParserPkg, false);
|
||||
|
||||
Field mSigningDetailsField = pkgParserPkg.getClass().getDeclaredField("mSigningDetails"); // SigningDetails
|
||||
mSigningDetailsField.setAccessible(true);
|
||||
Object mSigningDetails = mSigningDetailsField.get(pkgParserPkg);
|
||||
|
||||
Field infoField = mSigningDetails.getClass().getDeclaredField("signatures");
|
||||
infoField.setAccessible(true);
|
||||
Signature[] info = new Signature[this.sign.length];
|
||||
for (int i = 0; i < this.sign.length; i++) {
|
||||
info[i] = new Signature(this.sign[i]);
|
||||
}
|
||||
// Signature[] info = (Signature[]) infoField.get(mSigningDetails);//获取属性值
|
||||
infoField.set(mSigningDetails, info);
|
||||
} //else { //双hook
|
||||
packageInfo.signatures = new Signature[this.sign.length];
|
||||
for (int i = 0; i < packageInfo.signatures.length; i++) {
|
||||
packageInfo.signatures[i] = new Signature(this.sign[i]);
|
||||
// }
|
||||
}
|
||||
return packageInfo;
|
||||
}
|
||||
}
|
||||
// IPackageManager 中无getPackageArchiveInfo 方法无法代理
|
||||
return method.invoke(this.base, objArr);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user