diff --git a/app/build.gradle b/app/build.gradle index 29ae22f..8374ab4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,8 +6,8 @@ android { applicationId "us.spotco.malwarescanner" minSdkVersion 16 targetSdkVersion 32 - versionCode 310 - versionName "3.10" + versionCode 311 + versionName "3.11" resConfigs 'en', 'af', 'cs', 'de', 'el', 'es', 'fi', 'fr', 'gl', 'it', 'pl', 'pt', 'pt-rBR', 'ru', 'tr', 'zh-rCN' } buildTypes { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d04faee..278356d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -58,6 +58,19 @@ android:exported="false" android:label="Realtime Malware Scanner" /> + + + + + + + signaturesMD5Extended = null; public static BloomFilter signaturesSHA1 = null; public static BloomFilter signaturesSHA256 = null; + public static BloomFilter domains = null; public static long signaturesCount = 0; public static boolean changedDownload = false; public static boolean changedConfig = false; @@ -74,6 +75,11 @@ class Database { && signaturesSHA256 != null && signaturesSHA256.approximateElementCount() > 0; } + public static boolean isDomainDatabaseLoaded() { + return areDatabasesAvailable() && !isDatabaseLoading() + && domains != null && domains.approximateElementCount() > 0; + } + public static boolean isDatabaseLoading() { return !databaseFullyLoaded && databaseCurrentlyLoading; } @@ -111,6 +117,9 @@ class Database { if (prefs.getBoolean("SIGNATURES_EXTENDED", false)) { signatureDatabases.add(new SignatureDatabase(baseURL, "hypatia-md5-extended-bloom.bin")); } + if (prefs.getBoolean("DOMAINS", false)) { + signatureDatabases.add(new SignatureDatabase(baseURL, "hypatia-domains-bloom.bin")); + } } public static void loadDatabase(Context context, boolean forceReload, ConcurrentLinkedQueue signatureDatabases) { @@ -121,6 +130,7 @@ class Database { signaturesCount = 0; changedConfig = false; signaturesMD5Extended = null; + domains = null; File publicKey = new File(databasePath + "/gpg.key"); GPGDetachedSignatureVerifier verifier = new GPGDetachedSignatureVerifier(Utils.getSigningKey(context)); for (SignatureDatabase database : signatureDatabases) { @@ -137,25 +147,30 @@ class Database { Log.d("Hypatia", "Processing md5"); signaturesMD5 = BloomFilter.readFrom(databaseLoading, Funnels.stringFunnel(Charsets.US_ASCII)); signaturesCount += signaturesMD5.approximateElementCount(); - Log.d("Hypatia", "Loaded md5"); + Log.d("Hypatia", "Loaded md5 with " + signaturesMD5.approximateElementCount() + " entries"); break; case "hypatia-sha1-bloom.bin": Log.d("Hypatia", "Processing sha1"); signaturesSHA1 = BloomFilter.readFrom(databaseLoading, Funnels.stringFunnel(Charsets.US_ASCII)); signaturesCount += signaturesSHA1.approximateElementCount(); - Log.d("Hypatia", "Loaded sha1"); + Log.d("Hypatia", "Loaded sha1 with " + signaturesSHA1.approximateElementCount() + " entries"); break; case "hypatia-sha256-bloom.bin": Log.d("Hypatia", "Processing sha256"); signaturesSHA256 = BloomFilter.readFrom(databaseLoading, Funnels.stringFunnel(Charsets.US_ASCII)); signaturesCount += signaturesSHA256.approximateElementCount(); - Log.d("Hypatia", "Loaded sha256"); + Log.d("Hypatia", "Loaded sha256 with " + signaturesSHA256.approximateElementCount() + " entries"); break; case "hypatia-md5-extended-bloom.bin": Log.d("Hypatia", "Processing md5 extended"); signaturesMD5Extended = BloomFilter.readFrom(databaseLoading, Funnels.stringFunnel(Charsets.US_ASCII)); signaturesCount += signaturesMD5Extended.approximateElementCount(); - Log.d("Hypatia", "Loaded md5 extended"); + Log.d("Hypatia", "Loaded md5 extended with " + signaturesMD5Extended.approximateElementCount() + " entries"); + break; + case "hypatia-domains-bloom.bin": + Log.d("Hypatia", "Processing domains"); + domains = BloomFilter.readFrom(databaseLoading, Funnels.stringFunnel(Charsets.US_ASCII)); + Log.d("Hypatia", "Loaded domains with " + domains.approximateElementCount() + " entries"); break; } databaseLoading.close(); diff --git a/app/src/main/java/us/spotco/malwarescanner/LinkScannerService.java b/app/src/main/java/us/spotco/malwarescanner/LinkScannerService.java new file mode 100644 index 0000000..a101797 --- /dev/null +++ b/app/src/main/java/us/spotco/malwarescanner/LinkScannerService.java @@ -0,0 +1,116 @@ +package us.spotco.malwarescanner; + +import android.accessibilityservice.AccessibilityService; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Context; +import android.os.Build; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; + +import java.util.Random; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class LinkScannerService extends AccessibilityService { + + private static final String hostnameRegex = "^((?!-)[A-Za-z0-9-]{1,63}(? scannedObjects = new ConcurrentSkipListSet<>(); + private static final ConcurrentSkipListSet scannedDomains = new ConcurrentSkipListSet<>(); + private NotificationManager notificationManager = null; + + @Override + public void onServiceConnected() { + notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel detectionChannel = new NotificationChannel("DETECTION", getString(R.string.lblNotificationMalwareDetectionTitle), NotificationManager.IMPORTANCE_HIGH); + detectionChannel.setDescription(getString(R.string.lblNotificationMalwareDetectionDescription)); + notificationManager.createNotificationChannel(detectionChannel); + } + } + + @Override + public void onAccessibilityEvent(AccessibilityEvent event) { + if (Database.isDomainDatabaseLoaded()) { + scanViews(event.getSource()); + } + } + + @Override + public void onInterrupt() { + } + + private void scanViews(AccessibilityNodeInfo mNodeInfo) { + try { + //May already be gone + if (mNodeInfo == null) { + return; + } + + //Don't scan if we already did + int hash = mNodeInfo.toString().hashCode(); + if (scannedObjects.contains(hash)) { + return; + } else { + scannedObjects.add(hash); + } + + //Get and check the text + String text = (String) mNodeInfo.getText(); + if (text != null && text.contains(".")) { + scanText(text.toLowerCase()); + } + + //Finish if no more children + if (mNodeInfo.getChildCount() < 1) { + return; + } + + //Recurse into the children otherwise + for (int i = 0; i < mNodeInfo.getChildCount(); i++) { + scanViews(mNodeInfo.getChild(i)); + } + } catch (Exception ignored) { + } + } + + private void scanText(String haystack) { + Matcher matcher = hostnamePattern.matcher(haystack); + while (matcher.find()) { + if (!scannedDomains.contains(matcher.group())) { + scannedDomains.add(matcher.group()); + if (Database.domains.mightContain(matcher.group())) { + sendNotification(matcher.group()); + } + } + } + if (haystack.contains("/")) { + for (String split : haystack.split("/")) { + scanText(split); + } + } + } + + private void sendNotification(String link) { + link = link.replaceAll("\\.", "[.]"); + Notification.Builder mBuilder = + new Notification.Builder(this) + .setSmallIcon(R.drawable.ic_notification) + .setContentTitle(getText(R.string.lblNotificationLinkDetection)) + .setContentText("Domain: >>>" + link + "<<<") + .setStyle(new Notification.BigTextStyle().bigText("Domain: >>>" + link + "<<<")) + .setPriority(Notification.PRIORITY_MAX) + .setDefaults(Notification.DEFAULT_VIBRATE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + mBuilder.setVisibility(Notification.VISIBILITY_SECRET); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + mBuilder.setChannelId("DETECTION"); + } + notificationManager.notify(new Random().nextInt(), mBuilder.build()); + } + +} diff --git a/app/src/main/java/us/spotco/malwarescanner/MainActivity.java b/app/src/main/java/us/spotco/malwarescanner/MainActivity.java index 07c80a7..b464e73 100644 --- a/app/src/main/java/us/spotco/malwarescanner/MainActivity.java +++ b/app/src/main/java/us/spotco/malwarescanner/MainActivity.java @@ -83,7 +83,6 @@ public class MainActivity extends Activity { logView.append(getString(R.string.app_copyright) + "\n"); logView.append(getString(R.string.app_license) + "\n"); logView.append(getString(R.string.app_version, buildVersionName) + "\n"); - logView.append(getString(R.string.app_db_type_clamav) + "\n\n"); malwareScanner = new MalwareScanner(this, this, true); @@ -100,6 +99,8 @@ public class MainActivity extends Activity { this.menu = menu; menu.findItem(R.id.toggleRealtime).setChecked(Utils.isServiceRunning(MalwareScannerService.class, this)); menu.findItem(R.id.toggleOnionRouting).setChecked(prefs.getBoolean("ONION_ROUTING", false)); + menu.findItem(R.id.toggleExtended).setChecked(prefs.getBoolean("SIGNATURES_EXTENDED", false)); + menu.findItem(R.id.toggleLinkScanner).setChecked(prefs.getBoolean("DOMAINS", false)); updateScanButton(false); return true; } @@ -240,12 +241,14 @@ public class MainActivity extends Activity { .setIcon(android.R.drawable.ic_menu_compass) .setPositiveButton(getString(android.R.string.yes), (dialog, which) -> { prefs.edit().putBoolean("SIGNATURES_EXTENDED", true).apply(); + item.setChecked(true); if (!prevExtended) { Database.changedConfig = true; } }) .setNegativeButton(getString(android.R.string.no), (dialog, which) -> { prefs.edit().putBoolean("SIGNATURES_EXTENDED", false).apply(); + item.setChecked(false); if (prevExtended) { Database.changedConfig = true; } @@ -253,6 +256,35 @@ public class MainActivity extends Activity { }).show(); } break; + case R.id.toggleLinkScanner: + if (Database.hasDownloadsRunning()) { + logView.append(getString(R.string.lblUpdateRunning) + "\n"); + } else if (Database.isDatabaseLoading()) { + logView.append(getString(R.string.lblDatabaseLoading) + "\n"); + } else { + boolean prevDomains = prefs.getBoolean("DOMAINS", false); + new AlertDialog.Builder(this) + .setTitle(R.string.confirm_link_scanner_title) + .setMessage(getString(R.string.confirm_link_scanner_summary)) + .setIcon(android.R.drawable.ic_menu_compass) + .setPositiveButton(getString(android.R.string.yes), (dialog, which) -> { + prefs.edit().putBoolean("DOMAINS", true).apply(); + item.setChecked(true); + if (!prevDomains) { + Database.changedConfig = true; + } + startActivityForResult(new Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS), 0); + }) + .setNegativeButton(getString(android.R.string.no), (dialog, which) -> { + prefs.edit().putBoolean("DOMAINS", false).apply(); + item.setChecked(false); + if (prevDomains) { + Database.changedConfig = true; + } + dialog.cancel(); + }).show(); + } + break; case R.id.toggleRealtime: if (malwareScanner.running) { logView.append(getString(R.string.lblScanRunning) + "\n"); diff --git a/app/src/main/java/us/spotco/malwarescanner/MalwareScanner.java b/app/src/main/java/us/spotco/malwarescanner/MalwareScanner.java index 5bba589..7181ba8 100644 --- a/app/src/main/java/us/spotco/malwarescanner/MalwareScanner.java +++ b/app/src/main/java/us/spotco/malwarescanner/MalwareScanner.java @@ -28,7 +28,6 @@ import android.os.AsyncTask; import android.os.Build; import android.os.Environment; import android.os.SystemClock; -import android.util.Log; import android.widget.TextView; import com.google.common.hash.BloomFilter; diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index 40aa0cf..7c41e14 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -22,7 +22,12 @@ android:title="@string/lblSigningKey" /> + android:title="@string/lblExtendedDatabaseToggle" + android:checkable="true" /> + Contrôle de l\'analyse Action ignorée, une analyse est en cours ! Signature utilisée pour signer la base de données - Aucun réseau connecté ! + Aucun réseau connecté ! Auto-test réussi. Échec de l\'auto-test ! Action sautée, la base de données est en cours de chargement ! diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 1150eac..215079f 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -48,7 +48,7 @@ Контроль сканирования Пропуск действия, выполняется сканирование! Ключ подписи базы данных - Нет подключения к сети! + Нет подключения к сети! Самотестирование прошло успешно. Самотестирование завершено неудачно! Пропуск действия, загружается база данных! diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 8d517e9..fd6b683 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -49,7 +49,7 @@ Tarama Kontrolü Faaliyet es geçiliyor, bir tarama devam etmekte! Veri tabanı imzalama anahtarı - Hiçbir şebeke bağlı değil! + Hiçbir şebeke bağlı değil! Kendi kendini deneme başarılı. Kendi kendini deneme başarısız oldu! Faaliyet atlanıyor, veri tabanı yüklenmekte! diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 78e2b6a..9be447a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -71,11 +71,17 @@ Write self test files Extended database Enable extended database? - [EXPERIMENTAL]\nThis will enable detection of an additional ~40 million signatures.\nThis requires a 125MB download, will slow down startup by over two minutes, will increase app RAM usage, and will increase the false positive rate.\nThis database only updates quarterly. + [EXPERIMENTAL]\nThis will enable detection of an additional ~40 million signatures.\nThis requires a 200MB download, will slow down startup by over two minutes, will increase app RAM usage, and will increase the false positive rate.\nThis database only updates quarterly. Confirm download You appear to be on a metered connection. Are you sure you want to update the databases?\nIt may download up to %s megabytes of data. Skipping action, an update is running! Wrote test files! Primary Servers Cloudflare Mirror + Hypatia Link Scanner + Extracts domains from all screen text content and checks them against a blocklist + Malicious Link Detected: + Link Scanner + Enable link scanner? + [EXPERIMENTAL]\nThis will download an additional database of domains.\nAny domains found in screen content will be checked against the database.\nThis require granting accessibility service permission manually. diff --git a/app/src/main/res/xml/accessibility_service_config.xml b/app/src/main/res/xml/accessibility_service_config.xml new file mode 100644 index 0000000..9b4d7a3 --- /dev/null +++ b/app/src/main/res/xml/accessibility_service_config.xml @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/311.txt b/fastlane/metadata/android/en-US/changelogs/311.txt new file mode 100644 index 0000000..8ca136c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/311.txt @@ -0,0 +1 @@ +* Ability to scan screen content for malicious links diff --git a/scripts/Main.java b/scripts/Main.java index 343dc81..7a96104 100644 --- a/scripts/Main.java +++ b/scripts/Main.java @@ -41,10 +41,13 @@ public class Main { private static BloomFilter signaturesMD5 = null; private static BloomFilter signaturesSHA1 = null; private static BloomFilter signaturesSHA256 = null; + private static BloomFilter domains = null; private static int amtLinesValid = 0; private static int amtLinesInvalid = 0; + private static int amtDomains = 0; + private static int amtSignaturesReadMD5 = 0; private static int amtSignaturesReadSHA1 = 0; private static int amtSignaturesReadSHA256 = 0; @@ -66,24 +69,26 @@ public class Main { extendedMode = args[0].contains("-extended"); //isFileInNsrl("B61905308B336AD268A782790B661616"); int amtMaxMD5 = 7200000; //7.2m - if(extendedMode) { - amtMaxMD5 = 52000000; //52m + if (extendedMode) { + amtMaxMD5 = 52000000; //52m } int amtMaxSHA1 = 50000; //50k int amtMaxSHA256 = 2000000; //2m + int amtMaxDomains = 1800000; //1.8m signaturesMD5 = BloomFilter.create(Funnels.stringFunnel(Charsets.US_ASCII), amtMaxMD5, 0.00001); signaturesSHA1 = BloomFilter.create(Funnels.stringFunnel(Charsets.US_ASCII), amtMaxSHA1, 0.00001); signaturesSHA256 = BloomFilter.create(Funnels.stringFunnel(Charsets.US_ASCII), amtMaxSHA256, 0.00001); + domains = BloomFilter.create(Funnels.stringFunnel(Charsets.US_ASCII), amtMaxDomains, 0.00001); File existingDatabase = new File(args[0] + "../production/hypatia-md5-bloom.bin"); - if(extendedMode && existingDatabase.exists()) { - try { + if (extendedMode && existingDatabase.exists()) { + try { System.out.println("Loading existing hypatia-md5-bloom.bin database"); FileInputStream databaseLoading = new FileInputStream(existingDatabase); signaturesMD5Dedupe = BloomFilter.readFrom(databaseLoading, Funnels.stringFunnel(Charsets.US_ASCII)); System.out.println("\tLoaded " + signaturesMD5Dedupe.approximateElementCount() + " entries"); - } catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); - } + } } System.out.println("Processing exclusions:"); @@ -93,12 +98,12 @@ public class Main { try { System.out.println("\t" + exclusionDatabase.getName()); Scanner s = new Scanner(exclusionDatabase); - while(s.hasNextLine()) { + while (s.hasNextLine()) { String line = s.nextLine().trim().toLowerCase(); - if(line.contains(":")) { + if (line.contains(":")) { line = line.split(":")[0]; } - if(!line.startsWith("#") && isHexadecimal(line) && (line.length() == 32 || line.length() == 40 || line.length() == 64)) { + if (!line.startsWith("#") && isHexadecimal(line) && (line.length() == 32 || line.length() == 40 || line.length() == 64)) { arrExclusions.add(line); //System.out.println("\t\tAdded: " + line); } @@ -108,17 +113,37 @@ public class Main { e.printStackTrace(); } } - System.out.println("Loaded " + arrExclusions.size() + " excluded hashes"); + System.out.println("\tLoaded " + arrExclusions.size() + " excluded hashes"); + + if (args.length == 2) { + System.out.println("Processing domains:"); + File domainDatabase = new File(args[1]); + if (domainDatabase.exists()) { + try { + Scanner s = new Scanner(domainDatabase); + while (s.hasNextLine()) { + String line = s.nextLine().trim().toLowerCase(); + if (!line.startsWith("#")) { + domains.put(line); + } + } + s.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + System.out.println("\tLoaded " + domains.approximateElementCount() + " domains"); + } System.out.println("Processing signatures:"); File[] databases = new File(args[0]).listFiles(); File extras = new File(args[0] + "../extras/"); - if(extras.exists() && !extendedMode) { + if (extras.exists() && !extendedMode) { databases = Stream.concat(Arrays.stream(databases), Arrays.stream(extras.listFiles())).toArray(File[]::new); } Arrays.sort(databases); for (File databaseLocation : databases) { - if(databaseLocation.isFile()) { + if (databaseLocation.isFile()) { System.out.println("\t" + databaseLocation.getName()); amtPreviousSignaturesMD5 = amtSignaturesAddedMD5; amtPreviousSignaturesSHA1 = amtSignaturesAddedSHA1; @@ -172,29 +197,31 @@ public class Main { System.out.println("Read count: md5: " + amtSignaturesReadMD5 + ", sha1: " + amtSignaturesReadSHA1 + ", sha256: " + amtSignaturesReadSHA256); System.out.println("Added count: md5: " + amtSignaturesAddedMD5 + ", sha1: " + amtSignaturesAddedSHA1 + ", sha256: " + amtSignaturesAddedSHA256); System.out.println("Approximate count: md5: " + signaturesMD5.approximateElementCount() + ", sha1: " + signaturesSHA1.approximateElementCount() + ", sha256: " + signaturesSHA256.approximateElementCount()); - if(extendedMode) { System.out.println("Deduped count: md5: " + amtSignaturesDedupedMD5); } + if (extendedMode) { + System.out.println("Deduped count: md5: " + amtSignaturesDedupedMD5); + } System.out.println("Max amount: md5: " + amtMaxMD5 + ", sha1: " + amtMaxSHA1 + ", sha256: " + amtMaxSHA256); - System.out.println("Fill amount: md5: " + ((100F/amtMaxMD5) * amtSignaturesAddedMD5) + "%, sha1: " + ((100F/amtMaxSHA1) * amtSignaturesAddedSHA1) + "%, sha256: " + ((100F/amtMaxSHA256) * amtSignaturesAddedSHA256) + "%"); + System.out.println("Fill amount: md5: " + ((100F / amtMaxMD5) * amtSignaturesAddedMD5) + "%, sha1: " + ((100F / amtMaxSHA1) * amtSignaturesAddedSHA1) + "%, sha256: " + ((100F / amtMaxSHA256) * amtSignaturesAddedSHA256) + "%"); System.out.println("App reported count: " + (signaturesMD5.approximateElementCount() + signaturesSHA1.approximateElementCount() + signaturesSHA256.approximateElementCount())); System.out.println("Expected false postive rate: md5: " + signaturesMD5.expectedFpp() + ", sha1: " + signaturesSHA1.expectedFpp() + ", sha256: " + signaturesSHA256.expectedFpp()); System.out.println("Testing exclusions:"); int matchedExclusions = 0; - for(String excluded : arrExclusions) { - if(excluded.length() == 32 && signaturesMD5.mightContain(excluded)) { - System.out.println("\tmd5: Found excluded hash " + excluded); - matchedExclusions++; - } - if(excluded.length() == 40 && signaturesSHA1.mightContain(excluded)) { - System.out.println("\tsha1: Found excluded hash " + excluded); - matchedExclusions++; - } - if(excluded.length() == 64 && signaturesSHA256.mightContain(excluded)) { - System.out.println("\tsha256: Found excluded hash " + excluded); - matchedExclusions++; - } + for (String excluded : arrExclusions) { + if (excluded.length() == 32 && signaturesMD5.mightContain(excluded)) { + System.out.println("\tmd5: Found excluded hash " + excluded); + matchedExclusions++; + } + if (excluded.length() == 40 && signaturesSHA1.mightContain(excluded)) { + System.out.println("\tsha1: Found excluded hash " + excluded); + matchedExclusions++; + } + if (excluded.length() == 64 && signaturesSHA256.mightContain(excluded)) { + System.out.println("\tsha256: Found excluded hash " + excluded); + matchedExclusions++; + } } - if(matchedExclusions == 0) { + if (matchedExclusions == 0) { System.out.println("\tNo exclusions found :)"); } else { System.out.println("\tExclusions were found!"); @@ -211,6 +238,10 @@ public class Main { FileOutputStream fileSignaturesSHA256 = new FileOutputStream(new File(args[0]) + "/hypatia-sha256-bloom.bin"); signaturesSHA256.writeTo(fileSignaturesSHA256); fileSignaturesSHA256.close(); + + FileOutputStream fileDomains = new FileOutputStream(new File(args[0]) + "/hypatia-domains-bloom.bin"); + domains.writeTo(fileDomains); + fileDomains.close(); } catch (Exception e) { e.printStackTrace(); } @@ -227,7 +258,7 @@ public class Main { private static void addChecked(String potentialHash, boolean report) { if (!potentialHash.startsWith("#") && potentialHash.length() >= 4) { if (isHexadecimal(potentialHash)) { - if(arrExclusions.contains(potentialHash)) { + if (arrExclusions.contains(potentialHash)) { System.out.println("\t\tSkipping excluded hash: " + potentialHash); return; } @@ -237,7 +268,7 @@ public class Main { if (potentialHash.length() == 32) { boolean shouldAdd = true; if (extendedMode) { - if(signaturesMD5Dedupe.mightContain(potentialHash)) { + if (signaturesMD5Dedupe.mightContain(potentialHash)) { shouldAdd = false; amtSignaturesDedupedMD5++; } @@ -261,11 +292,11 @@ public class Main { amtLinesValid++; } else { amtLinesInvalid++; - if(report) System.out.println("\t\tINVALID LENGTH: " + potentialHash); + if (report) System.out.println("\t\tINVALID LENGTH: " + potentialHash); } } else { amtLinesInvalid++; - if(report) System.out.println("\t\tNOT HEXADECIMAL: " + potentialHash); + if (report) System.out.println("\t\tNOT HEXADECIMAL: " + potentialHash); } } }