-
Die vorliegende Erfindung betrifft ein Verfahren zum Generieren einer obfuskierten Softwareapplikation, eine Computervorrichtung, die eingerichtet ist, das erfindungsgemäße Verfahren auszuführen, eine Softwareapplikation, die mittels des erfindungsgemäßen Verfahrens generiert wurde, sowie eine Computervorrichtung, insbesondere ein mobiles Endgerät, auf welcher bzw. welchem eine mittels des erfindungsgemäßen Verfahrens generierte Softwareapplikation bereitgestellt ist.
-
Mobile Endgeräte, beispielsweise in Form von Smartphones, Tablet-Computern, persönlichen digitalen Assistenten oder dergleichen, werden zunehmend verwendet, um digitale Transaktionen auszuführen, wie etwa das Einkaufen von Waren im Internet, Online-Banking, oder dergleichen. Bei der Durchführung einer solchen digitalen Transaktion interagiert in der Regel eine auf dem mobilen Endgerät installierte Softwareapplikation (häufig kurz „App“ genannt) mit einem Server. Um die Transaktionen ausführen und abwickeln zu können, sind in der installierten Softwareapplikation üblicher Weise sicherheitskritische Daten hinterlegt, wie zum Beispiel Passwörter oder kryptographische Schlüssel.
-
Um derartige sicherheitskritische Daten vor einem Angreifer zu schützen, ist es zum Beispiel aus
DE 10 2014 019 090 A1 bekannt, den Programmcode der Softwareapplikation zu obfuskieren bzw. zu verschleiern, indem unter Beibehaltung der Funktionalität der Softwareapplikation zusätzliche Anweisungen in den Programmcode eingefügt und/ oder ursprüngliche Anweisungen in andere Anweisungen aufgeteilt werden. Das Obfuskieren wird dabei üblicherweise mit Hilfe einer entsprechenden Softwareanwendung vorgenommen, die auch als Obfuskator bezeichnet wird. Dem Obfuskator steht hierzu neben dem zu obfuskierenden Programmcode - in Form von Quellcode, Zwischencode, Bytecode oder Maschinencode und abhängig vom verwendeten Obfuskator, der jeweiligen und/ oder Zielarchitektur - insbesondere ein Obfuskierungsparameter zur Verfügung, beispielsweise in Form eines Zahlenparameters, welcher den Grad der Obfuskierung bzw. das Ausmaß der gewünschten Verschleierung des Programmcodes angibt.
-
Mit einer derart obfuskierten Softwareapplikation wird einem potentiellen Angreifer ein Reverse-Engineering, also das Identifizieren der ursprünglichen, funktional wichtigen Anweisungen der Softwareapplikation, erheblich erschwert oder gar unmöglich gemacht. Aus Sicherheitsgründen ist es daher wünschenswert, einen möglichst hohen Grad der Obfuskation zu verwenden.
-
Ein hoher Grad an Obfuskation bedeutet jedoch auch, dass die Softwareanwendung durch viele zusätzliche bzw. aufgeteilte und der Verschleierung dienende Anweisungen redundant erweitert wird, so dass der erforderliche Speicherplatz erhöht und das Laufzeitverhalten der Softwareapplikation beeinträchtigt wird und die Ausführung der Softwareapplikation verlangsamt wird.
-
Vor dem Hintergrund, dass auf mobilen Endgeräten zunehmend große Mengen an Mediendaten wie Fotos und Videos gespeichert werden und sie dementsprechend mit großen Speicherkapazitäten von einigen 10 GB und mehr ausgestattet sind, besitzt der durch die Obfuskierung bedingte zusätzliche Speicherbedarf demgegenüber eine lediglich untergeordnete und praktisch vernachlässigbare Bedeutung.
-
Hingegen ist das durch die Obfuskierung beeinflusste Laufzeitverhalten der Softwareapplikation von wesentlicher Bedeutung. Insbesondere führt die Obfuskierung je nach deren Grad zu einem trägeren Antwortverhalten bei Benutzerinteraktionen, Animationen beginnen zu ruckeln und Informationsdarstellungen erscheinen nur mit wahrnehmbarer Verzögerung. Für einen Benutzer erscheint die Softwareapplikation dadurch träge und schwerfällig zu bedienen. Aus der Sicht der Benutzerakzeptanz ist es daher notwendig, dass die Obfuskierung das Antwortverhalten der Softwareapplikation nicht so wahrnehmbar verschlechtert wird, dass sie von Benutzern als unkomfortabel abgelehnt wird.
-
In der Praxis ergibt sich somit ein Zielkonflikt zwischen einem aus Sicherheitsgründen erwünschten möglichst hohen Grad an Obfuskierung und der Sicherstellung eines für Benutzer akzeptablem Antwortverhalten der Softwareapplikation. Dies erfordert ein iteratives Vorgehen, bei dem wiederholt Obfuskierungsparameter gewählt werden und die entsprechend obfuskierte Softwareapplikation hinsichtlich ihres Antwortverhaltens getestet wird, bis ein optimaler Kompromiss zwischen dem Grad der Obfuskierung und den Antwortverhalten der Softwareapplikation erreicht wird. Dieses Vorgehen nach Versuch-und-Irrtum-Prinzip erfordert viele Tests und ist aufwändig und fehleranfällig.
-
Ein weiterer Nachteil dieses Verfahrens ist, dass nur ein einziger Parameter für die gesamte Softwareapplikation bestimmt wird, obwohl verschiedene Programmteile unterschiedliche Laufzeitverhalten aufweisen und entsprechend unterschiedliche Obfuskierungsparameter erfordern würden.
-
Darüber hinaus besteht der Nachteil, dass der Obfuskierungsparameter manuell eingestellt wird und daher bei Änderungen und Aktualisierungen der Softwareapplikation das vorstehend beschriebene Vorgehen erneut vorgenommen werden muss.
-
Insofern ist es die Aufgabe der vorliegenden Erfindung, eine Lösung zu schaffen, die die beschriebenen Nachteile des Standes der Technik vermeidet und ein verbessertes Verfahren zum Bereitstellen einer obfuskierten Softwareapplikation anzugeben.
-
Gelöst wird diese Aufgabe und andere Aufgaben durch ein Verfahren und Vorrichtungen sowie eine Softwareapplikation gemäß den unabhängigen Ansprüchen. In den abhängigen Ansprüchen sind vorteilhafte Ausgestaltungen und Weiterbildungen der Erfindung angegeben.
-
Gemäß eines Aspekts der Erfindung umfasst ein Verfahren zum Generieren einer obfuskierten Softwareapplikation die Schritte des Bereitstellens eines Quellcodes der Softwareapplikation, des Kompilierens bzw. Übersetzens des Quellcodes mit einem Compiler bzw. Übersetzer in kompilierten bzw. übersetzten Programmcode und des Obfuskierens des bereitgestellten Quellcodes und/ oder des kompilierten Programmcodes mittels eines Obfuskators. Erfindungsgemäß wird dabei der Quellcode analysiert, um darin enthaltene Ereignisbehandlungsroutinen (engl. „event handler“) zu identifizieren und für eine identifizierte Ereignisbehandlungsroutine einen Obfuskierungsparameter, oder kurz „Parameter“, zu bestimmen, der einen Grad der maximal zulässigen Obfuskierung für diese Ereignisbehandlungsroutine angibt. Die Ereignisbehandlungsroutine wird anschließend gemäß dem bestimmten Parameter obfuskiert, also maximal zulässig verschleiert.
-
Die Erfindung nutzt auf vorteilhafte Weise den Umstand, dass Softwareapplikationen ereignisbasiert arbeiten, dass sie also üblicherweise auf Ereignisse bzw. Events wie Benutzereingaben, eingehende Daten oder zutreffende Bedingungen warten, um dann eine entsprechende Ereignisbehandlungsroutine (Event Handler) aufzurufen, die das betreffende Ereignis bearbeitet. Die Dauer, die zur Ereignisbehandlung durch die betreffende Routine erforderlich ist, stellt aus Benutzersicht die relevante wahrnehmbare Eigenschaft des Laufzeitverhaltens der Softwareapplikation dar.
-
Die Fokussierung auf die Ereignisbehandlung ermöglicht es, für die Obfuskierung relevante, insbesondere optimale Parameter automatisch und maschinell zu ermitteln, so dass eine mühsame und fehleranfällige manuelle und nur suboptimale iterative Ermittlung im Versuch-und-Irrtum Verfahren nicht länger notwendig ist. Damit entfällt auch die Notwendigkeit, eine generierte obfuskierte Softwareapplikation wiederholt auf ihr Antwortverhalten zu testen. Im Ergebnis kann die Obfuskierung von Softwareapplikationen wesentlich vereinfacht und weitestgehend oder gar vollständig automatisiert werden. Der zum Generieren einer obfuskierten Softwareapplikation erforderliche Aufwand, insbesondere derjenige infolge manueller Interaktion, kann daher wesentlich reduziert werden.
-
Darüber hinaus können für die Obfuskierung relevante und insbesondere optimale Parameter für einzelne Ereignisbehandlungsroutinen bzw. für die diesen zugeordnete Codebereiche einschließlich den von den Ereignisbehandlungsroutinen aufgerufenen Funktionen separat ermittelt werden. Dies erlaubt, unterschiedliche Codebereiche unterschiedlich zu obfuskieren und die Obfuskierung dadurch für einzelne Ereignisbehandlungsroutinen bzw. die diesen zugeordneten Codebereichen separat zu optimieren. Weniger zeitkritische Codebereiche können daher zu einem höheren Grad obfuskiert werden und dort ein höheres Sicherheitsniveau ausbilden, ohne dass dabei zeitkritischere Codebereiche negativ beeinträchtigt werden. Dies ermöglicht eine insgesamt bessere und optimalere Obfuskierung der Softwareapplikation, während gleichzeitig automatisch gewährleistet wird, dass zeitkritische Benutzerinteraktionen der Softwareapplikation mit dem Benutzer noch innerhalb des akzeptablen Rahmens liegen. Das Auftreten von Fehlern durch ein manuelles, iteratives Vorgehen wird dadurch eliminiert.
-
In diesem Zusammenhang ist unter einer optimaleren oder maximal zulässigen Obfuskierung bzw. einer Obfuskierung basierend auf einem optimalen Obfuskierungsparameter eine solche Obfuskierung zu verstehen, die eine maximale Verschleierung des Quell- und/ oder Programmcodes einer Ereignisbehandlungsroutine hervorruft, ohne dass das Laufzeitverhalten dieser Routine bzw. der übergeordneten Applikationssoftware für einen Anwender wahrnehmbar beeinträchtigt wird.
-
Die Bestimmung des Parameters der maximal zulässigen Obfuskierung einer Ereignisbehandlungsroutine kann insbesondere das Festlegen einer maximal zulässigen Ausführungszeit für die entsprechende Ereignisbehandlungsroutine sowie die Bestimmung der zur Ausführung der Ereignisbehandlungsroutine erforderlichen Anzahl an Prozessortakten betreffen, um daraus den Parameter der maximal zulässigen Obfuskierung abzuleiten. Vorzugsweise wird dabei die zur Ausführung der Ereignisbehandlungsroutine erforderlichen Anzahl an Prozessortakten in eine Ausführungszeit auf einer vorgegebenen Referenzplattform umgerechnet und es wird der Quotient aus der einzuhaltenden maximalen Ausführungszeit für die Ereignisbehandlungsroutine und der Ausführungszeit auf der Referenzplattform gebildet, und der Obfuskierungsparameter wird basierend auf diesem Quotienten bestimmt.
-
Indem auf ohne Obfuskieren erforderlichen Ausführungszeiten und maximal zulässigen Ausführungszeiten abgestellt wird, lässt sich ein optimaler Grad der Obfuskierung realisieren, indem jede Ereignisbehandlungsroutine bis zum maximal möglichen Grad obfuskiert bzw. erweitert wird. Bei diesem maximal möglichen bzw. optimalen Grad nimmt der Benutzer noch keine Beeinträchtigung des Laufzeitverhaltens der betreffenden Softwareapplikation wahr.
-
Vorzugsweise wird die zur Ausführung einer Ereignisbehandlungsroutine erforderliche Anzahl an Prozessortakten durch rekursives Identifizieren der von dieser Routine rekursiv aufgerufenen Funktionen bestimmt. Für jede auf diese Weise rekursiv identifizierte Funktion wird die zur Ausführung erforderliche Anzahl an Prozessortakten bestimmt und die Summe der Anzahl der Prozessortakte aller identifizierten Funktionen entspricht dann der zur Ausführung der Ereignisbehandlungsroutine erforderlichen Anzahl an Prozessortakten.
-
Die Ereignisbehandlungsroutinen werden dabei nicht als „Black Box“ betrachtet, sondern detailliert analysiert hinsichtlich aller wesentlichen Laufzeiteffekte bei Ausführen von Funktionen zu Unterfunktionen. Dies ermöglicht eine akkurate, zutreffende und sichere Bewertung des Laufzeitverhaltens der Ereignisbehandlungsroutinen und somit die zuverlässige Optimierung der Obfuskierung.
-
Dabei kann vorgesehen sein, dass für eine identifizierte Funktion, die eine Betriebssystem-API Funktion ist, kein weiteres rekursives Identifizieren von aufgerufenen Funktionen erfolgt. Das rekursive Identifizieren von aufgerufenen Funktionen wird vorzugsweise beendet, sobald eine Betriebssystem-API Funktion identifiziert wird, denn Betriebssystem-API Funktionen haben ein bekanntes und festgelegtes Laufzeitverhalten, das eine weitergehende Analyse dieser Funktionen nicht notwendig macht und der rechnerische Aufwand verringert werden kann.
-
Der Quellcode der Softwareapplikation kann beispielsweise in Java, C, C++, Objective-C, C#, Swift oder einer anderen für die Softwareapplikation und/ oder die Zielplattform geeignete Programmiersprache erstellt sein. Der kompilierte Programmcode wiederum kann ein Maschinencode sein oder maschinennaher Code, oder Zwischencode sein, wie etwa ein Bytecode, insbesondere ein Java-Bytecode, oder ein CIL-Code in „Common Intermediate Language“ für das .NET Framework. Für den Fall, dass der kompilierte Programmcode ein Bytecode ist, kann eine weitere Kompilierung den Bytecodes in einen Maschinencode für die Zielplattform übersetzen, zum Beispiel mittels eines Ahead-of-Time Compilers.
-
Im Falle eines Bytecodes wird die Anzahl der zur Ausführung einer Funktion erforderlichen Prozessortakte vorzugsweise der Bytecode durch Analysieren der Funktionen vor dem Obfuskieren ermittelt, indem die Anzahl an Prozessortakten, welche dieser Bytecode bzw. die Summe seiner Funktionen zur Ausführung als Maschinencode benötigen würde bzw. nach einer Kompilierung benötigen wird, ermittelt wird.
-
Für den Fall, dass eine oder mehrere der identifizierten Funktionen einer Ereignisbehandlungsroutine Betriebssystem-API Funktionen sind, wird der Parameter, der eine maximal zulässige Obfuskierung angibt, vorzugsweise als das Produkt von zwei Quotienten bestimmt. Hierbei ist eine der beiden Multiplikatoren dieses Produkts der Quotient aus der festgelegten, einzuhaltenden maximalen Ausführungszeit für die Ereignisbehandlungsroutine und der Ausführungszeit der Ereignisbehandlungsroutine auf der Referenzplattform. Der andere der beiden Multiplikatoren des Produktes ist der Quotient aus der zur Ausführung der Ereignisbehandlungsroutine erforderlichen Anzahl an Prozessortakten und der Summe der zur Ausführung all jener identifizierten Funktion erforderlichen Anzahl an Prozessortakten, die keine Betriebssystem-API Funktion sind.
-
Die besondere Behandlung von Betriebssystem-API Funktionen im Zusammenhang mit der vorliegenden Erfindung liegt darin begründet, dass Betriebssystem-API Funktionen nicht Bestandteil der eigentlichen Softwareapplikation sind, sondern von der Softwareapplikation lediglich als Betriebssystemfunktionen aufgerufen werden. Entsprechend können Betriebssystem-API Funktionen auch nicht vom Obfuskator obfuskiert werden. Deshalb kann das für die Obfuskierung der Softwareapplikation zur Verfügung stehende Kontingent an Prozessortakten, das einschließlich der nicht obfuskierbaren Betriebssystem-API Funktionen ermittelt wurde, auf die tatsächlich obfuskierbaren Funktionen der Softwareapplikation konzentriert werden, also auf alle solche Funktionen, die keine Betriebssystem-API Funktionen sind.
-
Vorzugsweise wird jede identifizierte Funktion einer Ereignisbehandlungsroutine oder für jede identifizierte Funktion, die keine Betriebssystem-API Funktion ist, ein funktionsspezifischer Obfuskierungsparameter bestimmt, um das unterschiedliche Laufzeitverhalten von Routinen und Funktionen einer Softwareapplikation bei deren Obfuskierung zu berücksichtigen. Dieser funktionsspezifische Obfuskierungsparameter wird vorzugsweise bestimmt als die maximale Anzahl an Prozessortakten, die auf die betreffende Funktion entfallen und wird berechnet als das Produkt der zur Ausführung der betreffenden Funktion erforderlichen Anzahl an Prozessortakten und dem Parameter, der die maximal zulässige Obfuskierung für die Ereignisbehandlungsroutine angibt.
-
Dem Obfuskator kann auf diese Weise das für die Obfuskierung jeder einzelnen Funktion zur Verfügung stehende Kontingent an Prozessortakten mitgeteilt werden. Der Obfuskator braucht daher nicht selbständig zu ermitteln, wie und auf welche betroffenen Funktionen ein für eine Ereignisbehandlungsroutine insgesamt zur Verfügung stehendes Kontingent an Prozessortakten aufzuteilen ist. Auf diese Weise kann eine mögliche Fehlerquelle des inadäquaten Obfuskierens vermieden werden und/ oder den Einsatz einer größeren Anzahl von Obfuskatoren ermöglichen, insbesondere solcher, die funktionsspezifisch arbeiten und eine funktionsübergreifende Analyse nicht adäquat vornehmen können.
-
Die Softwareapplikation ist vorzugsweise eine Softwareapplikation für mobile Endgeräte bzw. mobile Telekommunikationsendgeräte, insbesondere für mobile Endgeräte, die mit dem Betriebssystem Android oder iOS ausgestattet sind. Vorzugsweise wird eine erfindungsgemäß obfuskierte Softwareapplikation an den Endkunden ausgeliefert, indem sie auf einer Softwaredistributionsplattform bereitgestellt wird, bevorzugt dem Google Play Store oder den Apple App Store.
-
Weitere Aspekte der Erfindung betreffen eine Softwareapplikation, die gemäß dem erfindungsgemäßen Verfahren generiert wurde und eine Computervorrichtung, vorzugsweise ein mobiles Endgerät, auf dem eine erfindungsgemäß generierte Softwareapplikation gespeichert vorliegt. Schließlich betrifft ein weiterer Aspekt der Erfindung eine Computervorrichtung mit darauf gespeichertem Programmcode, welcher durch Ausführen von einem Prozessor der Computervorrichtung diese veranlasst, das erfindungsgemäße Verfahren auszuführen.
-
Die beschriebenen Aspekte der Erfindung ermöglichen eine weniger aufwändige und weniger fehleranfällige Obfuskierung einer Softwareapplikation. Zudem gewährleistet die Erfindung ein hohes Maß an Obfuskierung und somit Sicherheit, während dadurch zeitkritische Benutzerinteraktionen nicht beeinträchtigt werden.
-
Weitere Merkmale und Vorteile der Erfindung ergeben sich aus der folgenden Beschreibung erfindungsgemäßer Ausführungsbeispiele sowie weiterer Ausführungsalternativen im Zusammenhang mit den folgenden Zeichnungen, die zeigen:
- 1 ein Schema eines erfindungsgemäßen Verfahrens zum Generieren einer obfuskierten Softwareapplikation;
- 2 ein Schema des Identifizierens von aufgerufenen Funktionen für eine beispielhafte Ereignisbehandlungsroutine; und
- 3 beispielhaft ermittelte Anzahlen an Prozessortakten, die zur Ausführung der identifizierten Funktionen erforderlich sind.
-
1 zeigt ein Flussdiagram eines Verfahrens 100 zum Generieren einer obfuskierten Softwareapplikation gemäß einer Ausführungsform der Erfindung. Das Verfahren 100 ist als computerimplementiertes Verfahren ausgebildet, das von einer Computervorrichtung ausgeführt wird, wie zum Beispiel einem Arbeitsplatzrechner, einem Server oder dergleichen. Die Computervorrichtung ist hierzu mit einem oder mehreren Prozessoren ausgestattet, sowie mit einem Speicher, in dem ein Programmcode gespeichert ist, welcher, das Verfahren 100 realisiert, wenn er von einen der Prozessoren ausgeführt wird.
-
Das Verfahren 100 beginnt im Schritt 102 mit dem Bereitstellen des Quellcodes für die Softwareapplikation, zum Beispiel in Form eines Java Quellcodes einer Softwareapplikation, die für mobile Endgeräte bestimmt ist, welche mittels des Android Betriebssystems betrieben werden. Der Quellcode der Softwareapplikation kann je nach eingesetzter Zielplattform aber auch in anderen Programmiersprachen vorliegen, beispielsweise in C, C++, Objective-C, C# oder Swift.
-
Im Schritt 120 wird der Quellcode analysiert, um darin enthaltene Ereignisbehandlungsroutinen - auch als Event Handler bezeichnet - zu identifizieren. So können beispielsweise alle von dem Quellcode definierten Klassen geparst und nach vorhandenen Event Handlern bzw. Ereignisbehandlungsroutinen durchsucht werden. Alle so aufgefundenen Ereignisbehandlungsroutinen werden dann in einer Liste der identifizierten Ereignisbehandlungsroutinen verzeichnet.
-
So kann zum Beispiel im Quellcode eine Ereignisbehandlungsroutine namens Window. onClick (...) identifiziert werden, welche aufgerufen wird, wenn der Benutzer ein von der Softwareapplikation auf einem Bildschirm angezeigtes Fenster anklickt, oder eine Ereignisbehandlungsroutine Animation. onNextFrame (...), die aufgerufen wird, wenn das Folgebild einer Animation auf dem Bildschirm angezeigt werden soll, oder eine Ereignisbehandlungsroutine Text Form. onKey (...), die aufgerufen wird, wenn der Benutzer ein Zeichen eingegeben hat.
-
Für jede derartige Ereignisbehandlungsroutine ist bekannt, welchen Zweck diese erfüllt und unter welchen Umständen sie aufgerufen wird. Die Ereignisbehandlungsroutine Window. onClick wird zum Beispiel aufgerufen in Reaktion auf eine Benutzerinteraktion mit der graphischen Benutzeroberfläche der Softwareapplikation. Aus nutzerpsychologischen Untersuchungen ist bekannt, dass eine solche Reaktion innerhalb von 0,2 Sekunden erfolgen muss, damit ein Benutzer der Softwareapplikation keine störende Verzögerung wahrnimmt. Dieser Umstand wird in Schritt 122 berücksichtigt, indem für jede Ereignisbehandlungsroutine basierend auf Untersuchungen oder anderweitigen Quellen eine jeweils einzuhaltende maximale Ausführungszeit festgelegt wird. So kann beispielsweise für die Ereignisbehandlungsroutine Window. onClick eine einzuhaltende maximale Ausführungszeit von 20 ms festgelegt werden und für die Routinen Animation. onNextFrame und TextForm. onKey eine einzuhaltende maximale Ausführungszeit von 10 ms.
-
Die tatsächliche Ausführungszeit einer Ereignisbehandlungsroutine wird jedoch nicht nur vom Code der Routine selbst bestimmt, sondern hängt auch wesentlich von den Funktionen ab, die von dieser Routine aufgerufen werden. Im Schritt 124 wird daher für jede Routine untersucht, welche Funktionen sie im Laufe ihrer Ausführung aufruft. So ruft beispielsweise die in 2 illustrierte Ereignisbehandlungsroutine Window. onClick die Funktionen playSound (...), displayBlink und retrieveDat (...) auf, welche wiederum weitere Funktionen aufrufen. Anhand der in 2 illustrierten beispielhaften Struktur der Funktionsaufrufe wird demnach weiter identifiziert, dass die Funktion displayBlink (...) keine weiteren Funktionen aufruft, während die Funktion playSound die Funktionen checkVolume und retrieveSound aufruft und letztere schließlich die Betriebssystem-API Funktion Sound.play (...).
-
Diese rekursive Identifikation von aufgerufenen Funktionen wird so lange wiederholt, bis eine Funktion keine weiteren Funktionsaufrufe mehr umfasst, wie im Beispiel der 2 die Funktionen displayBlink (...) und checkVolume oder bis ein Zyklus auftritt, wie im Beispiel der 2 die wechselseitigen Aufrufe der Funktionen retrieveData und processData Aufrufe von Funktionen über die Betriebssystem-API (Anwendungsprogrammierschnittstelle) werden hierbei zwar erfasst, nicht aber rekursiv weiterverfolgt, wie im Beispiel der 2 die Funktionen Sound, play (...) und Sound, load (...). Betriebssystem-API Funktionen verzweigen auf Routinen des Betriebssystems, die zum Zwecke Obfuskierung einer Softwareapplikation nicht weiter betrachtet werden. Auf diese Weise wird ein gerichteter Graph von identifizierten, aufgerufenen Funktionen gebildet, so wie in 2 gezeigt.
-
In einem nächsten Schritt 126 wird dann für jede im Schritt 124 identifizierte Funktion die zur Ausführung erforderlichen Anzahl an Prozessortakten ermittelt. Zu diesem Zweck kann der Quellcode ohne Obfuskierung in den Maschinencode der betreffenden Zielarchitektur übersetzt werden. Der Abschnitt des Maschinencodes, der der betreffenden Funktion entspricht, kann dann hinsichtlich der verwendeten Maschinencodebefehle analysiert werden, um basierend auf der für jeden Maschinencodebefehl bekannten, von der Zielarchitektur abhängigen Anzahl an erforderlichen Prozessortakten die Gesamtzahl an Prozessortakten zu berechnen, welche zur Ausführung der jeweiligen Funktion benötigt werden.
-
Für Programmiersprachen und/ oder Zielarchitekturen, welche Zwischencode verwenden, zum einen Bytecode, kann alternativ der Zwischencode hinsichtlich der verwendeten Zwischencodebefehle und deren zur Ausführung benötigten Prozessortakte analysiert werden. Dies betrifft insbesondere Zwischencode in Form eines Java-Bytecode, der im Fall von Java-Applikationen für mobile Endgeräte mit einem Android Betriebssystem eingesetzt wird. Da der Zwischencode, insbesondere im Fall von Java Bytecode, jedoch üblicherweise einer weiteren Kompilierung bzw. Übersetzung in Maschinencode unterzogen wird, sei es durch eine Ahead-of-Time-Kompilierung oder eine Just-in-Time-Kompilierung, bevor die Softwareapplikation von einem Prozessor einer Computervorrichtung ausgeführt wird, wird jedem Zwischencodebefehl eine beispielsweise empirisch ermittelte Anzahl von Prozessortakten zugeordnet, welche der Zwischencodebefehl benötigen würde, wenn er als Maschinencode übersetzt zur Ausführung käme. So können etwa für die nachstehende beispielhafte Java-Bytecode-Sequenz die genannten Prozessortakte für die einzelnen Befehle angenommen werden:
18: | irem | 4 Prozessortakte |
19: | ifne 25 | 8 Prozessortakte |
22: | goto 38 | 4 Prozessortakte |
25: | iinc 2,1 | 6 Prozessortakte |
28: | goto 11 | 4 Prozessortakte |
-
Für Betriebssystem-API-Funktionen ist die Gesamtzahl der erforderlichen Prozessortakte bekannt, da diese fest im Betriebssystem verankert und festgelegt sind. Eine gesonderte Analyse und Bestimmung der erforderlichen Prozessortakte zur Ausführung von Betriebssystem-API-Funktionen ist somit nicht erforderlich.
-
Auf diese Weise wird für jede Funktion die Anzahl der zur Ausführung erforderlichen Prozessortakte ermittelt. So können etwa für die in 2 gezeigten Funktionen playSound (...), displayBlink (...) und processData (...) 800 Takte, 700 Takte und 5.000 Takte ermittelt werden, wie in 3 angegeben. Es sei angemerkt, dass natürlich nicht nur die aufgerufenen Funktionen sondern auch der Code der eigentlichen Ereignisbehandlungsroutine, in 2 die Routine window. onClick (...), untersucht und deren erforderliche Anzahl an Prozessortakten - ohne Berücksichtigung der separat untersuchten Funktionsaufrufe - ermittelt wird; etwa 1.800 Takte für die Routine window. onClick (...), wie in 3 angegeben.
-
Basierend darauf wird in Schritt 126 die Gesamtzahl an Prozessortakten ermittelt, die für die Ausführung der gesamten Ereignisbehandlungsroutine erforderlich ist. Diese entspricht der Summe an Prozessortakten, die zur Ausführung der Routine und aller aufgerufenen Funktionen erforderlich ist. Für die Routine window. onClick (...) ergibt sich anhand der 3 beispielhaft eine Gesamtsumme von 20.500 Prozessortakten (= 1.800 + 800 + 4.000 + 500 + 6.000 +1.200 + 700 + 500 + 5.000) für deren Ausführung auf dem betreffenden Prozessor.
-
Basierend auf der ermittelten Gesamtzahl der Prozessortakte wird dann im Schritt 128 die tatsächliche Ausführungszeit der Ereignisbehandlungsroutine errechnet. Hierzu wird als Referenzplattform vorzugsweise das Modell der Zielplattform mit dem langsamsten Prozessor herangezogen, auf welchem die obfuskierte Softwareapplikation noch flüssig, das heißt ohne durch einen Benutzer wahrnehmbare Verzögerung, ausgeführt werden kann.
-
Wird beispielsweise eine Referenzplattform mit einem Prozessortakt von 1 GHz herangezogen, so wird für die Ereignisbehandlungsroutine Window. onClick (...) eine tatsächliche Ausführungszeit 20,5 Pikosekunden (ps) berechnet:
-
Im Schritt
130 wird anschließend ein Parameter der maximal zulässigen Obfuskierung für die betreffende Ereignisbehandlungsroutine errechnet, indem die einzuhaltende maximal zulässige Ausführungszeit durch die tatsächliche Ausführungszeit geteilt wird. Im Beispiel der
3 ergibt sich für die Ereignisbehandlungsroutine Window. onClick (...) beispielsweise der Parameterwert von
-
Dieser Parameter repräsentiert die maximal zulässige Obfuskierung der Routine Window. onClick (...) in Form eines routine- und plattformabhängigen Faktors, um den die Ausführungszeit der Routine bei der Obfuskierung verlangsamt werden kann, ohne dass dies für den Benutzer wahrnehmbar oder zumindest störend wäre.
-
Dieser Parameter wird für jede Ereignisbehandlungsroutine separat bestimmt und dem Obfuskator bereitgestellt, der diesen als Obergrenze für die Obfuskierung der betreffenden Routine in Schritt 104 verwendet.
-
Alternativ bzw. ergänzend ist es auch möglich, ausgehend von dem in Schritt 132 bestimmten Parameter der maximal zulässigen Obfuskierung funktionsspezifische Obfuskierungsparameter für jede von der betreffenden Ereignisbehandlungsroutine direkt oder indirekt aufgerufenen Funktion zu bestimmen. Der funktionsspezifische Obfuskierungsparameter kann dabei eine Anzahl an Prozessortakten angeben, die nach der Obfuskierung maximal für diese Funktion zur Verfügung stehen. Auf diese Weise ergibt sich für die Funktion playSound (...) beispielsweise ein Obfuskierungsparameter von 800 Takten * 976 = ca. 780.000 Takten.
-
Bei dem in 3 gezeigten Beispiel wird jedoch bei der Bestimmung des Parameters der maximal zulässigen Obfuskierung und der Bestimmung funktionsspezifischer Obfuskierungsparameter bisher nicht berücksichtigt, dass es sich bei den Funktionen Sound.play (...) und Sound.load (...) um Betriebssystem-API Funktionen handelt, welche vom Betriebssystem bereitgestellt und als solche nicht Bestandteil der eigentlichen Softwareapplikation sind. Solche Funktionen können von dem Obfuskator nicht obfuskiert werden, denn der Zugriff auf den Programmcode des Betriebssystems ist weder gewünscht noch möglich.
-
Für die Ereignisbehandlungsroutine Window. onClick (...) findet eine Obfuskierung daher nur für die Funktionen Window. onClick (...) selbst, sowie die aufgerufenen Nicht-API-Funktionen playSound (...), checkVolume (...), displayBlink (...), retrieveData (...) und processData (...) statt, welche zusammen einen Anteil von 10.500 Takten an den gesamten 20.500 Takten der tatsächlichen Ausführungszeit der Routine ausmachen.
-
Zum Zwecke einer weitergehenden Obfuskierung wird daher das für die Obfuskierung zur Verfügung stehende Kontingent an Prozessortakten, die bei gleichmäßiger Verteilung auf alle aufgerufenen Funktionen auch auf die Betriebssystem-API Funktionen entfallen und somit nicht zur Obfuskierung ausgenutzt würden, nur auf die tatsächlich obfuskierbaren Funktionen der Softwareapplikation umgelegt. Dazu wird beispielsweise der Parameter der maximal zulässigen Obfuskierung mit einem geeigneten Korrekturfaktor multipliziert. Dieser Korrekturfaktor ist vorzugsweise der Quotient aus der Gesamtzahl der zur Ausführung der Ereignisbehandlungsroutine erforderlichen Prozessortakte und der Summe der zur Ausführung nur der identifizierten nicht-Betriebssystem-API Funktion der Softwareapplikation, also derjenigen identifizierten Funktionen, die keine Betriebssystem-API Funktionen sind. Im Beispiel der in 3 gezeigten Ereignisbehandlungsroutine ist dieser Korrekturfaktor etwa 1,95, denn 10.500 der insgesamt 20.500 Takte entfallen auf originäre Funktionen der Routine, die keine Betriebssystem-API Funktionen sind.
-
Alternative oder ergänzende Varianten der Umverteilung eines ungenutzten Kontingents an Prozessortakten sind auch möglich, wie beispielsweise die Zuteilung derjenigen nach der Obfuskierung maximal zulässigen Prozessortakte, die als funktionsspezifische Obfuskierungsparameter auf die Betriebssystem-API Funktionen entfallen würden, auf eine oder mehrere Betriebssystem-API Funktionen.
-
Der Parameter der maximal zulässigen Obfuskierung und/ oder die funktionsspezifischen Obfuskierungsparameter werden dabei dadurch bereitgestellt, dass jede von der Ereignisbehandlungsroutine direkt oder indirekt aufgerufene Funktion im Quellcode mit einer vom Obfuskator auswertbaren Annotation versehen wird.
-
Anschließend wird der Quellcode in Schritt 104 mit Hilfe des Obfuskators obfuskiert und in Schritt 106 mit einem geeigneten Compiler kompiliert, um einen ausführbaren Programmcode zu erhalten. Je nach verwendeter Programmiersprache und abhängig von der konkreten Zielplattform kann es sich bei dem kompilieren Programmcode um einen Maschinencode, auch als nativer Code bezeichnet, oder um einen Zwischencode handeln, wie einem Bytecode bzw. Java Bytecode. In dem Fall, dass in Schritt 106 ein Zwischencode erzeugt wird, kann dieser optional mit einem geeigneten weiteren Compiler in einen von der Zielplattform direkt ausführbaren Maschinencode kompiliert werden. Ein solcher geeigneter Compiler ist beispielsweise einem Ahead-of-Time Compiler, wie er für Java Bytecode und auf Android-Plattformen verfügbar ist.
-
Die so erhaltene ausführbare, obfuskierte Softwareapplikation wird dann in Schritt 110 getestet, um das korrekte Arbeiten der Softwareapplikation und die Einhaltung der Anforderungen an das Laufzeitverhalten zu prüfen. Nach erfolgreichem Test wird die Softwareapplikation in Schritt 112 an die Benutzer bzw. Kunden ausgeliefert, indem sie beispielsweise in einer Softwaredistributionsplattform wie dem Google Play Store oder dem Apple App Store eingestellt wird, damit mobile Endgeräte die Softwareapplikation von dort laden und installieren können.
-
Abweichend von bzw. ergänzend zu den im Zusammenhang mit den Figuren beschriebenen Ausführungsformen sind vielfältige Abwandlungen und Ausgestaltungen möglich. So ist zum Beispiel die Reihenfolge der Schritte gemäß 1 veränderbar, ohne dass der erfindungsgemäße Zweck entfallen würde. Insbesondere können die Schritte 104 (Obfuskieren des Quellcodes) und 106 (Kompilieren der obfuskierten Quellcodes) auch vertauscht werden, so dass zunächst der Quellcode kompiliert wird und erst anschließend ein Ofuskator den kompilierten Code, zum Beispiel in Form eines Java Bytecode, zu obfuskieren. Ebenso können die Schritte des Obfuskierens und Kompilierens parallel, überlappend oder integriert ausgeführt werden, indem zum Beispiel ein obfuskierender Compiler verwendet wird, der die Funktion des Obfuskators und eines herkömmlichen Compilers in sich vereint.
-
ZITATE ENTHALTEN IN DER BESCHREIBUNG
-
Diese Liste der vom Anmelder aufgeführten Dokumente wurde automatisiert erzeugt und ist ausschließlich zur besseren Information des Lesers aufgenommen. Die Liste ist nicht Bestandteil der deutschen Patent- bzw. Gebrauchsmusteranmeldung. Das DPMA übernimmt keinerlei Haftung für etwaige Fehler oder Auslassungen.
-
Zitierte Patentliteratur
-
- DE 102014019090 A1 [0003]