Projektarbeit: Erkennung von Schadsoftware auf Androidgeräten

Während der Vorbereitung auf meine Masterarbeit habe ich diese Projektarbeit verfasst, dessen Schwerpunkt letztendlich die Erstellung des „App-Checkers“ war. Ein weiterer Schwerpunkt der Arbeit ist der Versuch aus Apps zur ihrer Laufzeit Informationen zu ihrem Verhalten zu entlocken.

In der Arbeit wird von einem Modell gesprochen, welches mit einer Support-Vektor-Maschine erstellt wurde. Dieses Modell enthält die Intelligenz vom App-Checker, also die Informationen welche Merkmale eine App enthalten muss damit sie als böse bzw. gut klassifiziert wird. Inzwischen gibt es eine Veröffentlichung zu dem Modell:

Drebin: Efficient and Explainable Detection of Android Malware in Your Pocket. (Daniel Arp, Michael Spreitzenbarth, Malte Hübner, Hugo Gascon, and Konrad Rieck.) In: Proc. of Network and Distributed System Security Symposium (NDSS), to appear 2014.

Drebin-Paper

 

Python Parameter-Tupel-Class

This simple piece of software is able to generate and iterate over a set of parameter-tuples. You specify the lower and upper bounces, the step width and the type (linear or logarithmic) for each parameter, then this class generate all combinations of parameters and saves it in tuples. You can consume each tuple with a simple while-loop.

Here is a simple example:

You need two parameter. The first is a binary one with {0,1} and the second is out of {-1, 0, 1}. The class would generate you 6 two-tuples with:
(0.0, -1.0), (0.0, 0.0), (0.0, 1.0),
(1.0, -1.0), (1.0, 0.0), (1.0, 1.0)
ParamTuple
ParamTuple
ParamTuple.txt
1.9 KiB
201 Downloads
Details
'''
Created on 06.06.2013

@author: ize
'''

import numpy as np

class ParamTuple:

	lastTuple = ()
	tupl = ()
	actualTuplePointer = 0

	def next(self):
		self.lastTuple = self.tupl
		self.tupl = self.tuplesArray[self.actualTuplePointer]
		if len(self.tupl)!=0:
			self.actualTuplePointer+=1
			return self.tupl
		else:
			return ()

	def hasMoreTuples(self):
		return self.actualTuplePointer<len(self.tuplesArray)

	def size(self):
		return len(self.tuplesArray)

	def getLastTuple(self):
		return self.lastTuple

	def __init__(self, *tuples):
		spacesArray = []

		for tup in tuples:
			if type(tup) != tuple:
				raise BaseException("Parameters are not only tuples")
			if len(tup) != 4:
				raise BaseException("All tuples must have length 4")
			if type(tup[0]) != str or (tup[0] != 'log' and tup[0]!='lin'):
				raise BaseException("First tuple-entry is not a string of log or lin")
			if type(tup[1]) != float or type(tup[2]) != float or type(tup[2]) != float:
				raise BaseException("Last three tuple-enties are not float-numbers")

			# ok this tuple is valid:
			if tup[0] == 'log':
				tmpSpace = np.logspace(tup[1], tup[2],tup[3])
			else:
				 tmpSpace = np.linspace(tup[1],tup[2],tup[3])
			spacesArray.append(tmpSpace)

		#generate code and execute it: 
		execstr = "tuplesArray = []\n"
		for i in range(0,len(spacesArray)):
			execstr += "for var" + str(i) + " in spacesArray["+str(i)+"]:\n\t"
			execstr += ("\t"*i)

		#tabs = "\t"*(len(spacesArray)-1)
		#execstr += tabs
		execstr += "tuplesArray.append(("
		for i in range(0,len(spacesArray)):
			execstr += "var"+str(i)+","	 # this last , is a "must have" ^^ for tuples with only one entry 
		execstr+= "))"

		#print execstr
		exec(execstr)
		self.tuplesArray = tuplesArray

