Use of Threadtear anti-obfuscation tool

During the development process, we have encountered some three-party libraries that are not open source. Sometimes we need to refer to some of the codes, and we need to decompile them to view them. It is also sometimes encountered that the code has been obfuscated. This article mainly introduces how to use Threadtear to deobfuscate the obfuscated jar package.

Threadtear Git address: https://github.com/GraxCode/threadtear

compile executable jar

There are two ways:
1. Directly download the latest version released by Github. (I downloaded the latest version 3.0.1 and found that it cannot run normally and has abnormalities)
2. Download the Git project code and import the project with Android Studio. And execute the following two commands, and then an executable jar file will be obtained in the builds/libs of the gui module: threadtear-gui-3.0.0-all.jar.

gradle build
gradle fatJar

tool use

Run the following command in the directory of the executable jar file just generated (you can also copy the jar file just generated to a new directory) to open the Threadtear tool:

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

The tool interface is as shown in the figure below:
insert image description here
There is a Look and feel settings under the help menu to set the interface style, mainly to set the text size, the default size is a bit small. . .
Next, we first set the tasks to be executed, click the Add button, as shown in the figure below:
insert image description here
Next, we add the tasks shown in the figure below to the executable list in order:
insert image description here
Then, we will need to decompile and deobfuscate the jar directly Drag it to the Class list area on the right.

Here I haven't found an execution list combination that completely restores all the obfuscated variables of each file to their original names. The door-to-door execution task is only to parse out each class name. The variable name is still under study, please update in time if there is any progress, sorry~

Custom Execution

insert image description here

As shown in the figure above, after downloading the project source code, create a new custom directory in the core module, create a custom Execution, and add the custom Execution to ExecutionLink. Then repack. In this way, we can see the custom Execution we just created in the ExecutionList of the executable jar.

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;
    }
}

insert image description here

Guess you like

Origin blog.csdn.net/u012230055/article/details/128894612