Skip to content

Commit

Permalink
Version 1.0-stable release
Browse files Browse the repository at this point in the history
  • Loading branch information
ThisIsLibra committed Apr 5, 2020
1 parent 5da37e6 commit 92a066c
Show file tree
Hide file tree
Showing 13 changed files with 932 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# MalPull
A CLI interface to search for a MD-5/SHA-1/SHA-256 hash on multiple malware databases and download the sample from the first hit
A CLI interface to search for a MD-5/SHA-1/SHA-256 hash on multiple malware databases and download the sample from the first hit. More information can be found <a href="https://maxkersten.nl/projects/malpull/">here</a>.If there are any questions, feature suggestions, or bug reports: please send me a message my Twitter (<a href="https://twitter.com/LibraAnalysis">@LibraAnalysis</a>).
68 changes: 68 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>malwarepuller</groupId>
<artifactId>MalPull</artifactId>
<version>1.0-stable</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<pluginRepositories>
<pluginRepository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
</pluginRepository>
</pluginRepositories>
<repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>malpull.MalPull</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.2.2</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20190722</version>
</dependency>
</dependencies>
<name>MalPull</name>
</project>
45 changes: 45 additions & 0 deletions src/main/java/endpoints/GenericEndpoint.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl]
*
* 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/>.
*/
package endpoints;

import malpull.Downloader;

/**
* This abstract class contains the shared code base for all endpoints, which is
* done to re-use code.
*
* @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl]
*/
public abstract class GenericEndpoint {

/**
* The downloader wrapper class that is used to make HTTP requests
*/
protected Downloader downloader;

/**
* The base URL of the API, to which specific API actions can be appended
*/
protected String apiBase;

public GenericEndpoint(String apiBase) {
//Sets the apiBase variable
this.apiBase = apiBase;
//Initialises the downloader class
downloader = new Downloader();
}
}
138 changes: 138 additions & 0 deletions src/main/java/endpoints/Koodous.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl]
*
* 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/>.
*/
package endpoints;

import exceptions.Error404NotFoundException;
import exceptions.Error429TooManyRequestsException;
import exceptions.HttpConnectionFailed;
import exceptions.SampleNotFoundException;
import okhttp3.Request;
import org.json.JSONArray;
import org.json.JSONObject;

/**
* This class is used to get a sample from the Koodous database via its API.
*
* @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl]
*/
public class Koodous extends GenericEndpoint {

/**
* The API key that is used to interact with the MalShare API
*/
private String key;

/**
* Creates an object to interact with the Koodous API
*
* @param key the MalShare API key which is required to use the API
*/
public Koodous(String key) {
//Sets the apiBase variable in the abstract GenericEndpoint class
super("https://koodous.com/api/apks");
//Sets the key variable
this.key = key;
}

/**
* Gets the sample from Koodous, if it is present. Throws an exception if it
* is not present.
*
* @param hash the hash to look for
* @return the sample as a byte array
* @throws HttpConnectionFailed if no connection can be made from the
* current machine, or to the given host
* @throws SampleNotFoundException if the sample cannot be found
* @throws Error404NotFoundException if the target returns a 404 status code
* @throws Error429TooManyRequestsException if the target returns a 429
* status code
*/
public byte[] getSample(String hash) throws HttpConnectionFailed, SampleNotFoundException, Error404NotFoundException, Error429TooManyRequestsException {
//Get the SHA-256 hash via the search function of the API, as only SHA-256 hashes can be used when downloading a sample
String sha256Hash = getSha256Hash(hash);
//Return the API's response
return download(sha256Hash);
}

/**
* Get the SHA-256 hash based upon a given MD-5, SHA-1, or SHA-256 hash. The
* download API of Koodous only accepts SHA-256 hashes when queried.
*
* @param hash the hash to query the back-end for, and obtain the SHA-256
* hash of the sample
* @return the SHA-256 hash of the given sample
* @throws HttpConnectionFailed if no connection can be made from the
* current machine, or to the given host
* @throws SampleNotFoundException if the sample cannot be found
* @throws Error404NotFoundException if the target returns a 404 status code
* @throws Error429TooManyRequestsException if the target returns a 429
*/
private String getSha256Hash(String hash) throws HttpConnectionFailed, SampleNotFoundException, Error404NotFoundException, Error429TooManyRequestsException {
//Create the url
String url = apiBase + "?search=" + hash + "&page=%1&page_size=%100";
//Create the requested, based on the given URL and with the required header token
Request request = new Request.Builder()
.url(url)
.addHeader("Authorization", "Token " + key)
.build();
//Get the result from the get request as a string
String result = new String(downloader.get(request));
//Convert the string in a JSON object
JSONObject jsonObject = new JSONObject(result);
//Get the count based on the search result
int count = jsonObject.optInt("count", 0);
if (count == 0) {
//If there are no hits, the sample is not present
throw new SampleNotFoundException();
}
//Get the results if there are any
JSONArray results = jsonObject.getJSONArray("results");
//Return the SHA-256 hash of the first hit
return results.getJSONObject(0).getString("sha256");
}

/**
* Download the sample from the API
*
* @param hash the SHA-256 hash of the sample to download
* @return the API's response, which is the raw file
* @throws HttpConnectionFailed if no connection can be made from the
* current machine, or to the given host
* @throws Error404NotFoundException if the target returns a 404 status code
* @throws Error429TooManyRequestsException if the target returns a 429
*/
private byte[] download(String hash) throws HttpConnectionFailed, Error404NotFoundException, Error429TooManyRequestsException {
//Create the URL
String url = apiBase + "/" + hash + "/download";
//Prepare the request with teh API token
Request request = new Request.Builder()
.url(url)
.addHeader("Authorization", "Token " + key)
.build();
//Get the result from the API as a string
String temp = new String(downloader.get(request));
//Convert the string into a JSON object, and get the direct download URL
String directUrl = new JSONObject(temp).getString("download_url");
//Reset the request to the direct download URL
request = new Request.Builder()
.url(directUrl)
.addHeader("Authorization", "Token " + key)
.build();
//Return the value of the direct download link
return downloader.get(request);
}
}
99 changes: 99 additions & 0 deletions src/main/java/endpoints/MalShare.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl]
*
* 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/>.
*/
package endpoints;