if __name__ == '__main__':
	print 'ParamTuple.py:'
	g = ParamTuple(('log',-3.0,0.0,4.0), ('log',-2.0,2.0,5.0))
	print g.size()
	while(g.hasMoreTuples()):
		print g.next()

Galaxy Gear Development – Kurztest

Schon als ich von meiner besseren Hälfte die Uhr das erste Mal in die Hand bekam, sah ich mit Freude die „USB-Debugging“-Option. Einmal aktiviert und an USB angeschlossen verhält sich die Uhr wie jedes andere Android-Gerät auch. Mit einer Neuerung, die ich bisher nicht kannte: Man muss den Debugging-Zugriff auf der Uhr explizit für den angeschlossenen Computer erlauben. Gleiches gilt im Übrigen auch für das Note 3, welches dann – wie die Uhr auch – den Nutzer automatisch nach Erlaubnis fragt.

Nach der Bestätigung ist die Uhr über die Android Debug Bridge (adb) ganz normal erreichbar und kann für die Entwicklung verwendet werden. Als Erstes habe ich mir mittels

adb shell

mal den Inhalt des Systems angesehen. Für vollen Zugriff gibt es sogar schon Rooting-Lösungen, die ich aber nicht getestet habe – ist ja nicht meine Uhr ;). Nachdem ich dann sichergestellt hatte, dass es sich um ein normales Android handelt wollte ich wissen:

Welche Apps wohl auf dieser Uhr laufen?

Mehr aus Faulheit mir zu überlegen, was man mal installieren könnte habe ich einfach in Eclipse beim App-Checker auf „Play“ gedrückt und siehe da, es installierte und startete völlig normal. Sogar das Layout war okay und ließ sich bedienen. Mit ein paar Tipps auf der Uhr war die zu analysierende App ausgesucht und die Analyse lief. Kurze Zeit später konnte man schon das Ergebnis begutachten und ich stellte fest: Auch die nativen Bibliotheken hatten ihre Arbeit geleistet.

Beeindruckt von dem Erfolg installierte ich TicTacTo, eine App, die ich für meine Hiwi-Stelle im „allgemeinen Programmierpraktikum“ an der Uni zu Testzwecken geschrieben hatte. Der Vorteil, ich hatte damals ein quadratisches Layout gebaut, von dem die Uhr natürlich absolut profitiert. Leider bin ich bisher nicht dazu gekommen eine anständige KI zu schreiben, aber im Alltag macht das Spiel – wenn überhaupt – eh nur mit echten Gegnern Spaß.

Da ich meiner Freundin jetzt etwas zum Spielen im Alltag installiert hatte, 😀 … überlegte ich kurz, was mögliche sinnvolle Anwendungen für die Uhr sein könnten und hatte zwei Ideen: Zum einen, ein Taschenrechner, den man so schnell griffbereit hat und zum Anderen einen QR-Code Scanner.

Nachdem sich der auf dem Note 3 vorhandene Taschenrechner nicht installieren lassen wollte, suchte ich im Google Play Store nach einem simplen Taschenrechner, der so aussieht, als würde er auch auf nahezu quadratischen Displays funktionieren können. Kurz und bündig: installieren und starten: ja; Benutzbarkeit: nein. Man müsste einen für das Display optimierten Taschenrechner zusammentüfteln.

Beim QR-Code Scanner hatte ich zunächst auch kein Glück, denn den QR-Code Scanner, den ich mir von meinem gerooteten S3 ausgeliehen habe wollte unbedingt die Google-Maps Bibliothek für die Installation haben (was ich prima mit meinem App-Checker überprüfen konnte … 🙂 ). Nach etwas Googlen fand ich einen weiteren QR- und Barcode Scanner, der nicht so aussah, als wollte er irgendwelche Karten anzeigen und lud diesen aus dem Play-Store runter. Die Installation klappte problemlos. Allerdings forderte es eine Menge Konzentration den Bildausschnitt des QR-Codes in das vorgegebene Fenster zu bringen, denn die Displayausrichtung passte nicht sonderlich gut zu der Kamera, sodass man die Uhr in zwei von drei Dimensionen spiegelverkehrt bewegen musste.

