高中生

- 金币
- 211
- 好评
- 10
- 信誉
- 100
|
本帖最后由 LivedForward 于 2025-12-8 17:33 编辑
检测基于:
在同一个JVM中,对于一个特定的类加载器,一个类(.class文件)在其生命周期内,只会生成一个 Class 对象。
先看一下android.jar里面的android.os.Parcelable这个公共接口类和
android.content.pm.PackageInfo类里面的这段代码:
public static final Parcelable.Creator<PackageInfo> CREATOR = new Parcelable.Creator<PackageInfo>() {
public PackageInfo createFromParcel(Parcel parcel) {
return new PackageInfo(parcel);
}
public PackageInfo[] newArray(int i) {
return new PackageInfo;
}
};
所以CREATOR这个静态字段存储的是一个Parcelable.Creator<PackageInfo>
接口的匿名实现类的实例对象,为PackageInfo$1类型。
匿名内部类在编译时会被编译成一个独立的类文件,命名格式为:
你执行实例化new Parcelable.Creator<PackageInfo>
代码所在的类名+$数字.class // 数字从 1 开始
Class packageInfoClass = Class.forName("android.content.pm.PackageInfo");
Field creatorField = packageInfoClass.getDeclaredField("CREATOR");
creatorField.setAccessible(true);
Object creatorObject = creatorField.get(null);
Class creatorObjectClass = creatorObject.getClass();
creatorObjectClass是android.content.pm.PackageInfo$1这个class文件所
对应的class对象。
重点:一份class文件只对应内存里面的一个class对象,一个class对象里面
里面所包含的类名包括public和非public修饰的,我们可以创建无数个类名
所对应的对象。也就是说你通过java方法获取的class对象的地址
其实指向的是同一个地址:
Class packageInfoClass1 = Class.forName("android.content.pm.PackageInfo");
Class packageInfoClass2 = android.content.pm.PackageInfo.class;
packageInfoClass1和packageInfoClass2地址一致。
回到这里:
public class PackageInfo implements Parcelable {
public static final Parcelable.Creator<PackageInfo> CREATOR = new Parcelable.Creator<PackageInfo>() {
public PackageInfo createFromParcel(Parcel parcel) {
return new PackageInfo(parcel);
}
public PackageInfo[] newArray(int i) {
return new PackageInfo;
}
};
*****
}
匿名内部类在编译时会被编译成一个独立的类文件,命名格式为:
你执行实例化new Parcelable.Creator<PackageInfo>
代码所在的类名+$数字.class // 数字从 1 开始
因为这段代码:
public static final Parcelable.Creator<PackageInfo> CREATOR = new Parcelable.Creator<PackageInfo>() {
public PackageInfo createFromParcel(Parcel parcel) {
return new PackageInfo(parcel);
}
public PackageInfo[] newArray(int i) {
return new PackageInfo;
}
};
重点:
是在android.content.pm.PackageInfo类里面实例化的Parcelable.Creator内部接口类,
所以是android.content.pm.PackageInfo$1.class文件。
我们Class packageInfoClassJava = Class.forName("android.content.pm.PackageInfo$1");
获取到的是android.jar里面的android.content.pm.PackageInfo$1所对应的class对象。
哪再看一下替换CREATOR静态字段所实例化的Parcelable.Creator内部接口类在哪个类里面执行
的:
肯定不是在android.content.pm.PackageInfo类里面执行的,所以被编译后所生成的class文件是:
YourJavaClassName$1,这样我们再通过Class.forName("YourJavaClassName");所获取到的class
对象就与android.content.pm.PackageInfo$1.class所对应的class对象不是同一个class对象了,
所以直接判断class对象地址是否相等即可:
Class packageInfoClass = Class.forName("android.content.pm.PackageInfo");
Field creatorField = packageInfoClass.getDeclaredField("CREATOR");
creatorField.setAccessible(true);
Object creatorObject = creatorField.get(null);
Class creatorObjectClass = creatorObject.getClass();
// CREATOR静态字段里的Object对应的class文件对象
Class packageInfo$1Class = Class.forName("android.content.pm.PackageInfo$1");
// 期望的CREATOR静态字段里的Object对应的class文件对象
if(creatorObjectClass == packageInfo$1Class){
// 未被篡改
}else{
// 被篡改
}
同理,检测PMS是否被Proxy一样。
最后:
在JNI中,我们通过FindClass获取的类引用和通过GetObjectClass获取的类引用可能不同,
即使它们代表同一个类。这是因为JNI的类引用是本地引用,
所以,我们通常不能在JNI里直接比较两个jclass的地址。
SafeCheck发布了2.0.1新版本,感兴趣可以一试:
SafeCheck
感谢大家的支持和关注,请评论指正错误之处。
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|