Threadtear反混淆工具的使用

本文介绍了如何使用Threadtear工具对已混淆的jar包进行反编译。首先,可以通过下载或编译GitHub项目来获取可执行jar。然后,使用java命令运行jar文件启动工具,设置执行任务并添加待处理的jar。虽然尚未找到能完全恢复所有混淆变量的方法,但可以创建自定义Execution来进行更深入的代码分析和修改。文章还提供了一个自定义Execution的示例代码。

开发过程中,我们已经会遇到一些三方库没有开源的情况,有时需要参考其中的一些代码,我们就需要对其进行反编译才能查看。有时还会遇到代码已混淆的情况。本文主要介绍如何使用Threadtear对已混淆的jar包进行反混淆。

Threadtear Git地址:https://github.com/GraxCode/threadtear

编译可执行jar

有两种方式:
1、直接下载Github已经发布的最新版本。(目前的最新版本3.0.1我下载后发现不可正常运行有异常)
2、下载Git项目代码,用Android Studio导入项目。并执行如下两条命令,然后在gui模块的builds/libs中会得到一个可运行的jar文件:threadtear-gui-3.0.0-all.jar

gradle build
gradle fatJar

工具使用

在刚才生成的可执行jar文件的目录下(也可以将刚才生成的jar文件拷贝到一个新目录下)运行如下命令,打开Threadtear工具:

java -noverify -jar threadtear-gui-3.0.0-all.jar

工具界面如下图:
在这里插入图片描述
help菜单下面有个Look and feel settings可以设置下界面样式,主要是设置下文字大小,默认的大小有点小。。。
接下来我们先设置下要执行的任务,点击Add按钮,如下图:
在这里插入图片描述
接下来,我们按顺序将下图所示的任务添加至可执行列表:
在这里插入图片描述
再接着,我们将需要反编译反混淆的jar直接拖至右侧Class list区域即可。

这里我还没有找到完全将每个文件的混淆变量全部恢复至原名称的执行列表组合,上门的执行任务只是将每个类名解析了出来。变量名还在研究中,有进展及时更新啦,sorry~

自定义Execution

在这里插入图片描述

如上图所示,下载项目源码之后,在core模块中新建custom目录,并创建自定义Execution,并把自定义Execution添加到ExecutionLink中。然后重新打包。这样在可执行jar的ExecutionList中就可以看到我们刚才新建的自定义Execution了。

public class MyExecution extends Execution implements IConstantReferenceHandler {

    public MyExecution() {
        super(ExecutionCategory.GENERIC, "My execution", "Performs stack analysis and replaces code.");
    }

    @Override
    public boolean execute(Map<String, Clazz> classes, boolean verbose) {
        classes.values().stream().map(c -> c.node).forEach(this::analyzeAndRewrite);
        return true;
    }

    public void analyzeAndRewrite(ClassNode cn) {
        cn.methods.forEach(m -> {
            // this analyzer keeps known stack values, e.g. can be useful for jump prediction
            Analyzer<ConstantValue> a = new Analyzer<ConstantValue>(new ConstantTracker(this,
                    Access.isStatic(m.access), m.maxLocals, m.desc, new Object[0]));

            try {
                a.analyze(cn.name, m);
            } catch (AnalyzerException e) {
                logger.error("Failed stack analysis in " + cn.name + "." + m.name + ":" + e.getMessage());
                return;
            }

            Frame<ConstantValue>[] frames = a.getFrames();
            InsnList rewrittenCode = new InsnList();
            Map<LabelNode, LabelNode> labels = Instructions.cloneLabels(m.instructions);

            // rewrite method instructions
            for (int i = 0; i < m.instructions.size(); i++) {

                AbstractInsnNode ain = m.instructions.get(i);
                Frame<ConstantValue> frame = frames[i];
                // replace / modify instructions, etc...

                if (frame.getStackSize() > 0) {
                    ConstantValue top = frame.getStack(frame.getStackSize() - 1);

                    if (top.isKnown() && top.isInteger()) {
                        int knownTopStackValue = top.getAsInteger();
                        // use the known stack to remove jumps, simplify code, etc...
                        // if(...) { rewrittenCode.add(...); }
                        continue;
                    }
                }

                rewrittenCode.add(ain.clone(labels));
            }

            // update instructions and fix try catch blocks, local variables, etc...
            Instructions.updateInstructions(m, labels, rewrittenCode);
        });
    }

    /**
     * Use this method to predict stack values if fields are loaded
     */
    @Override
    public Object getFieldValueOrNull(BasicValue v, String owner, String name, String desc) {
        return null;
    }

    /**
     * Use this method to predict stack values if methods are invoked on known objects
     */
    @Override
    public Object getMethodReturnOrNull(BasicValue v, String owner, String name, String desc, List<?
            extends ConstantValue> values) {

        if (name.equals("toCharArray") && owner.equals("java/lang/String")) {

            if (!values.get(0).isKnown()) {
                // invocation target is not known, we can't compute the return
                return null;
            }

            return ((String) values.get(0).getValue()).toCharArray();
        }

        return null;
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值