Als ich also nun herausgefunden hatte, das sich die Uhr durchaus auch für Entwicklung eignet habe ich mal etwas gegoogelt und einen Beitrag gefunden, in dem der Nova Launcher installiert wird, mit dem man dann das Gefühl einer normalen Androidoberfläche bekommt – funktioniert auch, habe aber keinen Vorteil darin gesehen.

Eins noch: Nach einem Update musste ich den Entwicklermodus freischalten, was ich mit 7x drücken auf die Softwareversion geschafft habe – auch eine Neuerung, die ebenfalls im Note 3 Einzug erhalten hat.

P.S.: Die Screenshots habe ich mit

adb shell  screencap -p /sdcard/<screenshot_name.png>

und

adb pull 

gemacht.

Access /data/app/-content from Android-application

Da meine App „App-Checker“ auf dem Handy andere Apps analysieren kann, sollte sie auch Zugriff auf die bereits auf dem Handy installierten Apps haben. Der Dateibrowser kann ohne root-Rechte allerdings nicht zu dem Ordner /data/app/ navigieren, da der „App-Checker“ nicht die Rechte besitzt den Inhalt zu lesen.

Dass es aber eine Möglichkeit gibt, die Apps aus dem Ordner zu lesen habe ich bei „Dex Dump“ und „Dexplorer“ gesehen und bin dem nachgegangen. Eigentlich ist die Lösung ganz einfach… 😉 :

private List<File> getDataApps(String dir) {
	ArrayList<File> list = new ArrayList<File>();
	Iterator<ApplicationInfo> apps = this.getPackageManager()
		.getInstalledApplications(PackageManager.GET_ACTIVITIES)
		.iterator();
	while (apps.hasNext()) {
		ApplicationInfo applicationInfo = (ApplicationInfo) apps.next();
		String path = applicationInfo.sourceDir;
		if (path.startsWith(dir)) {
			list.add(new File(path));
		}
	}
	return list;
}

Google Play Store-Kategorie von Apps finden

Stellt ein Entwickler seine Android-App im Google Play Store ein, muss er eine der – von Google vorgegebenen – Kategorien auswählen, in die die App gehört. Die Kategorie ist dabei nur dem Eintrag im Google Play Store zugeordnet und nicht teil der App selbst.

Möchte man nun zu einer App die zugehörige Kategorie finden, kann man dies anhand des Namens aber auch des Paketnamens suchen. Hier ein Beispiel: https://play.google.com/store/search?q=friendstatus%20de.izeland.friendstatus&c=apps.

Um die Kategorie zu finden, muss man von dieser Ergebnisseite zum Store-Eintrag der jeweiligen App weiterklicken. In der Beschreibung und dem zugehörigen Quelltext der Seite ist die Kategorie auf Englisch und Deutsch verfügbar.

Um alle Apps aus dem Datensatz meiner Masterarbeit zur kategorisieren habe ich ein simples Tool geschrieben, was den eben beschriebenen Vorgang automatisiert:

1. Aus den Apps (genauer einem Ordner mit den *.apk-Dateien) den Namen und den Paketnamen jeder App auslesen.

2. Im Google Play Store als Suchbegriff eingeben und den passenden Eintrag (in der  Regel ist dies der erste) der Suchergebnisse auswählen.

3. Auf der Beschreibungsseite der App die Kategorie extrahieren.

4. Die App auf dem eigenen System in den entsprechenden Ordner der Kategorie verschieben.

Dieses Tool wurde nur als Hilfsmittel programmiert und der Nutzer sollte sich den Quelltext vielleicht anschauen und auf seine Bedürfnisse anpassen. Für größere Datensätze kann eventuell der Heap nicht ausreichen – Fix: -Xmx1024M beim Ausführen der JavaVM angeben.

Bei mir ist es häufig vorgekommen, dass Apps, die beim ersten Durchlauf nicht zu kategorisieren waren, aufgrund eines anderen Fehlers nicht gefunden werden konnten und ein zweiter, dritter, etc. Durchlauf später zum Erfolg führte.

