Skip to content

Commit

Permalink
More tests and a bit of refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
EpicPlayerA10 committed Aug 24, 2024
1 parent 80f9a61 commit 5e19051
Show file tree
Hide file tree
Showing 34 changed files with 644 additions and 324 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,7 @@ buildNumber.properties
/work/
/test/

# Don't add compiled classes from java code
# Don't track compiled classes from java code
/testData/compiled/java/
# Don't track deobfuscated files. They are added as decompiled code
/testData/deobfuscated/
10 changes: 7 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## ✅ How to run deobfuscator
1. Navigate to class [`Bootstrap.java`](./deobfuscator-impl/src/test/java/Bootstrap.java)
2. In this class edit the deobfuscator configuration
- `input` - Your input jar file
- `inputJar` - Your input jar file
- `transformers` - Pick transformers that you want to run. You can find them in [`deobfuscator-transformers`](./deobfuscator-transformers) module.
3. Run this class manually from your IDE

Expand All @@ -19,6 +19,7 @@ The project is structured as follows:
- [`src/java`](./testData/src/java) - You can write your java code to test transformers
- [`compiled/custom-classes`](./testData/compiled/custom-classes) - Compiled classes to test transformers. You can throw here classes from your obfuscated jars.
- [`compiled/custom-jars`](./testData/compiled/custom-jars) - Jars to test transformers. You can throw here your obfuscated jars.
- [`deobfuscated`] - Raw classes after deobfuscation process. Useful when debugging.
- [`results`](./testData/results) - Expected results that are auto-generated decompiled java code.
- [`TestDeobfuscation.java`](./deobfuscator-impl/src/test/java/uwu/narumii/deobfuscator/TestDeobfuscation.java) - Class where each test sample is registered.
- [`Bootstrap.java`](./deobfuscator-impl/src/test/java/Bootstrap.java) - Class where you can run deobfuscator manually.
Expand All @@ -31,16 +32,19 @@ Whole deobfuscation process is based on transformers. Transformers are smaller c
1. Create a new class in [`deobfuscator-transformers`](./deobfuscator-transformers) module.
2. Pick `Transformer`-like class you would like to implement:
- `Transformer` - Basic transformer that transforms classes.
- `FramedInstructionsTransformer` - Transformer that mainly transforms instructions in methods. If you need you can also access values in the stack.
- `FramedInstructionsTransformer` - Transformer that mainly transforms instructions in methods. If you need you can also access values from the stack.
- `ComposedTransformer` - Transformer that consists of multiple transformers.
3. You can start coding!

## 🧪 Testing
### How these test work?
### How these tests work?
1. The registered samples are transformed using corresponding transformers.
2. The output gets decompiled using Vineflower.
3. The output gets compared with the expected output.

### How to run tests?
Just run command `mvn test` in the root directory of the project.

### How to create your own tests?
You can create your own tests for transformers. There are a few ways to do it:
- If the obfuscation is simple enough, you can write your own sample in [`testData/src/java`](./testData/src/java)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
> - Porting old transformers to new code base
> - Testing InstructionMatcher
> - Implementing/Improving transformers
> - Writing tests
> - Safety checks on putstatic in FieldInlineTransformers (overriding values)
> - Feedback on how the new api presents itself (mainly InstructionMatcher)
> <br>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,23 @@ public class ClassWrapper implements Cloneable {

protected static final Logger LOGGER = LogManager.getLogger(ClassWrapper.class);

/**
* Path for saving purposes.
*/
private final String path;
private final ClassNode classNode;
private final FieldCache fieldCache;
private final ConstantPool constantPool;
private final int classWriterFlags;

public ClassWrapper(String path, ClassReader classReader, int readerMode, int classWriterFlags) throws Exception {
public ClassWrapper(String path, ClassReader classReader, int classReaderFlags, int classWriterFlags) throws Exception {
this.path = path;
this.classNode = new ClassNode();
this.constantPool = new ConstantPool(classReader);
this.fieldCache = new FieldCache();
this.classWriterFlags = classWriterFlags;

classReader.accept(this.classNode, readerMode);
classReader.accept(this.classNode, classReaderFlags);
}

private ClassWrapper(String path, ClassNode classNode, FieldCache fieldCache, ConstantPool constantPool, int classWriterFlags) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,21 @@ public static boolean isClass(byte[] bytes) {
.equals("CAFEBABE");
}

public static ClassWrapper loadClass(String path, byte[] bytes, int readerMode, int classWriterFlags) throws Exception {
return loadClass(path, bytes, readerMode, classWriterFlags, false);
public static ClassWrapper loadClass(String path, byte[] bytes, int classReaderFlags, int classWriterFlags) throws Exception {
return loadClass(path, bytes, classReaderFlags, classWriterFlags, false);
}

public static ClassWrapper loadClass(String path, byte[] bytes, int readerMode, int classWriterFlags, boolean fix) throws Exception {
return new ClassWrapper(path, new ClassReader(fix ? fixClass(bytes) : bytes), readerMode, classWriterFlags);
/**
* Load class from bytes
*
* @param path Relative path of a class in a jar
* @param bytes Class bytes
* @param classReaderFlags {@link ClassReader} flags
* @param classWriterFlags {@link ClassWriter} flags
* @param fix Fix class using CAFED00D
*/
public static ClassWrapper loadClass(String path, byte[] bytes, int classReaderFlags, int classWriterFlags, boolean fix) throws Exception {
return new ClassWrapper(path, new ClassReader(fix ? fixClass(bytes) : bytes), classReaderFlags, classWriterFlags);
}

public static byte[] fixClass(byte[] bytes) throws InvalidClassException {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package uwu.narumi.deobfuscator.api.helper;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.function.BiConsumer;
import java.util.jar.JarFile;
Expand Down Expand Up @@ -32,4 +35,23 @@ public static void loadFilesFromZip(Path path, BiConsumer<String, byte[]> consum
LOGGER.debug("Error", e);
}
}

public static void deleteDirectory(File file) {
if (!file.exists()) {
return;
}
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (File f : files) {
deleteDirectory(f);
}
}
}
try {
Files.delete(file.toPath());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@

import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;

/**
* Transformer that will iterate instructions along with their current {@link Frame}s
*/
public abstract class FramedInstructionsTransformer extends Transformer {
private boolean changed = false;
private AtomicInteger changed = new AtomicInteger(0);

/**
* Transform instruction
Expand Down Expand Up @@ -72,11 +73,12 @@ protected boolean transform(ClassWrapper scope, Context context) throws Exceptio
// Run the instruction transformer
boolean transformerChanged = transformInstruction(classWrapper, methodNode, insn, frame);
if (transformerChanged) {
changed = true;
changed.incrementAndGet();
}
});
}));

return changed;
LOGGER.info("Transformed {} instructions", changed.get());
return changed.get() > 0;
}
}
Loading

0 comments on commit 5e19051

Please sign in to comment.