Skip to content

Commit

Permalink
Use context's classes in InheritanceGraph. Add tests to HP888PackerTr…
Browse files Browse the repository at this point in the history
…ansformer
  • Loading branch information
EpicPlayerA10 committed Oct 15, 2024
1 parent 280f044 commit 39c70d8
Show file tree
Hide file tree
Showing 31 changed files with 880 additions and 353 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package uwu.narumi.deobfuscator.api.classpath;

import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.tree.ClassNode;

import java.util.Collection;

public interface ClassProvider {
/**
* Gets class bytes by internal name
*
* @param name Internal name of class
* @return Class bytes
*/
byte @Nullable [] getClass(String name);

/**
* Gets file bytes by name
*
* @param path File path
* @return File bytes
*/
byte @Nullable [] getFile(String path);

/**
* Gets class node that holds only the class information. It is not guaranteed that the class holds code.
*
* @param name Internal name of class
* @return Class node
*/
@Nullable
ClassNode getClassInfo(String name);

/**
* Gets all classes in the provider.
*/
Collection<String> getLoadedClasses();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package uwu.narumi.deobfuscator.api.classpath;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.tree.ClassNode;
import software.coley.cafedude.InvalidClassException;
import uwu.narumi.deobfuscator.api.helper.ClassHelper;
import uwu.narumi.deobfuscator.api.helper.FileHelper;

import java.nio.file.Path;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ClassStorage implements ClassProvider {
private final Map<String, byte[]> compiledClasses = new ConcurrentHashMap<>();
private final Map<String, byte[]> files = new ConcurrentHashMap<>();

private final Map<String, ClassNode> classesInfo = new ConcurrentHashMap<>();

/**
* Adds jar to class storage
*
* @param jarPath Jar path
*/
public void addJar(@NotNull Path jarPath) {
FileHelper.loadFilesFromZip(jarPath, (classPath, bytes) -> {
if (!ClassHelper.isClass(classPath, bytes)) {
files.putIfAbsent(classPath, bytes);
return;
}

addRawClass(bytes);
});
}

public void addRawClass(byte[] bytes) {
try {
ClassNode classNode = ClassHelper.loadUnknownClassInfo(bytes);
String className = classNode.name;

// Add class to class storage
compiledClasses.putIfAbsent(className, bytes);
classesInfo.putIfAbsent(className, classNode);
} catch (InvalidClassException e) {
throw new RuntimeException(e);
}
}

@Override
public byte @Nullable [] getClass(String name) {
return compiledClasses.get(name);
}

@Override
public byte @Nullable [] getFile(String path) {
return files.get(path);
}

@Override
public @Nullable ClassNode getClassInfo(String name) {
return classesInfo.get(name);
}

@Override
public Collection<String> getLoadedClasses() {
return compiledClasses.keySet();
}

public Map<String, byte[]> compiledClasses() {
return compiledClasses;
}

public Map<String, byte[]> files() {
return files;
}

public Map<String, ClassNode> classesInfo() {
return classesInfo;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package uwu.narumi.deobfuscator.api.classpath;

import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.tree.ClassNode;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

public class CombinedClassProvider implements ClassProvider {
private final ClassProvider[] classProviders;

public CombinedClassProvider(ClassProvider... classProviders) {
this.classProviders = classProviders;
}

@Override
public byte @Nullable [] getClass(String name) {
for (ClassProvider classProvider : this.classProviders) {
byte[] bytes = classProvider.getClass(name);
if (bytes != null) return bytes;
}
return null;
}

@Override
public byte @Nullable [] getFile(String path) {
for (ClassProvider classProvider : this.classProviders) {
byte[] bytes = classProvider.getFile(path);
if (bytes != null) return bytes;
}
return null;
}

@Override
public @Nullable ClassNode getClassInfo(String name) {
for (ClassProvider classProvider : this.classProviders) {
ClassNode classInfo = classProvider.getClassInfo(name);
if (classInfo != null) return classInfo;
}
return null;
}

@Override
public Collection<String> getLoadedClasses() {
Set<String> classes = new HashSet<>();
for (ClassProvider classProvider : this.classProviders) {
classes.addAll(classProvider.getLoadedClasses());
}
return classes;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package uwu.narumi.deobfuscator.api.classpath;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.tree.ClassNode;
import uwu.narumi.deobfuscator.api.helper.ClassHelper;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* Classpath that fetches default JVM classes
*/
public class JvmClassProvider implements ClassProvider {
private static final Logger LOGGER = LogManager.getLogger();

public static final JvmClassProvider INSTANCE = new JvmClassProvider();

private final Map<String, byte[]> classesCache = new ConcurrentHashMap<>();
private final Map<String, ClassNode> classInfoCache = new ConcurrentHashMap<>();

private JvmClassProvider() {
}

@Override
public byte @Nullable [] getClass(String name) {
if (classesCache.containsKey(name)) {
return classesCache.get(name);
}

// Try to find it in classloader
byte[] value = null;
try (InputStream in = ClassLoader.getSystemResourceAsStream(name + ".class")) {
if (in != null) {
value = in.readAllBytes();
}
} catch (IOException ex) {
LOGGER.error("Failed to fetch runtime bytecode of class: {}", name, ex);
}

if (value == null) return null;

// Cache it!
classesCache.put(name, value);

return value;
}

@Override
public byte @Nullable [] getFile(String path) {
// JVM classpath doesn't have files
return null;
}

@Override
public @Nullable ClassNode getClassInfo(String name) {
if (classInfoCache.containsKey(name)) {
return classInfoCache.get(name);
}

byte[] bytes = getClass(name);
if (bytes == null) return null;

ClassNode classNode = ClassHelper.loadClassInfo(bytes);

// Cache it!
classInfoCache.put(name, classNode);

return classNode;
}

@Override
public Collection<String> getLoadedClasses() {
// We cannot determine all classes in JVM classpath
return List.of();
}
}
Loading

0 comments on commit 39c70d8

Please sign in to comment.