import exceptions.Error404NotFoundException;
import exceptions.Error429TooManyRequestsException;
import exceptions.SampleNotFoundException;
import exceptions.HttpConnectionFailed;
import okhttp3.Request;

/**
* This class is used to get a sample from the MalShare database via its API.
*
* @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl]
*/
public class MalShare extends GenericEndpoint {

/**
* The API key that is used to interact with the MalShare API
*/
private String key;

/**
* Creates an object to interact with the MalShare API
*
* @param key the MalShare API key which is required to use the API
*/
public MalShare(String key) {
//Sets the apiBase variable in the abstract GenericEndpoint class
super("https://malshare.com/api.php?api_key=" + key + "&action=");
//Sets the key variable
this.key = key;
}

/**
* This API call will return a byte array if the sample is found. If it is
* not found, a plain text response that starts with "Sample not found by
* hash" is given.
*
* @param hash the sample's hash
* @return the URL to get the sample from
*/
private String getDownloadUrl(String hash) {
return apiBase + "getfile&hash=" + hash;
}

/**
* Gets the sample from MalShare, if it is present. Throws an exception if
* it is not present.
*
* @param hash the hash to look for
* @return the sample as a byte array
* @throws HttpConnectionFailed if no connection can be made from the
* current machine, or to the given host
* @throws SampleNotFoundException if the sample cannot be found
* @throws Error404NotFoundException if the target returns a 404 status code
* @throws Error429TooManyRequestsException if the target returns a 429
* status code
*/
public byte[] getSample(String hash) throws HttpConnectionFailed, SampleNotFoundException, Error404NotFoundException, Error429TooManyRequestsException {
//Gets the URL
String url = getDownloadUrl(hash);
//Create the request based on the URL
Request request = new Request.Builder()
.url(url)
.build();
//Get the result from the API
byte[] result = downloader.get(request);
//Convert the result into a new string to check what the result is
String temp = new String(result);
/**
* If the sample is not present in the MalShare API, a plain text string
* is returned. This string contains the "Sample not found by hash"
* text. If string contains this text, the sample cannot be found.
* Otherwise, the returned value is the raw file
*/
if (temp.contains("Sample not found by hash")) {
//If the sample cannot be found, an exception is thrown
throw new SampleNotFoundException();
}
//Return the sample
return result;
}

}
Loading

0 comments on commit 92a066c

Please sign in to comment.