修改混淆jar中类方法

1.字节码出现类名与包名冲突

使用这个工具:jarjar工具

  • 创建一个rule文件,如rule.txt,内容如下:
rule 原包名.** 目标包名.@1

例如:

rule a.b.c.** x.y.z.@1
rule a.b.c.** a.b.c.@1

然后运行jarjar工具,将要修改的jar包old.jar按照rule.txt的规则产生新的jar包new.jar

java -jar jarjar-1.4.jar process rule.txt old.jar new.jar

2. 利用javaassist修改对应方法

  • 添加依赖

sourceCompatibility = 1.8

dependencies {
    compile 'io.reactivex.rxjava2:rxjava:2.1.16'
    compile fileTree('libs/javassist.jar')
}
  • 导入类
public class Clazz {

    private String JAR_DIR = "";
    private String JAR_NAME = "";
    private String PKGNAME = "";
    private String CLASSNAME = "";

    private Clazz() {
    }

    public interface Builder {
        Clazz CLAZZ = new Clazz();
    }

    public interface Presenter {
        void onHack(CtClass ctClass) throws Exception;
    }

    public static Clazz initialize(String libDir, String libName) {
        Clazz clazz = Builder.CLAZZ;

        clazz.JAR_DIR = libDir;
        clazz.JAR_NAME = libName;
        return clazz;
    }


    @SuppressWarnings("ResultOfMethodCallIgnored")
    public void hackClass(String pkgName, String className, Presenter presenter) {

        PKGNAME = pkgName;
        CLASSNAME = className;

        // jar包路径
        // class位置
        // 输入class路径, jar uvf命令替换jar
//            String command = String.format("cd %s; jar uvf %s %s", JAR_DIR, JAR_NAME, clazzPath);
//            String[] cmd = {"/bin/sh", "-c", command};
        Observable.create((ObservableOnSubscribe<String>) emitter -> {
            // jar包路径
            String jar = getJarPath();
            File file = new File(jar);
            if (file.exists()) {
                emitter.onNext(jar);
                emitter.onComplete();
            } else {
                emitter.onError(new FileNotFoundException(jar + " NOT FOUND!"));
            }

        }).map(jarPath -> {
            ClassPool classPool = ClassPool.getDefault();

            classPool.insertClassPath(jarPath);

            // class位置
            String clazz = getClazzName();
            CtClass ctClass = classPool.get(clazz);

            if (presenter != null) {
                presenter.onHack(ctClass);
            }
            return ctClass.toBytecode();
        }).map(bytes -> {
            String clazzPath = getClazzPath();

            File dstFile = new File(clazzPath);
            if (!dstFile.getParentFile().exists()) {
                dstFile.getParentFile().mkdirs();
            }
            FileOutputStream output = new FileOutputStream(dstFile);

            output.write(bytes);
            output.flush();
            return dstFile.getAbsolutePath();
        }).map(savePath -> {  // 输入class路径, jar uvf命令替换jar
            String clazzPath = getClazzPath();

//            String command = String.format("cd %s; jar uvf %s %s", JAR_DIR, JAR_NAME, clazzPath);
//            String[] cmd = {"/bin/sh", "-c", command};
            String command = String.format("jar uvf %s %s", getJarPath(), clazzPath);

            return exec(command);

        }).subscribe(status -> {
            if (status == 0) {
                String command = String.format("rm -rf %s", getClazzRootPath());
                Runtime.getRuntime().exec(command);
            }
            System.out.printf("status: %d\t%s\n", status, Thread.currentThread().getName());
        });

    }

    private String getJarPath() {
        return String.format("%s/%s", JAR_DIR, JAR_NAME);
    }

    private String getClazzRootPath() {
        String rootPath;
        int index = PKGNAME.indexOf(".");
        if (index > 0) {
            rootPath = PKGNAME.substring(0, index);
        } else {
            rootPath = getClazzPath();
        }

        return rootPath;
    }

    private String getClazzPath() {
        String clazzPath;
        if (PKGNAME.isEmpty()) {
            clazzPath = String.format("%s.class", CLASSNAME);
        } else {
            clazzPath = String.format("%s/%s.class", PKGNAME.replace(".", "/"), CLASSNAME);
        }
        return clazzPath;
    }

    private String getClazzName() {
        String clazzName;
        if (PKGNAME.isEmpty()) {
            clazzName = CLASSNAME;
        } else {
            clazzName = String.format("%s.%s", PKGNAME, CLASSNAME);
        }
        return clazzName;
    }


    public static int exec(String... commands) throws IOException, InterruptedException {
        int status = 1;
        if (commands == null) {
            return status;
        }
        File wd = new File(".");
        Process proc = Runtime.getRuntime().exec("/bin/bash", null);
        if (proc != null) {
            BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);
            for (String command : commands) {
                out.println(command);
            }
            out.println("exit");
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
            status = proc.waitFor();
            in.close();
            out.close();
            proc.destroy();
        }
        return status;
    }

    public static int exec2(String... commands) throws IOException, InterruptedException {
        int status = 1;
        if (commands == null) {
            return status;
        }
        String command = String.join(";", commands);
        String[] cmd = {"/bin/sh", "-c", command};
        Process proc = Runtime.getRuntime().exec(cmd);
        if (proc != null) {
            BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
            status = proc.waitFor();
            in.close();
            proc.destroy();
        }
        return status;
    }


    public static String readContent(String path) throws IOException, NotFoundException {

        File file = new File(path);

        if (!file.exists()) {
            throw new NotFoundException("Not Found: " + file.getAbsolutePath());
        }
        BufferedReader in = new BufferedReader(new FileReader(file));
        String line;

        StringBuilder buffer = new StringBuilder();

        while ((line = in.readLine()) != null) {
            buffer.append(line).append("\n");
        }
        in.close();
        return buffer.toString();

    }
}

  • 开始hook(写一个测试方法,修改charles.jar)
// dir: jar包目录
// charles.jar:  要修改的jar包名
 Clazz.initialize("dir", "charles.jar")
                .hackClass("com.xk72.charles", "oFTR", ctClass -> {

                    CtMethod ctMethod = ctClass.getDeclaredMethod("lktV", null);
                    ctMethod.setBody("{return \"Crack by me!\";}");

                });

3. 还原原包包名

按方法1修改即可。

END

  • PS:
// 如果方法体过大,采用读文本的形式setBody
String content = Clazz.readContent("method.txt");
ctMethod.setBody(content);

method.txt内容如下:

{
  return "Crack by me!";
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容