Bisher ist mir kein besserer Ansatz als dieser eingefallen und das Ergebnis ist leider nur teilweise befriedigend. Ich habe meine knapp 140.000 Apps sortieren können, wobei ca. die Hälfte nicht eingruppiert werden konnte (was vielleicht am Datensatz liegen mag, da nicht alle aus dem Play Store stammen). Vielleicht hilft es dennoch jemandem, der seine Apps anhand der Google Play Store Kategorien sortieren muss / möchte und er findet hiermit einen ersten Versuch.

Category Finder
Category Finder
Category Finder.zip
Version: 1.0
4.3 MiB
103 Downloads
Details

App-Checker Desktop: A Java Static Feature Generator for APK-Files

Dieses Tool mit dem Namen „App-Checker Desktop“ ist in der Lage aus einer *.apk-Datei – also einer Android-App – die unten genannten Merkmale zu extrahieren.

Hintergrund: Dieses Tool, was kurzfristig den Namen „App-Checker Desktop“ erhalten hat, entstand während der Projektphase zu meiner Masterarbeit und ist die Desktop-Version der im Rahmen dieses Projektes entwickelten App (dem App-Checker).

Motivation: Damit der App-Checker mittels der Methode  „Drebin“ Vorhersagen über die Bös- oder Gutartigkeit dritter Apps – auf dem Android-Gerät – machen kann, muss er in der Lage sein aus einer *.apk-Datei die gleichen Merkmale zu extrahieren, wie es der Webservice Mobile Sandbox tut. Mit der hier vorgestellten Desktop-Version kann man nun unabhängig von Android-Gerät oder der Mobile Sandbox die folgenden Merkmale auf dem Rechner generieren:

Aus dem Android-Manifest:

1. Angeforderte Rechte der App
2. Angeforderte Hard- und Software
3. Intents
4. Activities
5. Services
6. ContentProvider
7. Broadcast Reciever

Aus dem dexdump -d – Auszug (Assambler der App):
1. Benutzte Rechte
2. Benutzte API-Aufrufe, die Rechte benötigen
3. Benutzte gefährliche API-Aufrufe (können selbst festgelegt werden)
4. Benutzte „Networks“
5. Gefundene URLs und IPs

Ist man nicht wie ich an Java als Programmiersprache gebunden empfehle ich für diesen Anwendungsfall androguard.

 

AppChecker Desktop
AppChecker Desktop
AppChecker Desktop.zip
Version: 1.0
3.8 MiB
115 Downloads
Details

Java LibSVMFormatReader

„svm-predict“ gibt für die one-class-SVM scheinbar nur die vorhergesagten Labels zurück, nicht aber die Vorhersagewerte für die Daten. Da das auch für die Java-libsvm-Varriante gilt – die ich in der Android-App zu meiner Masterarbeit benutze – hier eine Klasse, die aus einer Datei im libsvm-Format die Daten in der internen libsvm-Datenstruktur zurückgibt (d. h. als svm_node[][]). Damit kann man dann nach Belieben eine der „predict“-Funktionen von libsvm aufrufen und somit auch die Vorhersagewerte erhalten.

Nachdem die Klasse fertig war, habe ich doch noch in der Java-libsvm-Implementierung ähnliche Funktionalität entdeckt (svm_predict.java – predict(BufferedReader, DataOutputStream, svm_model, int) und musste feststellen, dass ich mir mehr Gedanken bei der Regex hätte machen sollen ;). Aber nun ist es fertig und dafür wenigstens alleinstehend ohne „predict“-Funktion drum herum – vielleicht hilft es ja noch jemandem.

import java.io.BufferedReader;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

import libsvmimpl.libsvm.svm_node;

public class LibSVMFormatReader {

	private BufferedReader libsvmFormatFileReader;
	private svm_node[][] x;
	private double[] y;

	//////////////////
	// Constructors //
	//////////////////
	public LibSVMFormatReader(String libSVMFormatFilename) throws IOException {
		this(new File(libSVMFormatFilename));
	}

