为了账号安全,请及时绑定邮箱和手机立即绑定

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

标签:
Android

总有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文件

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
1万
获赞与收藏
137

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消