From e12ac8e5bc756ae850e478b4ce687256648fddad Mon Sep 17 00:00:00 2001 From: IkeVoodoo <55694349+IkeVoodoo@users.noreply.github.com> Date: Fri, 25 Aug 2023 12:31:19 +0200 Subject: [PATCH 1/4] Refactored method --- .../antimalware/utils/Utils.java | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/utils/Utils.java b/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/utils/Utils.java index 55206571..8a0a26ac 100644 --- a/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/utils/Utils.java +++ b/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/utils/Utils.java @@ -187,23 +187,25 @@ private static List getAuthors(FileConfiguration config, String field) { public static FileSystem fileSystemForZip(final Path pathToZip) throws IOException { try { - try { - return FileSystems.newFileSystem(pathToZip, new HashMap<>()); - } catch (IOException e) { - try { - return FileSystems.getFileSystem(URI.create("jar:" + pathToZip.toUri() + "!/")); - } catch (Exception e2) { - try { - return FileSystems.newFileSystem(URI.create("jar:" + pathToZip.toUri() + "!/"), new HashMap<>()); - } catch (IOException e3) { - return null; - } - } - } - } catch (Exception e) { - LOGGER.warn("Couldn't get FileSystem for " + pathToZip.toString()); - return null; + return FileSystems.newFileSystem(pathToZip, new HashMap<>()); + } catch (IOException ignored) { + // Ignore this exception, we can try again } + + try { + return FileSystems.getFileSystem(URI.create("jar:" + pathToZip.toUri() + "!/")); + } catch (Exception ignored) { + // Ignore this exception, we can try again + } + + try { + return FileSystems.newFileSystem(URI.create("jar:" + pathToZip.toUri() + "!/"), new HashMap<>()); + } catch (IOException ignored) { + // Ignore this exception, we can try again + } + + LOGGER.warn("Couldn't get FileSystem for " + pathToZip); + return null; } public static void unzip(ZipFile source, File destination) throws IOException { From 5a7271ee028be245b94f4902247f009b17db3e42 Mon Sep 17 00:00:00 2001 From: IkeVoodoo <55694349+IkeVoodoo@users.noreply.github.com> Date: Fri, 25 Aug 2023 12:32:12 +0200 Subject: [PATCH 2/4] Created scan helper --- .../antimalware/scanner/ScanHelper.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/scanner/ScanHelper.java diff --git a/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/scanner/ScanHelper.java b/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/scanner/ScanHelper.java new file mode 100644 index 00000000..8c73ebf6 --- /dev/null +++ b/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/scanner/ScanHelper.java @@ -0,0 +1,24 @@ +package optic_fusion1.antimalware.scanner; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static optic_fusion1.antimalware.AntiMalware.LOGGER; + +public final class ScanHelper { + + private ScanHelper() { + + } + + public static boolean isFileEmpty(Path path) { + try { + return Files.size(path) == 0; + } catch (IOException e) { + LOGGER.exception(e); + return false; + } + } + +} From 4e036654dbd580b36726e4939be1dae6f33f5791 Mon Sep 17 00:00:00 2001 From: IkeVoodoo <55694349+IkeVoodoo@users.noreply.github.com> Date: Fri, 25 Aug 2023 13:04:15 +0200 Subject: [PATCH 3/4] Moved file scanning, pray to your God(s) that this may work --- .../antimalware/scanner/Scanner.java | 385 ++--------------- .../antimalware/scanner/file/FileScanner.java | 390 ++++++++++++++++++ 2 files changed, 416 insertions(+), 359 deletions(-) create mode 100644 MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/scanner/file/FileScanner.java diff --git a/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/scanner/Scanner.java b/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/scanner/Scanner.java index 198a6adc..14b4e95d 100644 --- a/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/scanner/Scanner.java +++ b/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/scanner/Scanner.java @@ -16,10 +16,21 @@ */ package optic_fusion1.antimalware.scanner; +import optic_fusion1.antimalware.AntiMalware; +import optic_fusion1.antimalware.CommandLineParser; +import optic_fusion1.antimalware.check.BaseCheck; +import optic_fusion1.antimalware.check.CacheContainer; +import optic_fusion1.antimalware.check.CheckManager; +import optic_fusion1.antimalware.check.CheckResult; +import optic_fusion1.antimalware.database.Database; +import optic_fusion1.antimalware.notifications.NotificationHandler; +import optic_fusion1.antimalware.scanner.file.FileScanner; +import org.apache.commons.io.FileUtils; +import org.objectweb.asm.tree.ClassNode; + import java.io.File; import java.io.IOException; import java.io.PrintWriter; -import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.nio.file.FileSystem; import java.nio.file.Files; @@ -42,35 +53,15 @@ import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import optic_fusion1.antimalware.AntiMalware; + import static optic_fusion1.antimalware.AntiMalware.LOGGER; -import optic_fusion1.antimalware.CommandLineParser; -import optic_fusion1.antimalware.check.BaseCheck; -import optic_fusion1.antimalware.check.CacheContainer; -import optic_fusion1.antimalware.check.CheckManager; -import optic_fusion1.antimalware.check.CheckResult; -import optic_fusion1.antimalware.database.Database; -import optic_fusion1.antimalware.notifications.NotificationHandler; import static optic_fusion1.antimalware.utils.I18n.tl; import static optic_fusion1.antimalware.utils.Utils.fileSystemForZip; import static optic_fusion1.antimalware.utils.Utils.unzip; import static optic_fusion1.antimalware.utils.Utils.validClassPath; -import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.io.FileUtils; -import org.objectweb.asm.tree.ClassNode; public class Scanner extends Thread { - private static final Path ANTI_MALWARE_PATH; - - static { - try { - ANTI_MALWARE_PATH = new File(AntiMalware.class.getProtectionDomain().getCodeSource().getLocation().toURI()).toPath(); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } - } - private static final Queue SCANNABLE_FILES = new ConcurrentLinkedQueue<>(); private final ThreadPoolExecutor executorService; protected final AntiMalware antiMalware; @@ -78,18 +69,24 @@ public class Scanner extends Thread { protected final CheckManager checkManager; protected final CommandLineParser commandLineParser; private final NotificationHandler notificationHandler; - private final Database database; protected File unzipDirectory; - private Path zippedFilePath; - private final CacheContainer cache; + private final FileScanner fileScanner; public Scanner(AntiMalware antiMalware, File scanDirectory) { setName("AntiMalware/Scanner"); this.antiMalware = antiMalware; - database = antiMalware.getDatabase(); - cache = antiMalware.getCache(); + checkManager = antiMalware.getCheckManager(); commandLineParser = antiMalware.getCommandLineParser(); + + this.fileScanner = new FileScanner( + antiMalware.getCache(), + antiMalware.getDatabase(), + this.commandLineParser, + this.checkManager, + this::sendNotification + ); + if (commandLineParser.shouldScanZippedFiles()) { unzipDirectory = new File("AntiMalware", "unzipped"); if (!unzipDirectory.exists()) { @@ -112,7 +109,8 @@ public void run() { if (file == null) { return; } - scanFile(file); + + this.fileScanner.scanFile(file); } catch (Exception e) { LOGGER.exception(e); } @@ -131,280 +129,10 @@ public void scanFiles() { } } - private void scanZip(Path zippedFile) { - LOGGER.info("Unzipping " + zippedFile); - File destination = new File(unzipDirectory, UUID.randomUUID().toString()); - zippedFilePath = zippedFile; - if (!destination.exists()) { - destination.mkdirs(); - } - try { - unzip(new ZipFile(zippedFile.toFile()), destination); - File file = new File(destination, ".info"); - file.createNewFile(); - try (PrintWriter pw = new PrintWriter(file)) { - pw.write(zippedFile.toString()); - } - for (File foundDir : destination.listFiles()) { - if (foundDir.isDirectory()) { - scanDirectory(foundDir.toPath()); - continue; - } - scanFile(foundDir.toPath()); - } - } catch (IOException ex) { - Logger.getLogger(Scanner.class.getName()).log(Level.SEVERE, null, ex); - } - } - - private void scanDirectory(Path directory) { - if (!Files.isDirectory(directory)) { - scanFile(directory); - return; - } - try { - Files.list(directory).forEach((path) -> { - if (path.getFileSystem().isOpen()) { - if (Files.isDirectory(path)) { - scanDirectory(path); - } else { - scanFile(path); - } - } - }); - } catch (IOException e) { - LOGGER.exception(e); - } - } - - private void scanFile(Path file) { - if (Files.isDirectory(file)) { - scanDirectory(file); - return; - } - String fileName = file.getFileName().toString(); - if (cache.containsBlacklistedFileName(fileName)) { - try { - CheckResult result = database.getCheckResultForFileName(fileName); - if (result != null) { - sendNotification(file.toAbsolutePath(), result); - } -// return; - } catch (SQLException ex) { - LOGGER.exception(ex); - } - } - if (fileName.equals("VaultLib.jar")) { - sendNotification(file.toAbsolutePath(), new CheckResult("Spigot", "MALWARE", "Qlutch", "C")); -// return; - } - if (cache.containsBlacklistedFilePath(file.toString())) { - try { - CheckResult result = database.getCheckResultForFilePath(file.toString()); - if (result != null) { - sendNotification(file.toAbsolutePath(), result); - } -// return; - } catch (SQLException ex) { - LOGGER.exception(ex); - } - } - if (!fileName.endsWith(".jar") && !fileName.endsWith(".zip") && !fileName.endsWith(".rar") && !isPlugin(file)) { - return; - } - try { - if (Files.size(file) == 0) { - return; - } - } catch (IOException e) { - LOGGER.exception(e); - return; - } - String checksum = cache.fetchSHA1(file, file); - if (checksum == null) { - LOGGER.warn("The SHA-1 checksum for '" + file + "' couldn't be loaded"); - } else { - checksum = checksum.toUpperCase(); - if (cache.containsBlacklistedChecksum(checksum)) { - try { - CheckResult checkResult = database.getCheckResultForChecksum(checksum); - if (checkResult != null) { - if (commandLineParser.dontLogINFOCR() && checkResult.getType().equals("INFO")) { - return; - } - sendNotification(file, checkResult); -// return; - } - System.out.println(tl("scanner_blacklisted_not_in_database", file)); - } catch (SQLException ex) { - LOGGER.exception(ex); - } - } - } - try (FileSystem fs = fileSystemForZip(file)) { - if (fs == null) { - return; - } - Path rootFolder = fs.getRootDirectories().iterator().next(); - if (commandLineParser.shouldScanZippedFiles()) { - if (fileName.endsWith(".zip") || fileName.endsWith(".rar")) { - scanZip(file); - return; - } - } - WhitelistResult result = isFileWhitelisted(file); - if (result == WhitelistResult.INVALID_FILE || result == WhitelistResult.WHITELISTED) { - return; - } - - // TODO: Make this a separate check - if (Files.exists(rootFolder.resolve("dev/jnic/lib/"))) { - sendNotification(file, new CheckResult("Spigot", "Malware", "JNIC")); -// return; - } - - // TODO: Make these a separate check - if (Files.exists(rootFolder.resolve("plugin-config.bin"))) { - sendNotification(file, new CheckResult("Spigot", "Malware", "SG")); -// return; - } - - if (Files.exists(rootFolder.resolve("META-INF/gradle/org/apache/commons/local-info.hdm"))) { - sendNotification(file, new CheckResult("Spigot", "Malware", "SG", "B")); -// return; - } - - if (Files.exists(rootFolder.resolve("META-INF/gradle/io/netty/netty-locals.netd"))) { - sendNotification(file, new CheckResult("Spigot", "Malware", "SG", "C")); -// return; - } - - if (Files.exists(rootFolder.resolve("META-INF/maven/org/apache/logging/log4j/Log4j-events.dtd"))) { - sendNotification(file, new CheckResult("Spigot", "Malware", "SG", "D")); -// return; - } - - if (Files.exists(rootFolder.resolve("META-INF/gradle/org/apache/logging/log4j/Log4j-events.dtd"))) { - sendNotification(file, new CheckResult("Spigot", "Malware", "SG", "E")); -// return; - } - - if (Files.exists(rootFolder.resolve("META-INF/gradle/org.json/json/json.xsd"))) { - sendNotification(file, new CheckResult("Spigot", "Malware", "SG", "F")); -// return; - } - - if (Files.exists(rootFolder.resolve("META-INF/maven/org/apache/commons/api-catch.dir"))) { - sendNotification(file, new CheckResult("Spigot", "Malware", "SG", "G")); -// return; - } - - if (Files.exists(rootFolder.resolve("META-INF/maven/org/apache/commons/local-dir.hum"))) { - sendNotification(file, new CheckResult("Spigot", "Malware", "SG", "H")); -// return; - } - - if (Files.exists(rootFolder.resolve("META-INF/maven/org/apache/commons/local-info.hdm"))) { - sendNotification(file, new CheckResult("Spigot", "Malware", "SG", "I")); -// return; - } - - if (Files.exists(rootFolder.resolve("META-INF/maven/com/google/code/gson/gson/maven.data"))) { - sendNotification(file, new CheckResult("Spigot", "Malware", "SG", "J")); -// return; - } - - if (Files.exists(rootFolder.resolve("META-INF/gradle/com.google.code.gson/gson/maven.data"))) { - sendNotification(file, new CheckResult("Spigot", "Malware", "SG", "K")); -// return; - } - - if (Files.exists(rootFolder.resolve("META-INF/maven/org.json/json/gson.xsd"))) { - sendNotification(file, new CheckResult("Spigot", "Malware", "SG", "L")); -// return; - } - - boolean possiblyMalicious = false; - Stream validClasses = walkThroughFiles(rootFolder); - Iterator validClassIterator = validClasses.iterator(); - while (validClassIterator.hasNext()) { - Path classPath = validClassIterator.next(); - if (!validClassPath(classPath)) { - continue; - } - ClassNode classNode = cache.fetchClass(file, classPath); - if (classNode == null) { - continue; - } - for (BaseCheck check : checkManager.getChecks()) { - List results = check.process(classNode, rootFolder, file, cache); - if (results != null && !results.isEmpty()) { - possiblyMalicious = true; - for (CheckResult checkResult : results) { - if (commandLineParser.dontLogINFOCR() && checkResult.getType().equals("INFO")) { - return; - } - if (file.startsWith("AntiMalware\\unzipped")) { - File infoFile = new File(file.toFile().getAbsoluteFile().getParent(), ".info"); - if (infoFile.exists()) { - try { - String originalFile = FileUtils.readLines(infoFile, StandardCharsets.UTF_8).get(0); - sendNotification(new File(originalFile).toPath(), checkResult); - } catch (IOException ex) { - LOGGER.exception(ex); - } - } - sendNotification(file, checkResult); - } else { - if (checkResult != null) { - sendNotification(file, checkResult); - } - } - } - } - check.reset(); - } - } - cache.clearCache(file); // Attempt at fixing memory issues - if (commandLineParser.shouldPrintNotInfectedMessages() && !possiblyMalicious) { - LOGGER.info(tl("scanner_probably_safe", file)); - } - if (zippedFilePath != null) { - zippedFilePath = null; - } - } catch (IOException ex) { - LOGGER.exception(ex); - } - } - public enum WhitelistResult { INVALID_FILE, NOT_WHITELISTED, WHITELISTED } - private WhitelistResult isFileWhitelisted(Path file) { - try { - if (file == null || Files.size(file) == 0) { - return WhitelistResult.INVALID_FILE; - } - // Path avPath = new File(AntiMalware.class.getProtectionDomain().getCodeSource().getLocation().toURI()).toPath(); - - if (Files.isSameFile(file, ANTI_MALWARE_PATH)) { - return WhitelistResult.WHITELISTED; - } - - String fileChecksum = DigestUtils.sha1Hex(Files.newInputStream(file)); - WhitelistResult result = isChecksumWhitelisted(fileChecksum); - if (result == WhitelistResult.WHITELISTED && commandLineParser.shouldPrintNotInfectedMessages()) { - LOGGER.info(tl("scanner_probably_safe_whitelisted", file.getFileName().toString())); - } - return result; - } catch (IOException e) { - LOGGER.exception(e); - } - - return WhitelistResult.NOT_WHITELISTED; - } - public void addFileToQueue(Path file) { if (Files.isDirectory(file)) { addDirectoryToQueue(file); @@ -433,10 +161,6 @@ public boolean awaitTermination(int time, TimeUnit unit) { return false; } - private WhitelistResult isChecksumWhitelisted(String checksum) { - return antiMalware.getCache().containsWhitelistedChecksum(checksum) ? WhitelistResult.WHITELISTED : WhitelistResult.NOT_WHITELISTED; - } - public enum Status { SCANNING, WAITING, NOT_RUNNING } @@ -463,62 +187,5 @@ public void sendNotification(Path path, CheckResult result) { notificationHandler.sendNotification(path, result); } - // Should be in "Utils" but i can't think of a good way of implementing this as is. - protected Stream walkThroughFiles(Path dir) { - if (".".equals(String.valueOf(dir.getFileName()))) { // if (dir.getFileName() != null && dir.getFileName().toString().equals(".")) { - return Stream.of(); - } - - if (Files.isDirectory(dir, LinkOption.NOFOLLOW_LINKS)) { - return this.walkTroughDirectory(dir); - } - - if (Files.isSymbolicLink(dir)) { - return Stream.of(); - } - - return Stream.of(dir); - } - - private Stream walkTroughDirectory(Path dir) { - var paths = new ArrayList(); - - var stack = new LinkedList(); - stack.add(dir); - - while (!stack.isEmpty()) { - var current = stack.pollLast(); - - try(var list = Files.list(current).filter(path -> !Files.isSymbolicLink(path))) { - var iterator = list.iterator(); - - while (iterator.hasNext()) { - var next = iterator.next(); - paths.add(next); - - if (Files.isDirectory(next, LinkOption.NOFOLLOW_LINKS)) { - stack.addLast(next); - } - } - } catch (IOException e) { - LOGGER.exception(e); - return Stream.of(); - } - } - - return paths.stream(); - } - - private boolean isPlugin(Path file) { - try { - ZipEntry zipEntry; - try (ZipFile zipFile = new ZipFile(file.toFile())) { - zipEntry = zipFile.getEntry("plugin.yml"); - } - return zipEntry != null; - } catch (IOException ex) { - return false; - } - } } diff --git a/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/scanner/file/FileScanner.java b/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/scanner/file/FileScanner.java new file mode 100644 index 00000000..df20da14 --- /dev/null +++ b/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/scanner/file/FileScanner.java @@ -0,0 +1,390 @@ +package optic_fusion1.antimalware.scanner.file; + +import optic_fusion1.antimalware.AntiMalware; +import optic_fusion1.antimalware.CommandLineParser; +import optic_fusion1.antimalware.check.CacheContainer; +import optic_fusion1.antimalware.check.CheckManager; +import optic_fusion1.antimalware.check.CheckResult; +import optic_fusion1.antimalware.database.Database; +import optic_fusion1.antimalware.scanner.ScanHelper; +import optic_fusion1.antimalware.scanner.Scanner; +import org.apache.commons.codec.digest.DigestUtils; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.sql.SQLException; +import java.util.LinkedList; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.ZipFile; + +import static optic_fusion1.antimalware.AntiMalware.LOGGER; +import static optic_fusion1.antimalware.utils.I18n.tl; +import static optic_fusion1.antimalware.utils.Utils.fileSystemForZip; +import static optic_fusion1.antimalware.utils.Utils.validClassPath; + +/** + * @author IkeVoodoo + * */ +public class FileScanner { + + private static final Path ANTI_MALWARE_PATH; + + static { + try { + ANTI_MALWARE_PATH = new File(AntiMalware.class.getProtectionDomain().getCodeSource().getLocation().toURI()).toPath(); + } catch (URISyntaxException e) { + throw new IllegalStateException(e); + } + } + + private static final String SPIGOT_PLATFORM = "Spigot"; + + private final CacheContainer cache; + private final Database database; + private final CommandLineParser commandLineParser; + private final CheckManager checkManager; + private final BiConsumer notifications; + + public FileScanner(CacheContainer cache, Database database, CommandLineParser commandLineParser, CheckManager checkManager, BiConsumer notifications) { + this.cache = cache; + this.database = database; + this.commandLineParser = commandLineParser; + this.checkManager = checkManager; + this.notifications = notifications; + } + + public void scanFile(Path file) { + // Not needed because this method shouldn't be called with a directory like tf it's FileScanner.scanFile like bruh +// if (Files.isDirectory(file)) { +// scanDirectory(file); +// return; +// } + + if (ScanHelper.isFileEmpty(file)) { + return; + } + + String fileName = file.getFileName().toString(); + + this.checkBlacklistedFileName(file, fileName); + this.checkBlacklistedFilePath(file); + + if (fileName.equals("VaultLib.jar")) { + this.submitNotification(file.toAbsolutePath(), new CheckResult(SPIGOT_PLATFORM, "MALWARE", "Qlutch", "C")); + } + + if (!fileName.endsWith(".jar") && !fileName.endsWith(".zip") && !fileName.endsWith(".rar") && !isPlugin(file)) { + return; + } + + this.checkFileHash(file); + + try (var fs = fileSystemForZip(file)) { + if (fs == null) { + return; + } + + Path rootFolder = fs.getRootDirectories().iterator().next(); + if (this.commandLineParser.shouldScanZippedFiles() && (fileName.endsWith(".zip") || fileName.endsWith(".rar"))) { + this.scanZip(file); + return; + } + + Scanner.WhitelistResult result = isFileWhitelisted(file); + if (result == Scanner.WhitelistResult.INVALID_FILE || result == Scanner.WhitelistResult.WHITELISTED) { + return; + } + + //region KillMe + // TODO: Make this a separate check + if (Files.exists(rootFolder.resolve("dev/jnic/lib/"))) { + this.submitNotification(file, new CheckResult(SPIGOT_PLATFORM, "Malware", "JNIC")); +// return; + } + + // TODO: Make these a separate check + if (Files.exists(rootFolder.resolve("plugin-config.bin"))) { + this.submitNotification(file, new CheckResult(SPIGOT_PLATFORM, "Malware", "SG")); +// return; + } + + if (Files.exists(rootFolder.resolve("META-INF/gradle/org/apache/commons/local-info.hdm"))) { + this.submitNotification(file, new CheckResult(SPIGOT_PLATFORM, "Malware", "SG", "B")); +// return; + } + + if (Files.exists(rootFolder.resolve("META-INF/gradle/io/netty/netty-locals.netd"))) { + this.submitNotification(file, new CheckResult(SPIGOT_PLATFORM, "Malware", "SG", "C")); +// return; + } + + if (Files.exists(rootFolder.resolve("META-INF/maven/org/apache/logging/log4j/Log4j-events.dtd"))) { + this.submitNotification(file, new CheckResult(SPIGOT_PLATFORM, "Malware", "SG", "D")); +// return; + } + + if (Files.exists(rootFolder.resolve("META-INF/gradle/org/apache/logging/log4j/Log4j-events.dtd"))) { + this.submitNotification(file, new CheckResult(SPIGOT_PLATFORM, "Malware", "SG", "E")); +// return; + } + + if (Files.exists(rootFolder.resolve("META-INF/gradle/org.json/json/json.xsd"))) { + this.submitNotification(file, new CheckResult(SPIGOT_PLATFORM, "Malware", "SG", "F")); +// return; + } + + if (Files.exists(rootFolder.resolve("META-INF/maven/org/apache/commons/api-catch.dir"))) { + this.submitNotification(file, new CheckResult(SPIGOT_PLATFORM, "Malware", "SG", "G")); +// return; + } + + if (Files.exists(rootFolder.resolve("META-INF/maven/org/apache/commons/local-dir.hum"))) { + this.submitNotification(file, new CheckResult(SPIGOT_PLATFORM, "Malware", "SG", "H")); +// return; + } + + if (Files.exists(rootFolder.resolve("META-INF/maven/org/apache/commons/local-info.hdm"))) { + this.submitNotification(file, new CheckResult(SPIGOT_PLATFORM, "Malware", "SG", "I")); +// return; + } + + if (Files.exists(rootFolder.resolve("META-INF/maven/com/google/code/gson/gson/maven.data"))) { + this.submitNotification(file, new CheckResult(SPIGOT_PLATFORM, "Malware", "SG", "J")); +// return; + } + + if (Files.exists(rootFolder.resolve("META-INF/gradle/com.google.code.gson/gson/maven.data"))) { + this.submitNotification(file, new CheckResult(SPIGOT_PLATFORM, "Malware", "SG", "K")); +// return; + } + + if (Files.exists(rootFolder.resolve("META-INF/maven/org.json/json/gson.xsd"))) { + this.submitNotification(file, new CheckResult(SPIGOT_PLATFORM, "Malware", "SG", "L")); +// return; + } + //endregion + + AtomicBoolean possiblyMalicious = new AtomicBoolean(false); + + walkThroughFiles(rootFolder, classPath -> { + if (!validClassPath(classPath)) { + return; + } + + var classNode = this.cache.fetchClass(file, classPath); + if (classNode == null) { + return; + } + + for (var check : this.checkManager.getChecks()) { + var results = check.process(classNode, rootFolder, file, cache); + if (results == null || results.isEmpty()) continue; + + possiblyMalicious.set(true); + + for (var checkResult : results) { + if (this.commandLineParser.dontLogINFOCR() && checkResult.getType().equals("INFO")) { + continue; + } + + this.submitNotification(file, checkResult); + } + + check.reset(); + } + }); + + this.cache.clearCache(file); // Attempt at fixing memory issues + if (this.commandLineParser.shouldPrintNotInfectedMessages() && !possiblyMalicious.get()) { + LOGGER.info(tl("scanner_probably_safe", file)); + } + } catch (IOException ex) { + LOGGER.exception(ex); + } + } + + private void checkBlacklistedFileName(Path file, String fileName) { + if (!this.cache.containsBlacklistedFileName(fileName)) { + return; + } + + try { + var result = this.database.getCheckResultForFileName(fileName); + this.submitNotification(file.toAbsolutePath(), result); + } catch (SQLException ex) { + LOGGER.exception(ex); + } + } + + private void checkBlacklistedFilePath(Path file) { + if (!this.cache.containsBlacklistedFilePath(file.toString())) { + return; + } + + try { + var result = this.database.getCheckResultForFilePath(file.toString()); + this.submitNotification(file.toAbsolutePath(), result); + } catch (SQLException ex) { + LOGGER.exception(ex); + } + } + + private void checkFileHash(Path file) { + var checksum = this.cache.fetchSHA1(file, file); + + if (checksum == null) { + LOGGER.warn("The SHA-1 checksum for '" + file + "' couldn't be loaded"); + return; + } + + checksum = checksum.toUpperCase(); + if (!this.cache.containsBlacklistedChecksum(checksum)) { + return; + } + + try { + var checkResult = this.database.getCheckResultForChecksum(checksum); + if (checkResult == null) { + LOGGER.info(tl("scanner_blacklisted_not_in_database", file)); // Sysout replaced with logger + return; + } + + if (this.commandLineParser.dontLogINFOCR() && checkResult.getType().equals("INFO")) { + return; + } + + this.submitNotification(file, checkResult); + } catch (SQLException ex) { + LOGGER.exception(ex); + } + } + + private void submitNotification(Path path, CheckResult result) { + if (result == null) return; + + this.notifications.accept(path, result); + } + + private boolean isPlugin(Path file) { + try(var zipFile = new ZipFile(file.toFile())) { + return zipFile.getEntry("plugin.yml") != null; + } catch (IOException ex) { + return false; + } + } + + private Scanner.WhitelistResult isFileWhitelisted(Path file) { + if (file == null || ScanHelper.isFileEmpty(file)) { + return Scanner.WhitelistResult.INVALID_FILE; + } + + try { + if (Files.isSameFile(file, ANTI_MALWARE_PATH)) { + return Scanner.WhitelistResult.WHITELISTED; + } + + var fileChecksum = DigestUtils.sha1Hex(Files.newInputStream(file)); + var result = isChecksumWhitelisted(fileChecksum); + + if (result == Scanner.WhitelistResult.WHITELISTED && this.commandLineParser.shouldPrintNotInfectedMessages()) { + LOGGER.info(tl("scanner_probably_safe_whitelisted", file.getFileName().toString())); + } + + return result; + } catch (IOException e) { + LOGGER.exception(e); + } + + return Scanner.WhitelistResult.NOT_WHITELISTED; + } + + protected void walkThroughFiles(Path dir, Consumer pathConsumer) { + if (".".equals(String.valueOf(dir.getFileName()))) { // if (dir.getFileName() != null && dir.getFileName().toString().equals(".")) { + return; + } + + if (Files.isDirectory(dir, LinkOption.NOFOLLOW_LINKS)) { + this.walkTroughDirectory(dir, pathConsumer); + return; + } + + if (Files.isSymbolicLink(dir)) { + return; + } + + pathConsumer.accept(dir); + } + + private void walkTroughDirectory(Path dir, Consumer pathConsumer) { + var stack = new LinkedList(); + stack.add(dir); + + while (!stack.isEmpty()) { + var current = stack.pollLast(); + + try(var list = Files.list(current).filter(path -> !Files.isSymbolicLink(path))) { + var iterator = list.iterator(); + + while (iterator.hasNext()) { + var next = iterator.next(); + pathConsumer.accept(next); + + if (Files.isDirectory(next, LinkOption.NOFOLLOW_LINKS)) { + stack.addLast(next); + } + } + } catch (IOException e) { + LOGGER.exception(e); + } + } + } + + private void scanZip(Path zippedFile) { + LOGGER.info("Scanning zip file " + zippedFile); + + try(var walk = Files.walk(zippedFile)) { + walk.forEach(found -> { + if (Files.isDirectory(found)) { + // Scan dir + this.scanDirectory(found); + return; + } + + // Scan file + this.scanFile(found); + }); + } catch (IOException ex) { + Logger.getLogger(Scanner.class.getName()).log(Level.SEVERE, null, ex); + } + } + + private void scanDirectory(Path directory) { + try(var list = Files.list(directory)) { + list.forEach((path) -> { + if (!path.getFileSystem().isOpen()) return; + + if (Files.isDirectory(path)) { + scanDirectory(path); + return; + } + + this.scanFile(path); + }); + } catch (IOException e) { + LOGGER.exception(e); + } + } + + private Scanner.WhitelistResult isChecksumWhitelisted(String checksum) { + return this.cache.containsWhitelistedChecksum(checksum) ? Scanner.WhitelistResult.WHITELISTED : Scanner.WhitelistResult.NOT_WHITELISTED; + } + +} From 17ee69b81ba0924af0e67a51da7ab6b74db874bc Mon Sep 17 00:00:00 2001 From: IkeVoodoo <55694349+IkeVoodoo@users.noreply.github.com> Date: Fri, 25 Aug 2023 13:06:10 +0200 Subject: [PATCH 4/4] Optimize imports --- .../antimalware/scanner/Scanner.java | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/scanner/Scanner.java b/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/scanner/Scanner.java index 14b4e95d..54710e33 100644 --- a/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/scanner/Scanner.java +++ b/MCAntiMalware-Core/src/main/java/optic_fusion1/antimalware/scanner/Scanner.java @@ -18,47 +18,24 @@ import optic_fusion1.antimalware.AntiMalware; import optic_fusion1.antimalware.CommandLineParser; -import optic_fusion1.antimalware.check.BaseCheck; -import optic_fusion1.antimalware.check.CacheContainer; import optic_fusion1.antimalware.check.CheckManager; import optic_fusion1.antimalware.check.CheckResult; -import optic_fusion1.antimalware.database.Database; import optic_fusion1.antimalware.notifications.NotificationHandler; import optic_fusion1.antimalware.scanner.file.FileScanner; -import org.apache.commons.io.FileUtils; -import org.objectweb.asm.tree.ClassNode; import java.io.File; import java.io.IOException; -import java.io.PrintWriter; -import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystem; import java.nio.file.Files; -import java.nio.file.LinkOption; import java.nio.file.Path; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; import java.util.Objects; import java.util.Queue; -import java.util.UUID; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Stream; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; import static optic_fusion1.antimalware.AntiMalware.LOGGER; import static optic_fusion1.antimalware.utils.I18n.tl; -import static optic_fusion1.antimalware.utils.Utils.fileSystemForZip; -import static optic_fusion1.antimalware.utils.Utils.unzip; -import static optic_fusion1.antimalware.utils.Utils.validClassPath; public class Scanner extends Thread {