	public LibSVMFormatReader(BufferedReader buf) throws IOException {
		this.libsvmFormatFileReader = buf;
		convert();
	}

	public LibSVMFormatReader(File libSVMFormatFile) throws IOException {
		this(new BufferedReader(new InputStreamReader(new FileInputStream(
				libSVMFormatFile))));
	}

	////////////////
	// Converters //
	////////////////
	private void convert() throws IOException {
		ArrayList<svm_node[]> nodeArrayList = new ArrayList<svm_node[]>();
		ArrayList labelsList = new ArrayList();

		String line;
		while ((line = this.libsvmFormatFileReader.readLine()) != null) {
			nodeArrayList.add(devideRow(line));
			labelsList.add(getLabel(line));
		}

		// Copy references 1 by 1:
		svm_node[][] svm_nodeArray = new svm_node[nodeArrayList.size()][];
		double[] labels = new double[labelsList.size()];
		if (labels.length != svm_nodeArray.length) {
			throw new IllegalArgumentException(
					"Converting to Java-libsvm failed: could not find the same number of labels and vectors.");
		}

		for (int i = 0; i < svm_nodeArray.length; i++) {
			svm_nodeArray[i] = nodeArrayList.get(i);
			labels[i] = labelsList.get(i);
		}

		this.x = svm_nodeArray;
		this.y = labels;
	}

	private double getLabel(String line) {
		double ret = Double.NaN;
		try {
			ret = Double.parseDouble(line.split("\\s")[0]);
		} catch (NumberFormatException e) {
			throw new IllegalArgumentException(
					"Could not parse label to double-value.", e);
		} catch (ArrayIndexOutOfBoundsException e) {
			throw new IllegalArgumentException(
					"Could split line into different parts.", e);
		}
		return ret;
	}

	/**
	 * This method takes one row from the libsvm-format and converts it into a
	 * svm_node[]. On error it throws an exception.
	 * 
	 * @param row
	 * @return
	 */
	private svm_node[] devideRow(String row) {
		try {
			svm_node tNode;
			String[] tSplit;
			String tToken;

			ArrayList<svm_node> nodes = new ArrayList<svm_node>();

			// TODO Try out which space or character works finest:
			String[] segs = row.split("\\s");
			for (String string : segs) {
				// Skip first - its the label
				// and make sure there nothing suspicious:
				tToken = string.trim();
				if (tToken.contains(":")) {
					tNode = new svm_node();
					tSplit = tToken.split(":");
					tNode.index = Integer.parseInt(tSplit[0]);
					tNode.value = Double.parseDouble(tSplit[1]);
					nodes.add(tNode);
				}
			}

			// Copy to array 1 by 1:
			svm_node[] svm_nodes = new svm_node[nodes.size()];
			for (int i = 0; i < svm_nodes.length; i++) {
				svm_nodes[i] = nodes.get(i);
			}

			if (svm_nodes.length == 0) {
				throw new IllegalArgumentException(
						"No index-value-pairs found.");
			}

			return svm_nodes;

		} catch (NumberFormatException e) {
			throw new IllegalArgumentException(
					"Could not parse index or value into a number. Please proof your file.",
					e);
		}
	}

	/////////////////
	// getXYZ(...) //
	/////////////////

	public double[] getY() {
		return y;
	}

	public svm_node[][] getX() {
		return x;
	}

	/*
	 * Test-Main ...
	 */
	public static void main(String[] args) {
		try {
			LibSVMFormatReader libSVMFormatReader = new LibSVMFormatReader(
					"/Volumes/Android/BENIGN/LEARNDATA/libsvm/MW/25/BUSINESS_25_MW.libsvmS");
			svm_node[][] nA = libSVMFormatReader.x;
			double[] y = libSVMFormatReader.y;
			for (int i = 0; i < y.length; i++) {
				System.out.print("LABEL: " + y[i] + " ");
				for (svm_node node : nA[i]) {
					System.out.print(node);
				}
				System.out.println();
			}

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
LibSVMFormatReader
LibSVMFormatReader
LibSVMFormatReader.java
4.2 KiB
660 Downloads
Details