diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java index d6e59e4e..78fd6ead 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java @@ -13,6 +13,7 @@ import the.bytecode.club.bytecodeviewer.*; import the.bytecode.club.bytecodeviewer.api.ExceptionUI; import the.bytecode.club.bytecodeviewer.gui.components.*; import the.bytecode.club.bytecodeviewer.gui.plugins.MaliciousCodeScannerOptions; +import the.bytecode.club.bytecodeviewer.gui.plugins.MaliciousCodeScannerOptionsV2; import the.bytecode.club.bytecodeviewer.gui.plugins.ReplaceStringsOptions; import the.bytecode.club.bytecodeviewer.gui.resourcelist.ResourceListPane; import the.bytecode.club.bytecodeviewer.gui.resourcesearch.SearchBoxPane; @@ -566,7 +567,7 @@ public class MainViewerGUI extends JFrame openExternalPlugin.addActionListener(arg0 -> openExternalPlugin()); codeSequenceDiagram.addActionListener(arg0 -> CodeSequenceDiagram.open()); - maliciousCodeScanner.addActionListener(e -> MaliciousCodeScannerOptions.open()); + maliciousCodeScanner.addActionListener(e -> MaliciousCodeScannerOptionsV2.open()); showMainMethods.addActionListener(e -> PluginManager.runPlugin(new ShowMainMethods())); showAllStrings.addActionListener(e -> PluginManager.runPlugin(new ShowAllStrings())); replaceStrings.addActionListener(arg0 -> ReplaceStringsOptions.open()); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/plugins/MaliciousCodeScannerOptions.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/plugins/MaliciousCodeScannerOptions.java index 84689871..071f4bf8 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/plugins/MaliciousCodeScannerOptions.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/plugins/MaliciousCodeScannerOptions.java @@ -104,7 +104,7 @@ public class MaliciousCodeScannerOptions extends JFrame getContentPane().add(chckbxJavaawtrobot); JButton btnNewButton = new JButton("Start Scanning"); - btnNewButton.addActionListener(arg0 -> { + /*btnNewButton.addActionListener(arg0 -> { PluginManager.runPlugin(new MaliciousCodeScanner( chckbxJavalangreflection.isSelected(), chckbxJavalangruntime.isSelected(), @@ -117,7 +117,7 @@ public class MaliciousCodeScannerOptions extends JFrame chckbxNullSecMan.isSelected(), chckbxJavaawtrobot.isSelected())); dispose(); - }); + });*/ btnNewButton.setBounds(6, 264, 232, 23); getContentPane().add(btnNewButton); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/plugins/MaliciousCodeScannerOptionsV2.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/plugins/MaliciousCodeScannerOptionsV2.java new file mode 100644 index 00000000..ab3b4a6e --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/plugins/MaliciousCodeScannerOptionsV2.java @@ -0,0 +1,106 @@ +package the.bytecode.club.bytecodeviewer.gui.plugins; + +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.Resources; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareScanModule; +import the.bytecode.club.bytecodeviewer.plugin.PluginManager; +import the.bytecode.club.bytecodeviewer.plugin.preinstalled.MaliciousCodeScanner; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; + +/*************************************************************************** + * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * + * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +/** + * This GUI automatically populates the scan options from the MalwareScanModule enum. + * + * @author Konloch + */ + +public class MaliciousCodeScannerOptionsV2 extends JFrame +{ + private static final int SPACER_HEIGHT_BETWEEN_OPTIONS = 26; + + public static void open() + { + if (BytecodeViewer.getLoadedClasses().isEmpty()) + { + BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); + return; + } + + new MaliciousCodeScannerOptionsV2().setVisible(true); + } + + public MaliciousCodeScannerOptionsV2() + { + this.setIconImages(Resources.iconList); + setSize(new Dimension(250, 7+(MalwareScanModule.values().length * SPACER_HEIGHT_BETWEEN_OPTIONS)+90)); + setResizable(false); + setTitle("Malicious Code Scanner Options"); + getContentPane().setLayout(null); + ArrayList checkBoxes = new ArrayList<>(); + + int y = 7; + for(MalwareScanModule module : MalwareScanModule.values()) + { + final JCheckBox checkBox = new JCheckBox(module.getReadableName()); + checkBox.setSelected(module.isToggledByDefault()); //TODO + checkBox.setBounds(6, y, 232, 23); + getContentPane().add(checkBox); + checkBoxes.add(new MaliciousCodeOptions(module, checkBox)); + + y += SPACER_HEIGHT_BETWEEN_OPTIONS; + } + + JButton btnNewButton = new JButton("Start Scanning"); + btnNewButton.addActionListener(arg0 -> { + PluginManager.runPlugin(new MaliciousCodeScanner(checkBoxes)); + dispose(); + }); + + btnNewButton.setBounds(6, y, 232, 23); + getContentPane().add(btnNewButton); + this.setLocationRelativeTo(null); + } + + private static final long serialVersionUID = -2662514582647810868L; + + public static class MaliciousCodeOptions + { + private final MalwareScanModule module; + private final JCheckBox checkBox; + + public MaliciousCodeOptions(MalwareScanModule module, JCheckBox checkBox) { + this.module = module; + this.checkBox = checkBox; + } + + public JCheckBox getCheckBox() + { + return checkBox; + } + + public MalwareScanModule getModule() + { + return module; + } + } +} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/CodeScanner.java b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/CodeScanner.java new file mode 100644 index 00000000..5a3b2654 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/CodeScanner.java @@ -0,0 +1,19 @@ +package the.bytecode.club.bytecodeviewer.malwarescanner; + +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * @author Konloch + * @since 6/27/2021 + */ + +public interface CodeScanner +{ + void scanningClass(MalwareScan scan, ClassNode cn); + + void scanFields(MalwareScan scan, ClassNode cn, FieldNode[] fields); + + void scanMethods(MalwareScan scan, ClassNode cn, MethodNode[] methods); +} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/MalwareCodeScanner.java b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/MalwareCodeScanner.java new file mode 100644 index 00000000..39fb1b50 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/MalwareCodeScanner.java @@ -0,0 +1,93 @@ +package the.bytecode.club.bytecodeviewer.malwarescanner; + +import org.objectweb.asm.tree.*; +import the.bytecode.club.bytecodeviewer.malwarescanner.util.SearchableString; + +/** + * The base class for the malware code scanners + * + * @author Konloch + * @since 6/27/2021 + */ +public abstract class MalwareCodeScanner implements CodeScanner +{ + public abstract void scanFieldString(MalwareScan scan, ClassNode cn, FieldNode field, SearchableString string); + + public abstract void scanMethodString(MalwareScan scan, ClassNode cn, MethodNode method, SearchableString string); + + public abstract void scanMethodInstruction(MalwareScan scan, ClassNode cn, MethodNode method, AbstractInsnNode instruction); + + @Override + public void scanningClass(MalwareScan scan, ClassNode cn) + { + scanFields(scan, cn, cn.fields.toArray(new FieldNode[0])); + scanMethods(scan, cn, cn.methods.toArray(new MethodNode[0])); + } + + @Override + public void scanFields(MalwareScan scan, ClassNode cn, FieldNode[] fields) + { + for (FieldNode field : fields) + { + Object fieldValue = field.value; + + //scan strings + if (fieldValue instanceof String) + scanFieldString(scan, cn, field, new SearchableString((String) fieldValue)); + + //scan string array + else if (fieldValue instanceof String[]) + for(String s : (String[]) fieldValue) + scanFieldString(scan, cn, field, new SearchableString(s)); + } + } + + @Override + public void scanMethods(MalwareScan scan, ClassNode cn, MethodNode[] methods) + { + for (MethodNode method : methods) + { + InsnList instructionList = method.instructions; + + //scan each instruction + for (AbstractInsnNode instruction : instructionList.toArray()) + { + scanMethodInstruction(scan, cn, method, instruction); + + if (instruction instanceof LdcInsnNode) + { + if (((LdcInsnNode) instruction).cst instanceof String) + { + final String string = (String) ((LdcInsnNode) instruction).cst; + scanMethodString(scan, cn, method, new SearchableString(string)); + } + } + } + } + } + + public String fieldToString(ClassNode cn, FieldNode field) + { + return cn.name + "." + field.name + "(" + field.desc + ")"; + } + + public String methodToString(ClassNode cn, MethodNode method) + { + return cn.name + "." + method.name + "(" + method.desc + ")"; + } + + public void foundLDC(MalwareScan scan, String ldc, String foundAt) + { + scan.sb.append("Found LDC \"").append(ldc).append("\" ").append(foundAt); + } + + public void foundMethod(MalwareScan scan, String foundAt) + { + scan.sb.append("Found Method call to ").append(foundAt); + } + + public void found(MalwareScan scan, String found) + { + scan.sb.append("Found ").append(found); + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/MalwareScan.java b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/MalwareScan.java new file mode 100644 index 00000000..4e18980e --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/MalwareScan.java @@ -0,0 +1,29 @@ +package the.bytecode.club.bytecodeviewer.malwarescanner; + +import org.objectweb.asm.tree.ClassNode; + +import java.util.ArrayList; +import java.util.HashSet; + +/** + * A new malware scan object is created any time the MalicousCodeScanner plugin is ran + * + * This contains all of the details for the scan, including what should be scanned, + * and what was detected during the scan. + * + * @author Konloch + * @since 6/27/2021 + */ +public class MalwareScan +{ + public final ArrayList classNodeList; + public final StringBuilder sb; + public final HashSet scanOptions; + + public MalwareScan(ArrayList classNodeList, StringBuilder sb, HashSet scanOptions) + { + this.classNodeList = classNodeList; + this.sb = sb; + this.scanOptions = scanOptions; + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/MalwareScanModule.java b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/MalwareScanModule.java new file mode 100644 index 00000000..8c417271 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/MalwareScanModule.java @@ -0,0 +1,57 @@ +package the.bytecode.club.bytecodeviewer.malwarescanner; + +import org.objectweb.asm.tree.ClassNode; +import the.bytecode.club.bytecodeviewer.malwarescanner.impl.*; + +/** + * All of the installed malware scan modules + * + * @author Konloch + * @since 6/27/2021 + */ +public enum MalwareScanModule +{ + URL_SCANNER("Scan String URLs", new URLScanner(), true), + REFLECTION_SCANNER("Scan Java Reflection", new ReflectionScanner(), true), + JAVA_RUNTIME_SCANNER("Scan Java Runtime", new JavaRuntimeScanner(), true), + JAVA_NET_SCANNER("Scan Java Net", new JavaNetScanner(), true), + JAVA_IO_SCANNER("Scan Java IO", new JavaIOScanner(), false), + AWT_ROBOT_SCANNER("Scan AWT Robot", new AWTRobotScanner(), true), + NULL_SECURITY_MANAGER("Scan Null SecurityManager", new NullSecurityManagerScanner(), true), + ; + + private final String readableName; + private final CodeScanner codeScanner; + private final boolean toggledByDefault; + + MalwareScanModule(String readableName, CodeScanner codeScanner, boolean toggledByDefault) { + this.readableName = readableName; + this.codeScanner = codeScanner; + this.toggledByDefault = toggledByDefault; + } + + public String getReadableName() + { + return readableName; + } + + public CodeScanner getCodeScanner() + { + return codeScanner; + } + + public boolean isToggledByDefault() + { + return toggledByDefault; + } + + public static void performScan(MalwareScan scan) + { + for (ClassNode cn : scan.classNodeList) + { + for (MalwareScanModule module : values()) + if(scan.scanOptions.contains(module.name())) + module.codeScanner.scanningClass(scan, cn); + } + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/AWTRobotScanner.java b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/AWTRobotScanner.java new file mode 100644 index 00000000..74c70f52 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/AWTRobotScanner.java @@ -0,0 +1,44 @@ +package the.bytecode.club.bytecodeviewer.malwarescanner.impl; + +import org.objectweb.asm.tree.*; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareCodeScanner; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareScan; +import the.bytecode.club.bytecodeviewer.malwarescanner.util.SearchableString; + +import static the.bytecode.club.bytecodeviewer.Constants.nl; + +/** + * Scans for any trace of java/awt/Robot inside of method instructions and strings + * + * @author Konloch + * @since 6/27/2021 + */ +public class AWTRobotScanner extends MalwareCodeScanner +{ + @Override + public void scanFieldString(MalwareScan scan, ClassNode cn, FieldNode field, SearchableString string) + { + if(string.searchable.contains("java/awt/Robot") + || string.searchable.contains("java.awt.Robot")) + foundLDC(scan, string.original, "at field " + fieldToString(cn, field) + nl); + } + + @Override + public void scanMethodString(MalwareScan scan, ClassNode cn, MethodNode method, SearchableString string) + { + if(string.searchable.contains("java/awt/Robot") + || string.searchable.contains("java.awt.Robot")) + foundLDC(scan, string.original, "at method " + methodToString(cn, method) + nl); + } + + @Override + public void scanMethodInstruction(MalwareScan scan, ClassNode cn, MethodNode method, AbstractInsnNode instruction) + { + if (instruction instanceof MethodInsnNode) + { + final MethodInsnNode min = (MethodInsnNode) instruction; + if (min.owner.startsWith("java/awt/Robot")) + foundMethod(scan, methodToString(cn, method) + nl); + } + } +} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/JavaIOScanner.java b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/JavaIOScanner.java new file mode 100644 index 00000000..f40dbeae --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/JavaIOScanner.java @@ -0,0 +1,32 @@ +package the.bytecode.club.bytecodeviewer.malwarescanner.impl; + +import org.objectweb.asm.tree.*; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareScan; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareCodeScanner; +import the.bytecode.club.bytecodeviewer.malwarescanner.util.SearchableString; + +import static the.bytecode.club.bytecodeviewer.Constants.nl; + +/** + * @author Konloch + * @since 6/27/2021 + */ +public class JavaIOScanner extends MalwareCodeScanner +{ + @Override + public void scanFieldString(MalwareScan scan, ClassNode cn, FieldNode field, SearchableString string) { } + + @Override + public void scanMethodString(MalwareScan scan, ClassNode cn, MethodNode method, SearchableString string) { } + + @Override + public void scanMethodInstruction(MalwareScan scan, ClassNode cn, MethodNode method, AbstractInsnNode instruction) + { + if (instruction instanceof MethodInsnNode) + { + final MethodInsnNode min = (MethodInsnNode) instruction; + if (min.owner.startsWith("java/io")) + foundMethod(scan, methodToString(cn, method) + nl); + } + } +} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/JavaNetScanner.java b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/JavaNetScanner.java new file mode 100644 index 00000000..5f786386 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/JavaNetScanner.java @@ -0,0 +1,33 @@ +package the.bytecode.club.bytecodeviewer.malwarescanner.impl; + +import org.objectweb.asm.tree.*; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareScan; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareCodeScanner; +import the.bytecode.club.bytecodeviewer.malwarescanner.util.SearchableString; + +import static the.bytecode.club.bytecodeviewer.Constants.nl; + +/** + * @author Konloch + * @author WaterWolf + * @since 6/27/2021 + */ +public class JavaNetScanner extends MalwareCodeScanner +{ + @Override + public void scanFieldString(MalwareScan scan, ClassNode cn, FieldNode field, SearchableString string) { } + + @Override + public void scanMethodString(MalwareScan scan, ClassNode cn, MethodNode method, SearchableString string) { } + + @Override + public void scanMethodInstruction(MalwareScan scan, ClassNode cn, MethodNode method, AbstractInsnNode instruction) + { + if (instruction instanceof MethodInsnNode) + { + final MethodInsnNode min = (MethodInsnNode) instruction; + if (min.owner.startsWith("java/net")) + foundMethod(scan, methodToString(cn, method) + nl); + } + } +} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/JavaRuntimeScanner.java b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/JavaRuntimeScanner.java new file mode 100644 index 00000000..948b87f5 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/JavaRuntimeScanner.java @@ -0,0 +1,44 @@ +package the.bytecode.club.bytecodeviewer.malwarescanner.impl; + +import org.objectweb.asm.tree.*; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareScan; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareCodeScanner; +import the.bytecode.club.bytecodeviewer.malwarescanner.util.SearchableString; + +import static the.bytecode.club.bytecodeviewer.Constants.nl; + +/** + * Scans for any trace of java/lang/Runtime inside of method instructions and strings + * + * @author Konloch + * @since 6/27/2021 + */ +public class JavaRuntimeScanner extends MalwareCodeScanner +{ + @Override + public void scanFieldString(MalwareScan scan, ClassNode cn, FieldNode field, SearchableString string) + { + if(string.searchable.contains("java/lang/Runtime") + || string.searchable.contains("java.lang.Runtime")) + foundLDC(scan, string.original, "at field " + fieldToString(cn, field) + nl); + } + + @Override + public void scanMethodString(MalwareScan scan, ClassNode cn, MethodNode method, SearchableString string) + { + if(string.searchable.contains("java/lang/Runtime") + || string.searchable.contains("java.lang.Runtime")) + foundLDC(scan, string.original, "at method " + methodToString(cn, method) + nl); + } + + @Override + public void scanMethodInstruction(MalwareScan scan, ClassNode cn, MethodNode method, AbstractInsnNode instruction) + { + if (instruction instanceof MethodInsnNode) + { + final MethodInsnNode min = (MethodInsnNode) instruction; + if (min.owner.startsWith("java/lang/Runtime")) + foundMethod(scan, methodToString(cn, method) + nl); + } + } +} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/NullSecurityManagerScanner.java b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/NullSecurityManagerScanner.java new file mode 100644 index 00000000..3e1eae26 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/NullSecurityManagerScanner.java @@ -0,0 +1,55 @@ +package the.bytecode.club.bytecodeviewer.malwarescanner.impl; + +import com.strobel.assembler.ir.OpCode; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.*; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareCodeScanner; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareScan; +import the.bytecode.club.bytecodeviewer.malwarescanner.util.SearchableString; + +import static the.bytecode.club.bytecodeviewer.Constants.nl; + +/** + * Checks for the security manager getting set to null + * + * @author Konloch + * @author Adrianherrera + * @since 6/27/2021 + */ +public class NullSecurityManagerScanner extends MalwareCodeScanner +{ + private int lastInstruction; + + @Override + public void scanFieldString(MalwareScan scan, ClassNode cn, FieldNode field, SearchableString string) { } + + @Override + public void scanMethodString(MalwareScan scan, ClassNode cn, MethodNode method, SearchableString string) { } + + @Override + public void scanMethodInstruction(MalwareScan scan, ClassNode cn, MethodNode method, AbstractInsnNode instruction) + { + if (instruction instanceof MethodInsnNode && instruction.getOpcode() == Opcodes.INVOKESTATIC) + { + final MethodInsnNode min = (MethodInsnNode) instruction; + final String owner = min.owner; + final String name = min.name; + + if(lastInstruction == OpCode.ACONST_NULL.getCode() + && owner.equals("java/lang/System") + && name.equals("setSecurityManager")) + { + found(scan, "Security Manager set to null at method " + methodToString(cn, method) + nl); + } + } + + lastInstruction = instruction.getOpcode(); + } + + @Override + public void scanningClass(MalwareScan scan, ClassNode cn) + { + lastInstruction = 0; + super.scanningClass(scan, cn); + } +} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/ReflectionScanner.java b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/ReflectionScanner.java new file mode 100644 index 00000000..dae795dd --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/ReflectionScanner.java @@ -0,0 +1,35 @@ +package the.bytecode.club.bytecodeviewer.malwarescanner.impl; + +import org.objectweb.asm.tree.*; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareScan; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareCodeScanner; +import the.bytecode.club.bytecodeviewer.malwarescanner.util.SearchableString; + +import static the.bytecode.club.bytecodeviewer.Constants.nl; + +/** + * Scans for method instructions containing java/lang/reflect + * + * @author Konloch + * @author WaterWolf + * @since 6/27/2021 + */ +public class ReflectionScanner extends MalwareCodeScanner +{ + @Override + public void scanFieldString(MalwareScan scan, ClassNode cn, FieldNode field, SearchableString string) { } + + @Override + public void scanMethodString(MalwareScan scan, ClassNode cn, MethodNode method, SearchableString string) { } + + @Override + public void scanMethodInstruction(MalwareScan scan, ClassNode cn, MethodNode method, AbstractInsnNode instruction) + { + if (instruction instanceof MethodInsnNode) + { + final MethodInsnNode min = (MethodInsnNode) instruction; + if (min.owner.startsWith("java/lang/reflect")) + foundMethod(scan, methodToString(cn, method) + nl); + } + } +} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/URLScanner.java b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/URLScanner.java new file mode 100644 index 00000000..9c4ed170 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/impl/URLScanner.java @@ -0,0 +1,49 @@ +package the.bytecode.club.bytecodeviewer.malwarescanner.impl; + +import org.objectweb.asm.tree.*; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareScan; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareCodeScanner; +import the.bytecode.club.bytecodeviewer.malwarescanner.util.SearchableString; + +import java.util.regex.Pattern; + +import static the.bytecode.club.bytecodeviewer.Constants.nl; + +/** + * Scans strings for common URL patterns: + * Any string containing www + * Any string containing http:// + * Any string containing https:// + * Any string matching an IP pattern + * + * @author Konloch + * @author WaterWolf + * @since 6/27/2021 + */ +public class URLScanner extends MalwareCodeScanner +{ + private static final Pattern ipPattern = Pattern.compile("\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b"); + + @Override + public void scanFieldString(MalwareScan scan, ClassNode cn, FieldNode field, SearchableString string) + { + if (string.searchable.contains("www.") + || string.searchable.contains("http://") + || string.searchable.contains("https://") + || ipPattern.matcher(string.searchable).matches()) + foundLDC(scan, string.original, "at field " + fieldToString(cn, field) + nl); + } + + @Override + public void scanMethodString(MalwareScan scan, ClassNode cn, MethodNode method, SearchableString string) + { + if (string.searchable.contains("www.") + || string.searchable.contains("http://") + || string.searchable.contains("https://") + || ipPattern.matcher(string.searchable).matches()) + foundLDC(scan, string.original, "at method " + methodToString(cn, method) + nl); + } + + @Override + public void scanMethodInstruction(MalwareScan scan, ClassNode cn, MethodNode method, AbstractInsnNode instruction) { } +} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/util/SearchableString.java b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/util/SearchableString.java new file mode 100644 index 00000000..ef09a7db --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/malwarescanner/util/SearchableString.java @@ -0,0 +1,17 @@ +package the.bytecode.club.bytecodeviewer.malwarescanner.util; + +/** + * @author Konloch + * @since 6/27/2021 + */ +public class SearchableString +{ + public final String original; + public final String searchable; + + public SearchableString(String original) + { + this.original = original; + this.searchable = original.toLowerCase(); + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/MaliciousCodeScanner.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/MaliciousCodeScanner.java index 25d690a9..e5af7e7c 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/MaliciousCodeScanner.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/MaliciousCodeScanner.java @@ -1,20 +1,18 @@ package the.bytecode.club.bytecodeviewer.plugin.preinstalled; import java.util.ArrayList; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; +import java.util.HashSet; +import java.util.List; + import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldNode; -import org.objectweb.asm.tree.InsnList; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.LdcInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.MethodNode; -import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.api.Plugin; import the.bytecode.club.bytecodeviewer.api.PluginConsole; +import the.bytecode.club.bytecodeviewer.gui.plugins.MaliciousCodeScannerOptions; +import the.bytecode.club.bytecodeviewer.gui.plugins.MaliciousCodeScannerOptionsV2; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareScan; +import the.bytecode.club.bytecodeviewer.malwarescanner.MalwareScanModule; -import static the.bytecode.club.bytecodeviewer.Constants.*; +import javax.swing.*; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -35,134 +33,43 @@ import static the.bytecode.club.bytecodeviewer.Constants.*; ***************************************************************************/ /** - * The idea/core was based off of J-RET's Malicious Code Searcher I improved it, - * and added more stuff to search for. + * The Malicious Code Scanner plugin. All of the core components have been moved to the malwarescanner package. + * + * This tool is used to help aid reverse engineers in identifying malicious code. * * @author Konloch * @author Adrianherrera * @author WaterWolf + * @since 10/02/2011 */ -public class MaliciousCodeScanner extends Plugin { +public class MaliciousCodeScanner extends Plugin +{ + public final List options; - public boolean ORE, ONE, ORU, OIO, LWW, LHT, LHS, LIP, NSM, ROB; - - public MaliciousCodeScanner(boolean reflect, boolean runtime, boolean net, - boolean io, boolean www, boolean http, boolean https, boolean ip, - boolean nullSecMan, boolean robot) { - ORE = reflect; - ONE = net; - ORU = runtime; - OIO = io; - LWW = www; - LHT = http; - LHS = https; - LIP = ip; - NSM = nullSecMan; - ROB = robot; + public MaliciousCodeScanner(List options) + { + this.options = options; } @Override - public void execute(ArrayList classNodeList) { + public void execute(ArrayList classNodeList) + { PluginConsole frame = new PluginConsole("Malicious Code Scanner"); StringBuilder sb = new StringBuilder(); - for (ClassNode classNode : classNodeList) { - for (Object o : classNode.fields.toArray()) { - FieldNode f = (FieldNode) o; - Object v = f.value; - if (v instanceof String) { - String s = (String) v; - if ((LWW && s.contains("www.")) - || (LHT && s.contains("http://")) - || (LHS && s.contains("https://")) - || (ORE && s.contains("java/lang/Runtime")) - || (ORE && s.contains("java.lang.Runtime")) - || (ROB && s.contains("java.awt.Robot")) - || (ROB && s.contains("java/awt/Robot")) - || (LIP && s - .matches("\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b"))) - sb.append("Found LDC \"").append(s).append("\" at field ").append(classNode.name).append(".") - .append(f.name).append("(").append(f.desc).append(")").append(nl); - } - if (v instanceof String[]) { - for (int i = 0; i < ((String[]) v).length; i++) { - String s = ((String[]) v)[i]; - if ((LWW && s.contains("www.")) - || (LHT && s.contains("http://")) - || (LHS && s.contains("https://")) - || (ORE && s.contains("java/lang/Runtime")) - || (ORE && s.contains("java.lang.Runtime")) - || (ROB && s.contains("java.awt.Robot")) - || (ROB && s.contains("java/awt/Robot")) - || (LIP && s - .matches("\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b"))) - sb.append("Found LDC \"").append(s).append("\" at field ").append(classNode.name) - .append(".").append(f.name).append("(").append(f.desc).append(")") - .append(nl); - } - } - } - - boolean prevInsn_aconst_null = false; - - for (Object o : classNode.methods.toArray()) { - MethodNode m = (MethodNode) o; - - InsnList iList = m.instructions; - for (AbstractInsnNode a : iList.toArray()) { - if (a instanceof MethodInsnNode) { - final MethodInsnNode min = (MethodInsnNode) a; - if ((ORE && min.owner.startsWith("java/lang/reflect")) - || (ONE && min.owner.startsWith("java/net")) - || (ORU && min.owner.equals("java/lang/Runtime")) - || (ROB && min.owner.equals("java/awt/Robot")) - || (OIO && min.owner.startsWith("java/io"))) { - sb.append("Found Method call to ").append(min.owner).append(".").append(min.name) - .append("(").append(min.desc).append(") at ").append(classNode.name).append(".") - .append(m.name).append("(").append(m.desc).append(")").append(nl); - } - } - if (a instanceof LdcInsnNode) { - if (((LdcInsnNode) a).cst instanceof String) { - final String s = (String) ((LdcInsnNode) a).cst; - if ((LWW && s.contains("www.")) - || (LHT && s.contains("http://")) - || (LHS && s.contains("https://")) - || (ORE && s.contains("java/lang/Runtime")) - || (ORE && s.contains("java.lang.Runtime")) - || (ROB && s.contains("java.awt.Robot")) - || (ROB && s.contains("java/awt/Robot")) - || (LIP && s - .matches("\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b"))) { - sb.append("Found LDC \"").append(s).append("\" at method ").append(classNode.name) - .append(".").append(m.name).append("(").append(m.desc).append(")") - .append(nl); - } - } - } - - // Check if the security manager is getting set to null - if ((a instanceof InsnNode) - && (a.getOpcode() == Opcodes.ACONST_NULL)) { - prevInsn_aconst_null = true; - } else if ((a instanceof MethodInsnNode) - && (a.getOpcode() == Opcodes.INVOKESTATIC)) { - final String owner = ((MethodInsnNode) a).owner; - final String name = ((MethodInsnNode) a).name; - if ((NSM && prevInsn_aconst_null - && owner.equals("java/lang/System") && name - .equals("setSecurityManager"))) { - sb.append("Found Security Manager set to null at method ").append(classNode.name) - .append(".").append(m.name).append("(").append(m.desc).append(")") - .append(nl); - prevInsn_aconst_null = false; - } - } else { - prevInsn_aconst_null = false; - } - } - } - } + + //TODO automate this when the GUI has been changed + HashSet scanOptions = new HashSet<>(); + + for(MaliciousCodeScannerOptionsV2.MaliciousCodeOptions option : options) + if(option.getCheckBox().isSelected()) + scanOptions.add(option.getModule().name()); + + //create a new code scan object with all of the scan options + MalwareScan scan = new MalwareScan(classNodeList, sb, scanOptions); + + //scan the modules one by one + MalwareScanModule.performScan(scan); frame.appendText(sb.toString()); frame.setVisible(true);