Extended The Malicious Code Scanner
The new system is designed to make creating a new scan module painless
This commit is contained in:
parent
b7deff48da
commit
10d4bcf1f5
16 changed files with 650 additions and 129 deletions
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
/**
|
||||
* 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<MaliciousCodeOptions> 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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<ClassNode> classNodeList;
|
||||
public final StringBuilder sb;
|
||||
public final HashSet<String> scanOptions;
|
||||
|
||||
public MalwareScan(ArrayList<ClassNode> classNodeList, StringBuilder sb, HashSet<String> scanOptions)
|
||||
{
|
||||
this.classNodeList = classNodeList;
|
||||
this.sb = sb;
|
||||
this.scanOptions = scanOptions;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) { }
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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<MaliciousCodeScannerOptionsV2.MaliciousCodeOptions> 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<MaliciousCodeScannerOptionsV2.MaliciousCodeOptions> options)
|
||||
{
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ArrayList<ClassNode> classNodeList) {
|
||||
public void execute(ArrayList<ClassNode> 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<String> 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);
|
||||
|
|
Loading…
Reference in a new issue