package net.jscanner.archive;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.objectweb.asm.Handle;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import com.google.gson.Gson;
import com.tonicsystems.jarjar.asm.Opcodes;
/**
* Scans archives for malicious bytecode instructions.
*
* @author Desmond Jackson
*/
public class ArchiveScanner {
/**
* The archive to scan.
*/
private Archive archive;
/**
* The method instructions nodes found in the archive.
*/
private List<MethodInsnNode> methodInstructionNodes;
/**
* Creates a new archive scanner.
*
* @param archive The archive to scan
*/
public ArchiveScanner(Archive archive) {
this.archive = archive;
methodInstructionNodes = findMethodInstructionNodes();
}
/**
* Finds method instruction nodes in the archive.
*
* @return The method instruction nodes found in the archive
*/
private List<MethodInsnNode> findMethodInstructionNodes() {
List<MethodInsnNode> invocations = new ArrayList<MethodInsnNode>();
for (ClassNode node : archive) for (Object object : node.methods.toArray())
if (object instanceof MethodNode)
for (AbstractInsnNode ain : ((MethodNode) object).instructions.toArray())
if (ain instanceof MethodInsnNode)
invocations.add((MethodInsnNode) ain);
else if (ain instanceof InvokeDynamicInsnNode) {
Handle handle = ((InvokeDynamicInsnNode) ain).bsm;
invocations.add(new MethodInsnNode(Opcodes.INVOKEDYNAMIC, handle.getOwner(), handle.getName(), handle.getDesc(), handle.isInterface()));
}
return invocations;
}
/**
* Scans the archive for the specified class map of threats.
*
* @param threats A map of threatening classes and their methods
*
* @return The threats found in the archive in JSON format
*/
public String scan(Map<String, List<String>> threats) {
Map<String, List<String>> found = new HashMap<String, List<String>>();
for (MethodInsnNode min : methodInstructionNodes) {
String clazz = min.owner; String method = min.name;
for (Entry<String, List<String>> entry : threats.entrySet())
if (entry.getKey().equals(clazz)) {
if (!found.containsKey(clazz))
found.put(clazz, new ArrayList<String>());
if (entry.getValue().contains(method) && !found.get(clazz).contains(method))
found.get(clazz).add(method);
}
}
return new Gson().toJson(found);
}
}