hooK 1 2成功

This commit is contained in:
mahongyin
2021-03-05 16:51:58 +08:00
parent 5728c6befc
commit 723fc45565
12 changed files with 210 additions and 65 deletions

View File

@@ -551,3 +551,90 @@ versionI() {
net. bt. name=Android (系统名称)
dalvik.vm.stack-trace-file=/data/anr/traces.txt
```
Class.newInstance();只能反射无参的构造器,需要构造器可见;
Constructor.newInstance();可以反射任何构造器,可以反射私有构造器
```
public class Student {
private String name;
private int age;
private double score;
public Student() {}
private Student(String name, int age, double score) {
this.name = name;
this.age = age;
this.score = score;
}
}
```
```
public class Client {
public static void main(String[] args) throws Exception {
Class clazz = Student.class;
//利用Class.newInstance()
Object object1 = clazz.newInstance();
System.out.println(object1);
//利用Constructor.newInstance()反射无参构造方法
Constructor cons1 = clazz.getDeclaredConstructor();
Object object2 = cons1.newInstance();
//利用Constructor.newInstance()反射私有构造方法
Constructor cons2 = clazz.getDeclaredConstructor(String.class,Integer.TYPE,Double.TYPE);
if(!cons2.isAccessible())
cons2.setAccessible(true);
Object object3 = cons2.newInstance("张三",12,88.5);
}
}
```
Java除了这两这种方法创建对象外还有三个方式使用new 关键字使用对象克隆clone()方法以及使用反序列化ObjectInputStream的 readObject() 方法。
使用 clone()方法类必须实现Cloneable接口并重写其clone()方法
使用反序列化ObjectInputStream 的readObject()方法:类必须实现 Serializable接口
```
public class Student implements Serializable,Cloneable{
private static final long serialVersionUID = -2263090506226622866L;
private String name;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
}
public class Client {
public static void main(String[] args) throws Exception {
//使用new关键字创建对象
Student student1 = new Student();
//使用clone()方法类必须实现Cloneable接口并重写其clone()方法
Student student2 = (Student) student1.clone();
// 使用 反序列化ObjectInputStream的readObject()方法:类必须实现 Serializable接口
// 序列化
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.txt"));
objectOutputStream.writeObject(student1);
// 反序列化
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test.txt"));
Student student3 = (Student) objectInputStream.readObject();
}
}
```
记得之前写过一篇 单例模式 的博客其中最后就提到序列化也会破坏单例就是因为反序列化会创建新的对象所以我们在单例模式中要有readResolve()方法。

View File

@@ -61,7 +61,7 @@ public class APISecurity {
// Log.e("mhyLog", "hash:" + AppSigning.getSignatureHash(context));
// Log.e("mhyLog", "sha1:" + getSignSha1(context));
//runCommand();
Log.e("mhyLog包文件", "签名:"+getApkSignatures(context, context.getPackageName()));
// Log.e("mhyLog包文件", "签名:"+getApkSignatures(context, context.getPackageName()));
//Log.e("mhyLog已安装", "签名:"+getInstalledAPKSignature(context, context.getPackageName()));
//通过获取其他应用的签名 如果一样那么被hook了
}

View File

@@ -58,7 +58,8 @@ public class AppSigning {
String fingerprint = "error!";
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));
Log.e("mhyLog", "SignatureHash:" + sig.toCharsString().hashCode());
}
byte[] hexBytes = sigs[0].toByteArray();
try {

View File

@@ -165,7 +165,6 @@
"project": {
"compilerSettingsCacheFolder": "G:\\AProject\\Mahy\\API-Security\\.cxx",
"cxxFolder": "G:\\AProject\\Mahy\\API-Security\\.cxx",
"ideBuildTargetAbi": "arm64-v8a,armeabi-v7a,armeabi",
"isBuildOnlyTargetAbiEnabled": true,
"isCmakeBuildCohabitationEnabled": false,
"isNativeCompilerSettingsCacheEnabled": false,
@@ -188,8 +187,10 @@
"objFolder": "G:\\AProject\\Mahy\\API-Security\\app\\build\\intermediates\\cmake\\release\\obj",
"variantName": "release",
"validAbiList": [
"ARMEABI_V7A",
"ARM64_V8A",
"ARMEABI_V7A"
"X86",
"X86_64"
]
}
}

View File

@@ -165,7 +165,6 @@
"project": {
"compilerSettingsCacheFolder": "G:\\AProject\\Mahy\\API-Security\\.cxx",
"cxxFolder": "G:\\AProject\\Mahy\\API-Security\\.cxx",
"ideBuildTargetAbi": "arm64-v8a,armeabi-v7a,armeabi",
"isBuildOnlyTargetAbiEnabled": true,
"isCmakeBuildCohabitationEnabled": false,
"isNativeCompilerSettingsCacheEnabled": false,
@@ -188,8 +187,10 @@
"objFolder": "G:\\AProject\\Mahy\\API-Security\\app\\build\\intermediates\\cmake\\release\\obj",
"variantName": "release",
"validAbiList": [
"ARMEABI_V7A",
"ARM64_V8A",
"ARMEABI_V7A"
"X86",
"X86_64"
]
}
}

View File

@@ -11,6 +11,18 @@
"file": "G:\\AProject\\Mahy\\API-Security\\app\\CMakeLists.txt",
"tag": "release|armeabi-v7a"
},
{
"level": "INFO",
"message": "Trying to locate CMake in local SDK repository.",
"file": "G:\\AProject\\Mahy\\API-Security\\app\\CMakeLists.txt",
"tag": "release|armeabi-v7a"
},
{
"level": "INFO",
"message": "- CMake found in SDK at \u0027D:\\android-sdk-windows\\cmake\\3.10.2.4988404\u0027 had version \u00273.10.2\u0027",
"file": "G:\\AProject\\Mahy\\API-Security\\app\\CMakeLists.txt",
"tag": "release|armeabi-v7a"
},
{
"level": "INFO",
"message": "JSON \u0027G:\\AProject\\Mahy\\API-Security\\app\\.cxx\\cmake\\release\\armeabi-v7a\\android_gradle_build.json\u0027 was up-to-date",

View File

@@ -11,6 +11,18 @@
"file": "G:\\AProject\\Mahy\\API-Security\\app\\CMakeLists.txt",
"tag": "release|x86"
},
{
"level": "INFO",
"message": "Trying to locate CMake in local SDK repository.",
"file": "G:\\AProject\\Mahy\\API-Security\\app\\CMakeLists.txt",
"tag": "release|x86"
},
{
"level": "INFO",
"message": "- CMake found in SDK at \u0027D:\\android-sdk-windows\\cmake\\3.10.2.4988404\u0027 had version \u00273.10.2\u0027",
"file": "G:\\AProject\\Mahy\\API-Security\\app\\CMakeLists.txt",
"tag": "release|x86"
},
{
"level": "INFO",
"message": "JSON \u0027G:\\AProject\\Mahy\\API-Security\\app\\.cxx\\cmake\\release\\x86\\android_gradle_build.json\u0027 was up-to-date",

View File

@@ -11,6 +11,18 @@
"file": "G:\\AProject\\Mahy\\API-Security\\app\\CMakeLists.txt",
"tag": "release|x86_64"
},
{
"level": "INFO",
"message": "Trying to locate CMake in local SDK repository.",
"file": "G:\\AProject\\Mahy\\API-Security\\app\\CMakeLists.txt",
"tag": "release|x86_64"
},
{
"level": "INFO",
"message": "- CMake found in SDK at \u0027D:\\android-sdk-windows\\cmake\\3.10.2.4988404\u0027 had version \u00273.10.2\u0027",
"file": "G:\\AProject\\Mahy\\API-Security\\app\\CMakeLists.txt",
"tag": "release|x86_64"
},
{
"level": "INFO",
"message": "JSON \u0027G:\\AProject\\Mahy\\API-Security\\app\\.cxx\\cmake\\release\\x86_64\\android_gradle_build.json\u0027 was up-to-date",

View File

@@ -53,7 +53,7 @@ android {
path "CMakeLists.txt"
}
}
sourceSets.main.jniLibs.srcDirs = ['libs'] //为了直接读取 lib目录下 arm64-v8a/old.apk
}

View File

@@ -16,12 +16,12 @@
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG,__VA_ARGS__)
//此处改为你的APP签名
//#define SHA1 "a8e3d91a4f77dd7ccb8d43ee5046a4b6833f4785"//真实test.keystore
#define SHA1 "04c1411b0662acd9e4aa300559677e5f106a5255"//区分da小写 55
#define ALGORITHM_SHA1 "SHA1"
#define ALGORITHM_MD5 "MD5"
//此处改为你的APP签名
#define SHA1 "a8e3d91a4f77dd7ccb8d43ee5046a4b6833f4785"//真实test.keystore
//#define SHA1 "04c1411b0662acd9e4aa300559677e5f106a5255"//区分da小写 55
//此处改为你的APP包名
#define APP_PKG "cn.android.sample"
#define APPLICATION_NAME "cn.android.sample.MyApplication"
@@ -508,7 +508,7 @@ void checkTaskCount() {
}
/**
* Application.getClass().getName();
* Application.getClass().getName(); 验证application是否被替换
*/
extern "C"
JNIEXPORT void JNICALL

View File

@@ -21,19 +21,19 @@ public class MainActivity extends AppCompatActivity {
tv = findViewById(R.id.sample_text);
APISecurity.verify(getApplicationContext());
if(APISecurity.init(getApplicationContext())){
tv.setText("初始化ok");
}else {
tv.setText("初始化fail");
}
APISecurity.verify(getApplicationContext());
findViewById(R.id.btnTest).setOnClickListener(new View.OnClickListener() {
@SuppressLint("SetTextI18n")
@Override
public void onClick(View v) {
//API签名字符串
String val = "POST https://www.xxx.com/login?id=1&pwd=xxx......";
//计算签名
String aptStr="123456";
tv.setText("Sign:" + APISecurity.sign(aptStr));
}

View File

@@ -24,6 +24,9 @@ import android.util.Log;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
@@ -31,16 +34,18 @@ import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import cn.android.security.APISecurity;
//继承原application
import cn.android.security.AppSigning;
public class MyApplication extends Application implements InvocationHandler {
private static final int GET_SIGNATURES = 64;
private static final int GET_SIGNING_CERTIFICATES = 134217728;
private String appPkgName = "";
private Object base;
private byte[][] sign;
private File apkPath;//源 apk目录 这样使读取源文件签名达到骗过验证 针对sdk28 新API
private Object base;//全局sPackageManager对象
private byte[][] sign;//源 签名数组
static MyApplication app;
public MyApplication() {
// 在构造函数里提早检测
// earlyCheckSign();
@@ -58,7 +63,15 @@ public class MyApplication extends Application implements InvocationHandler {
}
}
private void copyFile(Context context, final String fileName) {
//data/app/packagename/lib/arm64/libold.so 将源文件搞到此目录
String libPath = context.getApplicationInfo().nativeLibraryDir+File.separator+fileName;
apkPath=new File(libPath);
Log.e("mhyLog","File:"+libPath);
if (!apkPath.exists()){
throw new RuntimeException("old.so未就位libs/ABI对应目录/libold.so");
}
}
@Override
protected void attachBaseContext(Context context) {
//在这里hook 签名校验被
@@ -81,25 +94,26 @@ public class MyApplication extends Application implements InvocationHandler {
*
* @param context
*/
@SuppressLint("PrivateApi")
private void hook(Context context) {
copyFile(context, "libold.so");//源apk
try {
// String realy = "308203273082020fa003020102020477d6d1f6300d06092a864886f70d01010b05003044310c300a06035504061303303231310e300c060355040813056368696e613111300f060355040713087368616e676861693111300f0603550403130877757a6f6e67626f301e170d3139303330353032343132345a170d3434303232373032343132345a3044310c300a06035504061303303231310e300c060355040813056368696e613111300f060355040713087368616e676861693111300f0603550403130877757a6f6e67626f30820122300d06092a864886f70d01010105000382010f003082010a0282010100a3ac52268a32e8420a20a727c184c133d513998a207e198f5a535d628a436ba5e095e7ba3f92535234a83fb6272e70ed6113d8f6facc3dee2cfc076a3bd93dad3520fd5d9d9ae4c48afe56e7b421f5de2adfbc23e450f7a5f71e0afdec047b1ce8d7be62ef754a9d43bf36d9b9e0728fc268cb845b464cce1370573dfafd6c40b2efb98ba1f20c5a63c417264b69d86adb839241dc37d1a7113295a9c51623e51e9408f9623ed49a63a3ba6269172872088213332f38370af530d5be56e54115b0884ace6813911bfc6873bea28207741f4b2471b797bab156e4c6ead91659076553cee1db82c0cebdd17b64802a20c7ee6a3414f959133e6c435efe9241ab7d0203010001a321301f301d0603551d0e041604143806aea351c74f2a8b83fa26c0a9e3d3820b6699300d06092a864886f70d01010b050003820101006ebcc664b996f15c1e03d041eebbdf74a0976d117d68f34d21ef67855b614f5a2bfede66c9d4ea78fe3b50e3673890dfa2eb9eaf4321b30eb76be6f5944004b6501b2629ae4f2c6750f784ea2f9be6c26318258f98772fd3ff0c6ea817fb76d9ae02daa1fa1b91653d531db345f52aa4e7b21e8f92387a2d15d1afd5556213b0c32aadd529bac330516536948bcf85398fb86a65dbae95ef0e5582a87e26b1dbcceeaf77e6e93c63042acdf49c74927561df508020547426ad37776e360feb219523ef4e2a6f5f41a43cd0c0514c53f8644c71014080cfbe036f120a6daad6e12d6b1a07939ca840af2b3373388c0ed6b18594dd838122174304d5eb720f1cef";
// realy= Base64.encodeToString(realy.getBytes(),Base64.DEFAULT);
String singnStr = "AQAAAjAwggIsMIIBlaADAgECAgMY2gowDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCQ04xCzAJBgNVBAgTAmhlMQwwCgYDVQQHEwNzanoxDDAKBgNVBAoTA2VkdTEPMA0GA1UECxMGc2Nob29sMRIwEAYDVQQDEwltYWhvbmd5aW4wHhcNMTgxMDExMDcwMjE1WhcNNDMxMDA1MDcwMjE1WjBbMQswCQYDVQQGEwJDTjELMAkGA1UECBMCaGUxDDAKBgNVBAcTA3NqejEMMAoGA1UEChMDZWR1MQ8wDQYDVQQLEwZzY2hvb2wxEjAQBgNVBAMTCW1haG9uZ3lpbjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAr0aFNvrxBnBEEbAANDcsrmBlcQBGJKsvT5onXngek2ZbkWZx8/1o8nbgCBSjAZvnXEYYjjkC5k+AIne1PJUF5bPKTjIQepNmtK+KVHsAJLjn6rG4fQ3oaeu0vvNBehuzt54bACbzkXZj9nV5rs8OllD9RronLsOb3DVJ95DyLIMCAwEAATANBgkqhkiG9w0BAQUFAAOBgQCpF6kB++zR0FW4eZaJCEAnQNP0GtwAnrXEpvP7ePcakk/JT/e56uTS/OAbpmM/tWETvPtx9hOB4RoPwRl3Q0G1ieCMeVyIABmGAeOktARqtiExfHvorrmk4mxVIiPTwUJSWzAKuhLV93pMxTFZSZK0iTJFVVM/l8Wh3CTdFtpW+w==";
DataInputStream dataInputStream = new DataInputStream(
new ByteArrayInputStream(Base64.decode(singnStr, Base64.DEFAULT)));
DataInputStream dataInputStream = new DataInputStream(new ByteArrayInputStream(Base64.decode(singnStr, Base64.DEFAULT)));
byte[][] bArr = new byte[(dataInputStream.read() & 255)][];
for (int i = 0; i < bArr.length; i++) {
bArr[i] = new byte[dataInputStream.readInt()];
dataInputStream.readFully(bArr[i]);
}
// hook全局sPackageManager对象
Class cls = Class.forName("android.app.ActivityThread");
Class<?> cls = Class.forName("android.app.ActivityThread");
Object invoke = cls.getDeclaredMethod("currentActivityThread", new Class[0]).invoke(null, new Object[0]);
Field declaredField = cls.getDeclaredField("sPackageManager");
declaredField.setAccessible(true);
Object obj = declaredField.get(invoke);
Class cls2 = Class.forName("android.content.pm.IPackageManager");
Class<?> cls2 = Class.forName("android.content.pm.IPackageManager");
this.base = obj;
this.sign = bArr;
this.appPkgName = context.getPackageName();
@@ -120,59 +134,64 @@ public class MyApplication extends Application implements InvocationHandler {
@Override
public Object invoke(Object obj, Method method, Object[] objArr) throws Throwable {
if ("getPackageInfo".equals(method.getName())) {//方法名对上
Log.e("mhyLogHook","getPackageInfo");
Log.e("mhyLogHook","getPackageInfo"+"_flag:"+(int)objArr[1]);
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 &&(((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);
//
//// 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]);
}
infoField.set(mSigningDetails, info);
Signature[] info2 = signingInfo.getApkContentsSigners();//获取属性值
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P &&((int) objArr[1] & GET_SIGNING_CERTIFICATES) != 0) {//a&b!=0 -> a=b
Class<?> pkgParserCls = Class.forName("android.content.pm.PackageParser");
Constructor<?> pkgParserCt = pkgParserCls.getConstructor();//可以反射任何构造器,可以反射私有构造器
Object pkgParser = pkgParserCt.newInstance();//PackageParser()
//Package parsePackage(File packageFile, int flags)
Method parsePackageMtd = pkgParserCls.getDeclaredMethod("parsePackage", File.class, int.class);
Object pkgParserPkg = parsePackageMtd.invoke(pkgParser, apkPath, PackageManager.GET_SIGNING_CERTIFICATES);//Package
Method collectCertificatesMtd = pkgParserCls.getDeclaredMethod("collectCertificates", pkgParserPkg.getClass(), Boolean.TYPE);
if (!collectCertificatesMtd.isAccessible()){collectCertificatesMtd.setAccessible(true);}
//void collectCertificates(Package pkg, boolean skipVerify)
collectCertificatesMtd.invoke(pkgParser, pkgParserPkg, true);//执行后 mSigningDetails就获取了值 到这里算是就给赋值了
// collectCertificatesMtd.invoke(pkgParser, pkgParserPkg, false);// Build.VERSION.SDK_INT > 28?:
// PackageParser$Package里的属性 mSigningDetails public
Field mSigningDetailsField = pkgParserPkg.getClass().getDeclaredField("mSigningDetails");
mSigningDetailsField.setAccessible(true);
//获取PackageParser$Package里mSigningDetails 对象
Object mSigningDetails = mSigningDetailsField.get(pkgParserPkg);
Class<?> sigInfo_clazz=Class.forName("android.content.pm.SigningInfo");
// Class<?> mSigningDetails_clazz=Class.forName("android.content.pm.PackageParser$SigningDetails");
/*clazz.newInstance();//只能反射()无参的构造器,需要构造器可见;*/
//利用Constructor.newInstance()反射私有构造方法 @hide
Constructor<?> sifInfoCt = sigInfo_clazz.getDeclaredConstructor(mSigningDetails.getClass());
if(!sifInfoCt.isAccessible())
sifInfoCt.setAccessible(true);
Object sifInfo_object = sifInfoCt.newInstance(mSigningDetails);//PackageParser()
// Constructor<?> sifInfoCt = sigInfo_clazz.getConstructor(mSigningDetails.getClass());
// Object sifInfo_object = sifInfoCt.newInstance(mSigningDetails);//可以反射任何构造器,可以反射私有构造器
packageInfo.signingInfo= (SigningInfo) sifInfo_object;
Field infoField = mSigningDetails.getClass().getDeclaredField("signatures");//final的
infoField.setAccessible(true);
//验证 是否hook
Signature[] info2 = (Signature[]) infoField.get(mSigningDetails);
if (info2.length>0){
Log.e("mhyLogHook2",info2[0].toCharsString());}
} else { //双hook
// if ((((Integer) objArr[1]).intValue() & 64) != 0){
Log.e("mhyLogHook2",AppSigning.getSignatureString(info2,AppSigning.SHA1));
}
} //else { //双hook
if ((((Integer) objArr[1]).intValue() & GET_SIGNATURES) != 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]);
}
Log.e("mhyLogHook1后",AppSigning.getSignatureString(packageInfo.signatures,AppSigning.SHA1));
}
return packageInfo;
}
}
// IPackageManager 中无getPackageArchiveInfo 方法无法代理
// IPackageManager接口中无getPackageArchiveInfo 方法无法代理
return method.invoke(this.base, objArr);
}