关于jar和aar中修改其中class字节码

总有jar和aar中修改其中class字节码的需求,之前想直接用压缩工具解压缩,直接用javasist写代码修改,然后再替换这个classes.jar 再转成aar格式,但是好像这样破坏了aar结构导致aar无法使用,于是就写了一个工具

看看效果图吧(修改classes.jar后可以被识别的aar)

借助了https://github.com/BryanSharp/hibeaver 中对jar和aar中修改其中class字节码相关代码的帮助(抄袭),这里感谢作者

以下这个工具的github 地址 https://github.com/zjw-swun/AppMethodTime

相关代码

 public static File unzipEntryToTemp(ZipEntry element, ZipFile zipFile, String parentDir) {
        def stream = zipFile.getInputStream(element);
        def array = IOUtils.toByteArray(stream);
        //String hex = DigestUtils.md5Hex(element.getName());
        File targetFile = new File(parentDir, "temp.jar");
        if (targetFile.exists()) {
            targetFile.delete()
        }
        def out = new FileOutputStream(targetFile)
        out.write(array)
        out.close()
        stream.close()
        return targetFile
    }

    public
    static File modifyJar(File jarFile) {
        ClassPath jarClassPath = pool.appendClassPath(jarFile.path)
        ClassPath androidClassPath = pool.insertClassPath(androidJarPath)
        /**
         * 读取原jar
         */
        def file = new JarFile(jarFile);
        /** 设置输出到的jar */
        def hexName = "";
        hexName = DigestUtils.md5Hex(jarFile.absolutePath).substring(0, 8);

        def outputJar = new File(jarFile.parent, "Target_" + jarFile.name)
        if (outputJar.exists()) {
            outputJar.delete()
        }
        JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(outputJar));
        Enumeration enumeration = file.entries();
        while (enumeration.hasMoreElements()) {
            JarEntry jarEntry = (JarEntry) enumeration.nextElement();
            InputStream inputStream = file.getInputStream(jarEntry);

            String entryName = jarEntry.getName();
            String className

            ZipEntry zipEntry = new ZipEntry(entryName);

            jarOutputStream.putNextEntry(zipEntry);

            byte[] modifiedClassBytes = null;
            byte[] sourceClassBytes = IOUtils.toByteArray(inputStream);
            if (filter(entryName)) {
                //println("entryName "+entryName)
                className = entryName.replace("/", ".").replace(".class", "")
                //println("modifyJar className "+className)
                CtClass c = modifyClass(className)
                if (c != null) {
                    modifiedClassBytes = c.toBytecode()
                    c.detach()
                }
            }
            if (modifiedClassBytes == null) {
                jarOutputStream.write(sourceClassBytes);
            } else {
                jarOutputStream.write(modifiedClassBytes);
            }
            jarOutputStream.closeEntry();
        }
//            Log.info("${hexName} is modified");
        jarOutputStream.close();
        file.close();
        pool.removeClassPath(jarClassPath)
        pool.removeClassPath(androidClassPath)
        return outputJar;
    }

    public static void modifyAar(File targetFile) {

        ZipFile zipFile = new ZipFile(targetFile);
        Enumeration<ZipEntry> entries = zipFile.entries();

        def outputAar = new File(targetFile.parent, "Target_" + targetFile.name)
        if (outputAar.exists()) {
            outputAar.delete()
        }

        ZipOutputStream outputAarStream = new ZipOutputStream(new FileOutputStream(outputAar))
        FileInputStream fileInputStream = null;
        File innerJar = null;
        File outJar = null;
        while (entries.hasMoreElements()) {
            ZipEntry element = entries.nextElement();
            def name = element.getName();
            ZipEntry zipEntry = new ZipEntry(name);

            outputAarStream.putNextEntry(zipEntry);
            if (name.endsWith(".jar")) {
                innerJar = unzipEntryToTemp(element, zipFile, targetFile.parent);
                outJar = modifyJar(innerJar);
                fileInputStream = new FileInputStream(outJar)
                outputAarStream.write(IOUtils.toByteArray(fileInputStream))
            } else {
                def stream = zipFile.getInputStream(element)
                byte[] array = IOUtils.toByteArray(stream)
                if (array != null) {
                    outputAarStream.write(array)
                }
                stream.close()
            }
            outputAarStream.closeEntry();
        }
        zipFile.close()
        if (fileInputStream!= null){
            fileInputStream.close()
        }
        outputAarStream.close()
        if (innerJar != null){
            innerJar.delete()
        }
        if (outJar != null){
            outJar.delete()
        }
    }

项目中buildSrc模块中是一个transform api的插件

使用说明

添加aarOrJarPath 配置字段,填入目标jar或者aar路径 执行gradle面板对应项目中other目录appMethodJarOrAar 任务即可在aarOrJarPath 配置的同目录下生成带 Target_前缀的目标jar或者aar文件

可以参考
https://github.com/zjw-swun/AppMethodTime/blob/master/mylibrary/build.gradle

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值