一个soot带来的java.lang.IncompatibleClassChangeError

2024-02-17 00:32

本文主要是介绍一个soot带来的java.lang.IncompatibleClassChangeError,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

    最近基于soot在做一些中间变换,在处理一个APK后报了一个IncompatibleClassChangeError,这种错误通常是编译时类路径与运行时类路径不同导致,但是我原始的APK可以正常运行,但是经过soot处理后的APK不能正常运行,因此怀疑是某些类被改变了。下面是该APK的源码(修改自Android cts部分源码):

public class MethodTest {// Default method reflection.public interface InterfaceWithDefault {default String defaultMethod() {return identifyCaller();}}public static class ImplementationWithDefault implements InterfaceWithDefault {}interface InterfaceWithReAbstractedMethod extends InterfaceWithDefault {// Re-abstract a default method.@Override String defaultMethod();}interface InterfaceWithRedefinedMethods extends InterfaceWithReAbstractedMethod {// Reimplement an abstracted default method.@Override default String defaultMethod() {return identifyCaller();}}interface OtherInterfaceWithDefault {default String defaultMethod() {return identifyCaller();}}public void testDefaultMethod_superSyntax() throws Exception {class ImplementationSuperUser implements InterfaceWithDefault, OtherInterfaceWithDefault {@Override public String defaultMethod() {return identifyCaller() + ":" +InterfaceWithDefault.super.defaultMethod() + ":" +OtherInterfaceWithDefault.super.defaultMethod();}}String implementationSuperUserClassName = ImplementationSuperUser.class.getName();String interfaceWithDefaultClassName = InterfaceWithDefault.class.getName();String otherInterfaceWithDefaultClassName = OtherInterfaceWithDefault.class.getName();String expectedReturnValue = implementationSuperUserClassName + ":" +interfaceWithDefaultClassName + ":" + otherInterfaceWithDefaultClassName;ImplementationSuperUser obj = new ImplementationSuperUser();assertEquals(expectedReturnValue, obj.defaultMethod());Method defaultMethod = ImplementationSuperUser.class.getMethod("defaultMethod");assertEquals(expectedReturnValue, defaultMethod.invoke(obj));}/*** Keep this package-protected or public to avoid the introduction of synthetic methods that* throw off the offset.*/static String identifyCaller() {StackTraceElement[] stack = Thread.currentThread().getStackTrace();int i = 0;while (!stack[i++].getMethodName().equals("identifyCaller")) {}return stack[i].getClassName();}private void assertEquals(String expectValue, String value) {if(!expectValue.equals(value)) {Log.i("susu", "assert error, expectValue: " + expectValue + " ,actualValue : " + value);}}private void assertEquals(Object expectValue, Object value) {if(!expectValue.equals(value)) {Log.i("susu", "assert error, expectValue: " + expectValue.toString() + " ,actualValue : " + value.toString());}}
}

1,首先利用smali工具对原始APK进行反编译,然后再回编译,签名运行没有问题。

2,对经过soot处理后的APK进行反编译,与原始APK的反编译结果进行对比,粗略看了一下,好像也大致相同。其反编译出七个文件,如下所示:

3,用soot处理后的APK反编译文件逐个去替换原始APK反编译的文件,并进行回编译测试。替换到上图第二个文件,也就是MethodTest$1ImplementationSuperUser.smali文件时,发现出现IncompatibleClassChangeError。问题显然出在该文件中,对该文件继续深入分析,发现defaultMethod方法中的一条invoke指令有问题,如下所示:

查阅Android官方文档后发现这一条解释:

使用 invoke-virtual 调用正常的虚方法(该方法不是 private、static 或 final,也不是构造函数)。当 method_id 引用非接口类方法时,使用 invoke-super 调用最近超类的虚方法(这与调用类中具有相同 method_id 的方法相反)。invoke-virtual 具有相同的方法限制。在版本 037 或更高版本的 Dex 文件中,如果 method_id 引用接口方法,则使用 invoke-super 来调用在该接口上定义的该方法的最具体、未被覆盖版本。

 

 

 

这篇关于一个soot带来的java.lang.IncompatibleClassChangeError的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/716158

相关文章

Spring boot整合dubbo+zookeeper的详细过程

《Springboot整合dubbo+zookeeper的详细过程》本文讲解SpringBoot整合Dubbo与Zookeeper实现API、Provider、Consumer模式,包含依赖配置、... 目录Spring boot整合dubbo+zookeeper1.创建父工程2.父工程引入依赖3.创建ap

SpringBoot结合Docker进行容器化处理指南

《SpringBoot结合Docker进行容器化处理指南》在当今快速发展的软件工程领域,SpringBoot和Docker已经成为现代Java开发者的必备工具,本文将深入讲解如何将一个SpringBo... 目录前言一、为什么选择 Spring Bootjavascript + docker1. 快速部署与

Spring Boot spring-boot-maven-plugin 参数配置详解(最新推荐)

《SpringBootspring-boot-maven-plugin参数配置详解(最新推荐)》文章介绍了SpringBootMaven插件的5个核心目标(repackage、run、start... 目录一 spring-boot-maven-plugin 插件的5个Goals二 应用场景1 重新打包应用

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

Spring Boot集成Druid实现数据源管理与监控的详细步骤

《SpringBoot集成Druid实现数据源管理与监控的详细步骤》本文介绍如何在SpringBoot项目中集成Druid数据库连接池,包括环境搭建、Maven依赖配置、SpringBoot配置文件... 目录1. 引言1.1 环境准备1.2 Druid介绍2. 配置Druid连接池3. 查看Druid监控

Java中读取YAML文件配置信息常见问题及解决方法

《Java中读取YAML文件配置信息常见问题及解决方法》:本文主要介绍Java中读取YAML文件配置信息常见问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录1 使用Spring Boot的@ConfigurationProperties2. 使用@Valu

创建Java keystore文件的完整指南及详细步骤

《创建Javakeystore文件的完整指南及详细步骤》本文详解Java中keystore的创建与配置,涵盖私钥管理、自签名与CA证书生成、SSL/TLS应用,强调安全存储及验证机制,确保通信加密和... 目录1. 秘密键(私钥)的理解与管理私钥的定义与重要性私钥的管理策略私钥的生成与存储2. 证书的创建与

浅析Spring如何控制Bean的加载顺序

《浅析Spring如何控制Bean的加载顺序》在大多数情况下,我们不需要手动控制Bean的加载顺序,因为Spring的IoC容器足够智能,但在某些特殊场景下,这种隐式的依赖关系可能不存在,下面我们就来... 目录核心原则:依赖驱动加载手动控制 Bean 加载顺序的方法方法 1:使用@DependsOn(最直

SpringBoot中如何使用Assert进行断言校验

《SpringBoot中如何使用Assert进行断言校验》Java提供了内置的assert机制,而Spring框架也提供了更强大的Assert工具类来帮助开发者进行参数校验和状态检查,下... 目录前言一、Java 原生assert简介1.1 使用方式1.2 示例代码1.3 优缺点分析二、Spring Fr

java使用protobuf-maven-plugin的插件编译proto文件详解

《java使用protobuf-maven-plugin的插件编译proto文件详解》:本文主要介绍java使用protobuf-maven-plugin的插件编译proto文件,具有很好的参考价... 目录protobuf文件作为数据传输和存储的协议主要介绍在Java使用maven编译proto文件的插件