hook getPackageArchiveInfo无效

hook 参数区分 64 & ((Integer) objArr[1]).intValue()
This commit is contained in:
mahongyin
2021-03-04 18:08:45 +08:00
parent 798efbb1d1
commit 5728c6befc
6 changed files with 325 additions and 288 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -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("非法调用5SHA1: %s", ss);
isInit = false;
}
}

View File

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