Normalize all strings to lower-case and add self-test function

Signed-off-by: Tad <tad@spotco.us>
This commit is contained in:
Tad 2023-12-22 18:54:10 -05:00
parent fa25395a08
commit dfabf6b9ff
No known key found for this signature in database
GPG key ID: B286E9F57A07424B
6 changed files with 53 additions and 28 deletions

View file

@ -6,8 +6,8 @@ android {
applicationId "us.spotco.malwarescanner" applicationId "us.spotco.malwarescanner"
minSdkVersion 19 minSdkVersion 19
targetSdkVersion 32 targetSdkVersion 32
versionCode 113 versionCode 116
versionName "2.36" versionName "2.37"
resConfigs 'en', 'af', 'de', 'el', 'es', 'fi', 'fr', 'it', 'pl', 'pt', 'ru', 'tr', 'zh-rCN' resConfigs 'en', 'af', 'de', 'el', 'es', 'fi', 'fr', 'it', 'pl', 'pt', 'ru', 'tr', 'zh-rCN'
} }
buildTypes { buildTypes {

View file

@ -166,10 +166,10 @@ class Database {
boolean onionRouting = (boolean) objects[0]; boolean onionRouting = (boolean) objects[0];
String url = (String) objects[1]; String url = (String) objects[1];
File out = new File((String) objects[2]); File out = new File((String) objects[2]);
File outNew = new File((String) objects[2] + ".new"); File outNew = new File(objects[2] + ".new");
String baseURL = (String) objects[3]; String baseURL = (String) objects[3];
try { try {
if(outNew.exists()) { if (outNew.exists()) {
outNew.delete(); outNew.delete();
} }
HttpURLConnection connection; HttpURLConnection connection;
@ -218,7 +218,7 @@ class Database {
connection.disconnect(); connection.disconnect();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
if(outNew.exists()) { if (outNew.exists()) {
outNew.delete(); outNew.delete();
} }
publishProgress(url.replaceAll(baseURL, "") publishProgress(url.replaceAll(baseURL, "")
@ -232,4 +232,13 @@ class Database {
log.append(progress[0] + "\n"); log.append(progress[0] + "\n");
} }
} }
public static boolean selfTest() {
if (signaturesMD5 != null && signaturesSHA1 != null && signaturesSHA256 != null) {
return signaturesMD5.mightContain("903616d0dbe074aa363d2d49c03f7362")
&& signaturesSHA1.mightContain("fc4a3e802894cc2229be77ec6f082d1aab744e54")
&& signaturesSHA256.mightContain("df44844a0e99ddd935e8419257440a2ca7ef3243435a67416fcbb6cd3ae560c3");
}
return false;
}
} }

View file

@ -279,28 +279,29 @@ public class MainActivity extends Activity {
private void updateDatabase() { private void updateDatabase() {
new Database(findViewById(R.id.txtLogOutput)); new Database(findViewById(R.id.txtLogOutput));
if(!Database.isDatabaseLoading()) { if (!Database.isDatabaseLoading()) {
Database.updateDatabase(this, Database.signatureDatabases); Database.updateDatabase(this, Database.signatureDatabases);
} else { } else {
Log.w("Hypatia", "Database is loading, not downloading!"); logView.append(getString(R.string.lblDatabaseLoading) + "\n");
} }
if (Database.isDatabaseLoaded()) { Utils.getThreadPoolExecutor().execute(() -> {
Utils.getThreadPoolExecutor().execute(() -> { try {
try { Thread.sleep(500);
Log.w("Hypatia", "Invoking database reload!");
while (Database.hasDownloadsRunning()) {
Thread.sleep(500); Thread.sleep(500);
Log.w("Hypatia", "Invoking database reload!"); Log.w("Hypatia", "Download in progress, waiting!");
while (Database.hasDownloadsRunning()) {
Thread.sleep(500);
Log.w("Hypatia", "Download in progress, waiting!");
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} }
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
logView.append(getString(R.string.lblDatabasesUpdated) + "\n");
if (Database.isDatabaseLoaded()) {
Log.w("Hypatia", "Really reloading database!"); Log.w("Hypatia", "Really reloading database!");
Database.loadDatabase(getApplicationContext(), true, Database.signatureDatabases); Database.loadDatabase(getApplicationContext(), true, Database.signatureDatabases);
}); }
} });
} }
private void updateScanButton(boolean running) { private void updateScanButton(boolean running) {

View file

@ -137,6 +137,13 @@ class MalwareScanner extends AsyncTask<HashSet<File>, Object, String> {
if (Database.isDatabaseLoaded()) { if (Database.isDatabaseLoaded()) {
publishProgress("\t" + context.getString(R.string.main_database_loaded, "?") + "\n", true); publishProgress("\t" + context.getString(R.string.main_database_loaded, "?") + "\n", true);
//Perform a self-test
if (Database.selfTest()) {
publishProgress("\t" + context.getString(R.string.self_test_result_success), true);
} else {
publishProgress("\t" + context.getString(R.string.self_test_result_failure), true);
}
//Get file hashes //Get file hashes
publishProgress("\t" + context.getString(R.string.main_hashing_files), true); publishProgress("\t" + context.getString(R.string.main_hashing_files), true);
publishProgress("\t", true); publishProgress("\t", true);
@ -203,7 +210,7 @@ class MalwareScanner extends AsyncTask<HashSet<File>, Object, String> {
} }
private void checkSignature(String hashType, HashMap<File, String> signaturesToCheck, BloomFilter<String> signatureDatabase) { private void checkSignature(String hashType, HashMap<File, String> signaturesToCheck, BloomFilter<String> signatureDatabase) {
if (Database.isDatabaseLoaded()) { if (Database.isDatabaseLoaded() && signatureDatabase != null) {
for (Map.Entry<File, String> file : signaturesToCheck.entrySet()) { for (Map.Entry<File, String> file : signaturesToCheck.entrySet()) {
if (signatureDatabase.mightContain(file.getValue())) { if (signatureDatabase.mightContain(file.getValue())) {
publishProgress("Potential match in " + file.getKey().toString().replaceAll(Environment.getExternalStorageDirectory().toString(), "~"), false); publishProgress("Potential match in " + file.getKey().toString().replaceAll(Environment.getExternalStorageDirectory().toString(), "~"), false);
@ -239,9 +246,9 @@ class MalwareScanner extends AsyncTask<HashSet<File>, Object, String> {
fis.close(); fis.close();
fileHashesMD5.put(file, String.format("%032x", new BigInteger(1, digestMD5.digest()))); fileHashesMD5.put(file, String.format("%032x", new BigInteger(1, digestMD5.digest())).toLowerCase());
fileHashesSHA1.put(file, String.format("%032x", new BigInteger(1, digestSHA1.digest()))); fileHashesSHA1.put(file, String.format("%032x", new BigInteger(1, digestSHA1.digest())).toLowerCase());
fileHashesSHA256.put(file, String.format("%064x", new BigInteger(1, digestSHA256.digest()))); fileHashesSHA256.put(file, String.format("%064x", new BigInteger(1, digestSHA256.digest())).toLowerCase());
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }

View file

@ -63,4 +63,8 @@
<string name="lblScanRunning">Skipping action, a scan is running!</string> <string name="lblScanRunning">Skipping action, a scan is running!</string>
<string name="lblSigningKey">Database signing key</string> <string name="lblSigningKey">Database signing key</string>
<string name="lblNoNetwork">No network connected!</string> <string name="lblNoNetwork">No network connected!</string>
<string name="self_test_result_success">Self test successful.</string>
<string name="self_test_result_failure">Self test failed!</string>
<string name="lblDatabaseLoading">Database is loading, not updating!</string>
<string name="lblDatabasesUpdated">All databases updated!</string>
</resources> </resources>

View file

@ -55,7 +55,7 @@ public class Main {
if (databaseLocation.getName().contains(".hdb")) {//.hdb format: md5, size, name if (databaseLocation.getName().contains(".hdb")) {//.hdb format: md5, size, name
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
if (line.length() > 0) { if (line.length() > 0) {
String[] lineS = line.trim().split(":"); String[] lineS = line.trim().toLowerCase().split(":");
if (lineS[0].length() > 0) { if (lineS[0].length() > 0) {
if (signaturesMD5.put(lineS[0])) { if (signaturesMD5.put(lineS[0])) {
amtSignaturesMD5++; amtSignaturesMD5++;
@ -67,7 +67,7 @@ public class Main {
} else if (databaseLocation.getName().contains(".hsb")) {//.hsb format: sha256, size, name } else if (databaseLocation.getName().contains(".hsb")) {//.hsb format: sha256, size, name
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
if (line.length() > 0) { if (line.length() > 0) {
String[] lineS = line.trim().split(":"); String[] lineS = line.trim().toLowerCase().split(":");
if (lineS[0].length() == 32) { if (lineS[0].length() == 32) {
if (signaturesSHA1.put(lineS[0])) { if (signaturesSHA1.put(lineS[0])) {
amtSignaturesSHA1++; amtSignaturesSHA1++;
@ -84,7 +84,7 @@ public class Main {
} else if (databaseLocation.getName().contains(".md5")) {//one signature per line } else if (databaseLocation.getName().contains(".md5")) {//one signature per line
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
if (line.length() > 0) { if (line.length() > 0) {
if (signaturesMD5.put(line.trim())) { if (signaturesMD5.put(line.trim().toLowerCase())) {
amtSignaturesMD5++; amtSignaturesMD5++;
} }
amtSignaturesRead++; amtSignaturesRead++;
@ -93,7 +93,7 @@ public class Main {
} else if (databaseLocation.getName().contains(".sha1")) {//one signature per line } else if (databaseLocation.getName().contains(".sha1")) {//one signature per line
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
if (line.length() > 0) { if (line.length() > 0) {
if (signaturesSHA1.put(line.trim())) { if (signaturesSHA1.put(line.trim().toLowerCase())) {
amtSignaturesSHA1++; amtSignaturesSHA1++;
} }
amtSignaturesRead++; amtSignaturesRead++;
@ -102,7 +102,7 @@ public class Main {
} else if (databaseLocation.getName().contains(".sha256")) {//one signature per line } else if (databaseLocation.getName().contains(".sha256")) {//one signature per line
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
if (line.length() > 0) { if (line.length() > 0) {
if (signaturesSHA256.put(line.trim())) { if (signaturesSHA256.put(line.trim().toLowerCase())) {
amtSignaturesSHA256++; amtSignaturesSHA256++;
} }
amtSignaturesRead++; amtSignaturesRead++;
@ -118,6 +118,10 @@ public class Main {
signaturesMD5.put("44d88612fea8a8f36de82e1278abb02f"); //Eicar test file signaturesMD5.put("44d88612fea8a8f36de82e1278abb02f"); //Eicar test file
signaturesSHA256.put("6a0b4866f143c32e651662cebf7f380d27b0db809db3b6a34cf34c7436ab6bbf"); //Hypatia test file signaturesSHA256.put("6a0b4866f143c32e651662cebf7f380d27b0db809db3b6a34cf34c7436ab6bbf"); //Hypatia test file
signaturesMD5.put("903616d0dbe074aa363d2d49c03f7362"); //Hypatia self-test canaries (echo -n "HypatiaHypatiaHypatia" | sum)
signaturesSHA1.put("fc4a3e802894cc2229be77ec6f082d1aab744e54");
signaturesSHA256.put("df44844a0e99ddd935e8419257440a2ca7ef3243435a67416fcbb6cd3ae560c3");
System.out.println("Total: " + amtSignaturesRead); System.out.println("Total: " + amtSignaturesRead);
System.out.println("Mismatch: " + (amtSignaturesRead-amtSignaturesMD5-amtSignaturesSHA1-amtSignaturesSHA256)); System.out.println("Mismatch: " + (amtSignaturesRead-amtSignaturesMD5-amtSignaturesSHA1-amtSignaturesSHA256));
System.out.println("Loaded all databases - md5: " + amtSignaturesMD5 + ", sha1: " + amtSignaturesSHA1 + ", sha256: " + amtSignaturesSHA256); System.out.println("Loaded all databases - md5: " + amtSignaturesMD5 + ", sha1: " + amtSignaturesSHA1 + ", sha256: " + amtSignaturesSHA256);