
Ich gehöre zu den Menschen, die mit Beginn des Herbstes versuchen, weniger Zeit auf der Straße zu verbringen. In Moskau ist das nicht schwierig: Sie beschränken sich auf den Weg von zu Hause ins Büro und zurück. Feuchtes Wetter kann jedoch zu Unannehmlichkeiten im Raum führen, insbesondere wenn sich Ihr Arbeitsplatz wie meiner am Fenster befindet und jeder zweite Kollege, der sich über Verstopfung beschwert, darum bittet, das Büro zu lüften. Um nicht in die Milz zu fallen, habe ich diesen Herbst die Garderobe aktualisiert.
Als ich über das Schicksal unnötiger Dinge nachdachte, fragte ich mich, was ich damit anfangen sollte: wegwerfen, in Lumpen schneiden, meinem jüngeren Bruder geben, um es zu tragen? Aber zum einen war keine dieser Methoden geeignet: Es waren Lederstiefel 44 von anständiger Größe, aber sie störten mich in Ordnung. Ich beschloss, sie auf Avito zu verkaufen. Ich habe Fotos hochgeladen, einen falschen Namen angegeben (Informationssicherheit ist dieselbe), meine Stiefel ausgezogen, ein paar andere Dinge und bin schlafen gegangen. Woher wusste ich, dass dies zu einer langen Analyse der Anwendung auf versteckte Bedrohungen führen würde?

Angenehme Überraschung
Am Tag nach ein paar zweifelhaften Anrufen erhielt ich eine interessante SMS mit folgendem Inhalt:

Nach ein paar Tagen erhielt ich eine weitere ähnliche Nachricht:

Überrascht, dass jemand im Internet irgendwie Geld an mich überweisen konnte (anscheinend bin ich der einzige, der alt ist - ich benutze immer noch Sparbücher), klickte ich auf den Link in SMS.
Danach wurde mir angeboten, eine Android-Anwendung (apk-Datei) herunterzuladen. Beim Herunterladen der Datei sah ich Folgendes:

Es ist glaubwürdig! Ich wollte unbedingt alles schnell installieren und beenden.
Aber hier, wie immer, erlaubte mir das nervige Android-Betriebssystem aus irgendeinem Grund nicht, die Datei auszuführen. "Gib mir das Geld schon!" Ich war empört. Ich musste zu den Einstellungen gehen und eine Option "Unbekannte Quellen" aktivieren. Ist das Telefon 2018 wirklich so dumm? Mein Handy ist übrigens Xiaomi Remdi mit Andoid 6.0.1 (Hinweis für Technikfreaks).


Es folgte eine Reihe seltsamer Ereignisse. Das Telefon meldete weiterhin unzuverlässige Quellen. Aber Avito ist eine
zuverlässige Quelle ! Ich musste es googeln, herausfinden, wie ich das umgehen kann, und es dann in den Einstellungen ausschalten. Bald erschien ein bestimmtes Antivirenprogramm, das ich nicht installiert hatte.




Schließlich habe ich das begehrte Standardinstallationsfenster gesehen -
es macht heutzutage keinen Sinn, sich die Berechtigungen anzusehen , jetzt startet sogar ein Notebook erst, wenn Sie ihm vollen Zugriff auf das Telefon gewähren. Freudiger Moment nach Abschluss der Anwendungsinstallation und START! Ich freute mich auf das versprochene Geld. Darüber hinaus forderte die Anwendung Administratorrechte an, denen ich freudig zustimmte. Leider verhielt sich die Anwendung seltsam und wollte nicht bezahlen, und bald verschwand sie vollständig aus der Liste der Anwendungen auf dem allgemeinen Bildschirm.





Altruismus
Also, wozu sind wir gekommen:
- Die Installation dauerte 20 Minuten.
- Ich habe das Geld nicht erhalten.
Ich dachte, das Problem sei ein Codefehler, wie es bei Programmierern häufig der Fall ist. Ich habe mich entschlossen, festzustellen, welche Fehler auftreten, wenn die Anwendung auf meinem Telefon ausgeführt wird, und dem Entwickler einen Bericht darüber zu senden.
SpoilerJetzt sind so wenige desinteressierte Menschen übrig, einer von ihnen bin ich.
Es ist klar, dass diese Art von Anwendung funktionieren sollte, wenn das Internet verbunden ist. Daher habe ich zunächst versucht, den Datenverkehr zwischen dem Telefon und dem Anwendungsserver zu analysieren.
Technisches Handbuch zur Proxy-KonfigurationSie können den Internetverkehr jederzeit auf dem Weg vom Telefon zum Server abhören, sei es ein Heimrouter, ein lokaler Internetanbieter, ein Internet-Backbone oder ein Anwendungsserver.
Die Probleme:
- Der Zugang zu diesem Gerät ist erforderlich.
- Es ist erforderlich, den Datenverkehr der gewünschten Anwendung vom Rest zu trennen.
- Bei der Verschlüsselung (und 2018 ist bereits alles verschlüsselt) ist die Kenntnis des Schlüssels erforderlich.
Ich entschied mich für eine klassischere Vorgehensweise und konfigurierte Proxys auf dem Telefon mit einem Proxyserver auf meinem eigenen Laptop. Um das Verschlüsselungsproblem zu verringern, habe ich beschlossen, mein Zertifikat zu importieren, und keine anderen Anwendungen gestartet, um den Anwendungsverkehr zu trennen.
Ich habe
Burp Suite als Proxy-Server-
Programm gewählt . Ich habe einen Proxyserver eingerichtet und ein Zertifikat auf mein Telefon exportiert.




Nach dem Einrichten einer speziellen Software konnte ich sehen, welche Anforderungen die Anwendung an den Server sendet:

Wie Sie sehen, werden die Daten nicht gesendet (der unbekannte Hostwert wird in der IP-Spalte angegeben). Darüber hinaus können sie aufgrund der zusätzlichen Verschlüsselung auf Anwendungsebene nicht analysiert werden. Aus Versehen konnte das Telefon die IP-Adresse des Servers und seiner Subdomains
https: //*.sky-sync.pw nicht anhand seines Domainnamens ermitteln.
Dies kann nur folgende Optionen bedeuten:
- Der Domainname existiert nicht mehr
- Es wurde vom Eigentümer selbst blockiert.
- Er wurde vom Registrar wegen der Beschwerde blockiert.
- Problem mit dem DNS-Server
- Der DNS-Server kennt die Adresse nicht, da der Entwickler in der Produktion die lokale DNS-Adresse eingeführt hat.
- Der DNS-Server hat diese Anfrage speziell blockiert, was im Zeitalter der Internet-Zensur nicht überraschend ist.
Um die Annahme eines Problems mit dem DNS-Server zu überprüfen, habe ich versucht, Anforderungen von verschiedenen großen DNS-Servern zu stellen: Google, Yandex, OpenDNS (normalerweise wird lokales DNS zensiert):

Es ist zu sehen, dass keiner von ihnen etwas über diesen Namen weiß. Als nächstes habe ich mir whois Informationen zur Domainregistrierung angesehen:

Merkwürdig: Die Domain ist registriert, dh höchstwahrscheinlich nicht lokal. Da sich die Domain jedoch nicht auflösen lässt, wurde sie möglicherweise vom Registrar wegen Missbrauchs blockiert. Aber wofür? Was hat er falsch gemacht?
Um herauszufinden, was diese Anwendung überhaupt ist und wie ich mein Geld nehmen kann, habe ich mich für die
Magie des Reverse Engineering entschieden.
Abgrund
Wenn Sie ein Humanist sind und bis zu diesem Ort gelesen haben, dann ist dies gut - für die Entwicklung des folgenden sind Sie einer
posthumen Auszeichnung würdig.
Toolkit
Um herauszufinden, was sich unter der Haube der Anwendung befindet, müssen wir spezielle Tools herunterladen. Sie können sie einzeln herunterladen:
- Apk behälter auspacken
- Klassiker - ApkTool .
- Sie können es mit einem herkömmlichen Archivierer entpacken, aber dann sind alle binären Ressourcen, einschließlich Anwendungen und der Manifest-Datei, nicht lesbar.
- Smali Code Dekompiler
- Der Standard ist Dex2Jar , aber lernen Sie, dass dieses Programm oft schief funktioniert.
- Sie müssen die Angelegenheit sehr sorgfältig angehen, da der Dekompiler vom Dekompiler unterschiedlich ist. Wir werden dies später betrachten.
- Als Programm zum Anzeigen von dekompiliertem Code würde ich jd-gui empfehlen
Oder Sie können das normalerweise kostenpflichtige Produkt verwenden, bei dem alles auf einmal vorhanden ist. Ich bevorzuge
JebDecompiler : Er kann einfach eine apk-Anwendung an seine Eingabe senden und ordnet alles ordentlich in Registerkarten an. Außerdem ist es praktisch, zwischen smali und dekompiliertem Java-Code darin zu wechseln.
Separat möchte ich beachten:
- Wenn native Bibliotheken vorhanden wären (der Ordner / libs in der Anwendungsstruktur), wäre ein Disassembler erforderlich.
- Möglicherweise benötigen Sie eine Reihe von Dienstprogrammen für die Arbeit mit Smali-Code (Dex-to-Smali, Smali-to-Dex).
- Syntaxhervorhebung in Notepad ++, um die Augen nicht zu brechen.
Nur alte Leute ziehen in die Schlacht
Rückblick
Wenn Sie den dekompilierten Code öffnen, wird sofort klar, dass er verschleiert ist.

Wie verstehe ich das?
- Vom Menschen lesbare Klassennamen
isqpwcmx.isfdztgb.adscjobz.nxscomkr.jypbdxnt.utagwpym.wprtdznb.swldgrhm.yrbjpktq.wukovicq;
- Nicht erreichbarer Code
if(0 != 0) {</li> String v1 = "flnwznvh";</li> if(v1.length() != 661 && v1.charAt(0) == 104) {</li> v1.length();</li> }
- String-Verschlüsselung
vcgrnfjx.execSQL(nvhdzjfo.xipswfqb(new String[]{"f741f04a4991fc2f0a0029f610bbd1c250dfe115fb7770b892f75d8718b822d273251013991b4407e224fa3f9d4e92f6","378f40211b6e32a5406cd97e85bcf9ad","6378a459b1c20edf", "gexnfwok", "meazfhdp", "bsmotaxn"})
Es ist unwahrscheinlich, dass der Programmierer so verrückt war, den Code zunächst zu entwickeln. Höchstwahrscheinlich benutzte er einen der öffentlich zugänglichen Verschleierer. Dieser Schritt ist durchaus üblich, um die Code-Analyse zu komplizieren, um beispielsweise das geistige Eigentum zu schützen, aber welche Art von „Wendung“ für den Forscher.
Achten wir auf die Hauptverschlüsselungsfunktion:

Die Verschlüsselungsfunktion selbst akzeptiert 3 Eingabezeilen (wenn mehr, macht der Rest keinen Sinn):
- Chiffretext
- der Schlüssel
- Initialisierungsvektor für CBC - AES
Auf diese Funktion wird im Programm mindestens 213 Mal verwiesen:

Ich stelle fest, dass dies ein wichtiger Schlüssel für die normale Code-Analyse ist. Als nächstes müssen
Sie denken, dass wir die folgenden Möglichkeiten haben, das Programm zu analysieren:
- Stellen Sie die Logik der Funktion wieder her, sammeln Sie alle Aufrufe in der statischen Analyse und entschlüsseln Sie die Zeilen. Es mag schwierig und lang sein, aber es wird ein 100% iges Ergebnis liefern.
- Nehmen Sie Änderungen am Smali-Code der Anwendung vor, kompilieren Sie erneut, führen Sie die Anwendung aus und fangen Sie entschlüsselte Zeilen in den Protokollen ab. Dies ist einfach, aber das Verhalten der Anwendung bei einem bestimmten Start ist nicht bekannt, und Sie sehen möglicherweise nicht das gesamte Bild (es werden nicht alle Funktionen aufgerufen). Darüber hinaus können Probleme bei der Selbstprüfung durch Anwendung des Zertifikats und (oder) der Integrität auftreten.
- Wenn es schwierig ist, die Logik der Funktion wiederherzustellen, können Sie alle Funktionsaufrufe sammeln und diese Funktionen mit den erforderlichen Parametern direkt in der Dynamik selbst abrufen (z. B. mithilfe der Frida- Software).
Wir werden Methode Nummer 1 als die strengste zuverlässige wählen.
Deobfuscation
Machen Sie sofort eine Reservierung, Deobfuscation ist oft ein langer und langwieriger Prozess, daher müssen Sie Ihren Zeitrahmen richtig einschätzen. Für unsere Analyse reicht es aus, alle Zeilen zumindest auf irgendeine Weise zu entschlüsseln und dies in kürzester Zeit zu tun, selbst auf Krückenart, als einen Monat lang herumzuspielen, um eine vage ideale Option zu erreichen.
Eine qualitativ hochwertige Deobfuscation ist bei vollständigem Reverse Engineering sinnvoll. Beispielsweise müssen Diebe des geistigen Eigentums dies tun, wenn sie versuchen, die Lösung eines Mitbewerbers zu kopieren, oder wenn Sie häufig Programme analysieren müssen, die von einem Obfuscator verarbeitet werden. Dies ist jedoch nicht unser Fall.
Quellcode nach JEB Decompiler v.1.4 Decompiler
Spoiler public static String podxiwkt(String[] args) { int v6; int v4; byte[] v2; Cipher v1; String v10 = args[0]; String v7 = args[1]; String v0 = args[2]; if(v10 == null) { goto label_9; } if(v10.length() != 0) { goto label_11; } goto label_9; label_11: IvParameterSpec v5 = new IvParameterSpec(v0.getBytes()); try { v1 = Cipher.getInstance("AES/CBC/NoPadding"); goto label_15; } catch(NoSuchPaddingException v3) { } catch(NoSuchAlgorithmException v3_1) { } String v11 = ""; goto label_10; label_15: SecretKeySpec v9 = new SecretKeySpec(v7.getBytes(), "AES"); int v11_1 = 2; try { v1.init(v11_1, ((Key)v9), ((AlgorithmParameterSpec)v5)); v2 = Base64.decode(v1.doFinal(bwdoclkr.xkvasepi(v10)), 0); if(v2.length <= 0) { goto label_48; } v4 = 0; v6 = v2.length - 1; label_29: if(v6 < 0) { goto label_38; } if(v2[v6] != 0) { goto label_33; } } catch(Exception v3_2) { goto label_51; } ++v4; label_33: --v6; goto label_29; label_38: if(v4 <= 0) { goto label_48; } try { byte[] v8 = new byte[v2.length - v4]; System.arraycopy(v2, 0, v8, 0, v2.length - v4); v2 = v8; } catch(Exception v3_2) { label_51: v11 = ""; goto label_10; } label_48: v11 = new String(v2); goto label_10; label_9: v11 = ""; label_10: return v11; } }
Decompiler HinweisDex2jar stürzt übrigens oft ab. In der folgenden Abbildung ist also zu sehen, dass dex2jar Version 2.0 nicht zurechtkommt und nur einen kleinen Code ausgegeben hat.

Die neueste Version, die aus den Quellen kompiliert wurde, erzeugte einen dekompilierten Code für diese Funktion, konnte jedoch nicht viele andere dekompilieren (das ist der Trick).


Fazit: Überlegen Sie sorgfältig, welchen Dekompiler Sie wählen - dies spart Ihnen viel Zeit und ist einfacher als die Analyse des Smali-Codes.
Wenn wir diesen Code jetzt in die IDE einfügen, funktioniert er aufgrund von Fehlern nicht.
Es ist wichtig zu beachten: Der Dekompiler muss keinen gültigen Code erstellen, der vom Entwickler geschrieben wurde. Er ist nur ein Lebensretter in der Analyse und macht Annahmen darüber, wie der Code geschrieben werden könnte. In den meisten Fällen ist die Aufgabe, den ursprünglichen Code vollständig wiederherzustellen, nach der Optimierung durch den Compiler nicht mehr trivial.
Beispiel für eine schlechte Dekompilierung:
if(v10 == null) { goto label_9; } if(v10.length() != 0) { goto label_11; } goto label_9; … label_9: v11 = ""; return v11;
Wir sehen, dass es schlecht und funktionsunfähig geworden ist. Wir schreiben um:
if ((v10 == null) || (v10.length() == 0)) { return ""; }
Jetzt ist es viel klarer, hier ist die übliche Eingabeprüfung. In diesem Fall brauchen wir:
- Ersetzen Sie alle "goto" durch andere Sprachkonstrukte, as "Springen" ist seit langem ein ungültiger Operator.
- Ersetzen Sie Android-Bibliotheksaufrufe durch Java-Bibliotheksaufrufe (wenn wir versuchen, Code in der Java-IDE auszuführen).
- Fügen Sie abhängige Klassen ein, auf die unser Code verweist.
- Überlegen Sie selbst, was los ist.
Als Ergebnis erhalten wir:
package com.company;
{ "b1acd584a6eae4ca6321b1f7cdf9ba9617112b4fb39e76c8def876346e3032fbd32b2d188a09715f27124c1bf9facfdc", "637904cd08aeb2d3f6a21b5c7e84f519", "8f4c796d5a3120eb", "zcmwgvdn", "mkngbsyr", "rwcdaieu"})); package com.company;
Dieser Code erfüllt erfolgreich. Nachdem seine Arbeit klar geworden ist, kann sie vereinfacht und vereinfacht werden, was zu der angeblich lakonischen Art führt, die vom Programmierer geschrieben wurde (es sei denn natürlich, seine Hände waren anfangs nicht krumm).
HinweisÜbrigens kann in diesem Fall die Entschlüsselung von Zeichenfolgen mithilfe einer Reihe von Online-Ressourcen demonstriert werden. Ein Beispiel für den Aufruf einer verschlüsselten Zeichenfolge in einem Programm:

Hier muss zuerst der Initialisierungsvektor in das Hex-Format konvertiert werden:

Ersetzen Sie alle Werte:

Und am Ende dekodieren Sie von base64:

Als Ergebnis erhalten wir die übliche Zeichenfolge, und der Aufruf erhält ein aussagekräftiges Aussehen.
Sie müssen also den gesamten Code durchgehen und alle verschlüsselten Zeichenfolgen sammeln, jetzt können wir sie unabhängig voneinander entschlüsseln. Der wichtige Punkt hierbei ist, dass wir in der Phase des „Änderns und Kommentierens des Codes“ sowohl auf der Smali-Ebene als auch auf der Java-Ebene (dekompilierte Smali) arbeiten können.
| Pluspunkte der Modifikation | Nachteile Mods |
Smali | Sie können Änderungen vornehmen, in dex neu kompilieren und mit neuen Zeilen dekompilieren | Es ist nicht immer einfach, mit dem Smali-Code zu arbeiten. Wenn die Änderung nicht korrekt ist, wird die Anwendung nicht kompiliert |
Java | Es ist oft viel einfacher, Daten aus übergeordneten Vorgängen zu extrahieren. | Die meisten Java-Code-Viewer können nicht bearbeiten. |
Ein weiteres Zeilenbeispiel
vcgrnfjx.execSQL(nvhdzjfo.xipswfqb(new String[]{"f741f04a4991fc2f0a0029f610bbd1c250dfe115fb7770b892f75d8718b822d273251013991b4407e224fa3f9d4e92f6","378f40211b6e32a5406cd97e85bcf9ad","6378a459b1c20edf", "gexnfwok", "meazfhdp", "bsmotaxn"})
Von hier aus ist es sehr einfach, Parameter mit einem regulären Ausdruck abzurufen, als einen regulären auf den folgenden Code zu schreiben:
Smali-Codebeispiel 1 00000280 new-instance v13, Ljava/lang/StringBuilder; 00000284 invoke-direct {v13}, Ljava/lang/StringBuilder;-><init>()V 0000028A const/4 v14, 0x6 0000028C new-array v14, v14, [Ljava/lang/String; 00000290 const/4 v15, 0x0 00000292 const-string v16, "f741f04a4991fc2f0a0029f610bbd1c250dfe115fb7770b892f75d8718b822d273251013991b4407e224fa3f9d4e92f6" 00000296 aput-object v16, v14, v15 0000029A const/4 v15, 0x1 0000029C const-string v16, "378f40211b6e32a5406cd97e85bcf9ad" 000002A0 aput-object v16, v14, v15 000002A4 const/4 v15, 0x2 000002A6 const-string v16, "6378a459b1c20edf" 000002AA aput-object v16, v14, v15 000002AE const/4 v15, 0x3 000002B0 const-string v16, "gexnfwok" 000002B4 aput-object v16, v14, v15 000002B8 const/4 v15, 0x4 000002BA const-string v16, "meazfhdp" 000002BE aput-object v16, v14, v15 000002C2 const/4 v15, 0x5 000002C4 const-string v16, "bsmotaxn" 000002C8 aput-object v16, v14, v15
Smali-Codebeispiel 2 0000008E new-array v0, v0, [Ljava/lang/String; 00000092 move-object/from16 v89, v0 00000096 const/16 v90, 0x0 0000009A const-string v91, "4500b5e2e2ad26b7545eb54d70ab360ae28c9d031e2afcc3f6a2b2ac488ea440" 0000009E aput-object v91, v89, v90 000000A2 const/16 v90, 0x1 000000A6 const-string v91, "da96f678922d4b07350b3a184ecc1f5e" 000000AA aput-object v91, v89, v90 000000AE const/16 v90, 0x2 000000B2 const-string v91, "0cf69e3d2745a1b8" 000000B6 aput-object v91, v89, v90 000000BA const/16 v90, 0x3 000000BE const-string v91, "jhiqsaoe" 000000C2 aput-object v91, v89, v90 000000C6 const/16 v90, 0x4 000000CA const-string v91, "khbqxurn" 000000CE aput-object v91, v89, v90
Smali-Codebeispiel 3 00000D3E new-array v0, v0, [Ljava/lang/String; 00000D42 move-object/16 v298, v0 00000D48 const/4 v0, 0x0 00000D4A move/16 v299, v0 00000D50 const-string v0, "b286945744e085f4d5c19916fd261481" 00000D54 move-object/16 v300, v0 00000D5A move-object/from16 v0, v300 00000D5E move-object/from16 v1, v298 00000D62 move/from16 v2, v299 00000D66 aput-object v0, v1, v2 00000D6A const/4 v0, 0x1 00000D6C move/16 v299, v0 00000D72 const-string v0, "df6883742b2911ac5ac7b4dee065390f" 00000D76 move-object/16 v300, v0 00000D7C move-object/from16 v0, v300 00000D80 move-object/from16 v1, v298 00000D84 move/from16 v2, v299 00000D88 aput-object v0, v1, v2 00000D8C const/4 v0, 0x2 00000D8E move/16 v299, v0 00000D94 const-string v0, "90a463ce2df17b58" 00000D98 move-object/16 v300, v0 00000D9E move-object/from16 v0, v300 00000DA2 move-object/from16 v1, v298 00000DA6 move/from16 v2, v299 00000DAA aput-object v0, v1, v2 00000DAE const/4 v0, 0x3 00000DB0 move/16 v299, v0 00000DB6 const-string v0, "cupyzsgq" 00000DBA move-object/16 v300, v0 00000DC0 move-object/from16 v0, v300 00000DC4 move-object/from16 v1, v298 00000DC8 move/from16 v2, v299 00000DCC aput-object v0, v1, v2
Wie wir sehen, ändern sich die internen Variablen, die Reihenfolge der Befehle variiert, die Anzahl der Argumente variiert ebenfalls. Außerdem wird im Programm die Entschlüsselungsfunktion nicht direkt, sondern über die Funktionen der Schicht aufgerufen. Versuchen Sie, selbst eine Regel zu schreiben, um nach diesem Konstrukt zu suchen, Fehler beim Erfassen von Zeichenfolgen aus anderen Funktionen zu vermeiden und dies alles schnell zu tun (
viel Glück ).
Fallenplan:
- Wir werden alle Werte aus dem dekompilierten Code extrahieren.
- Entschlüsseln.
- Ersetzen Sie den Chiffretext durch den offenen im Smali-Code. Wir ersetzen zum Beispiel anstelle des ersten Operators. (Es wäre professioneller, den gesamten Funktionsaufruf auszuschneiden und die zurückgegebene entschlüsselte Zeichenfolge zu belassen, aber andererseits besteht ein großes Risiko, dass das Programm beschädigt wird.)
- Sammeln wir den Smali-Code in einer Dex-Datei.
- Es wird zweckmäßig sein, weiter in den Code-Analysator zu schauen, in dem wir begonnen haben.
Wenn Sie den gesamten dekompilierten Code in einer einzigen Datei zusammenfassen, erhalten Sie ungefähr 20.000 Zeilen, was für die manuelle Analyse viel Zeit erfordert, was deutlich mehr kostet als die Stiefel, die ich zum Verkauf angeboten habe. Sammeln Sie zunächst alle Zeilen mit einem regulären Ausdruck.

Wir sehen 593 Spiele, plus ein Dutzend, die nicht unter diese Regel fallen,
die Familie hat ihre schwarzen Schafe . Ein Beispiel:

Sortieren, filtern, insgesamt 422 eindeutige Zeilen:

Wir durchlaufen die zuvor wiederhergestellte Entschlüsselungsfunktion. Ergebnis:

Ersetzen Sie den Chiffretext mit Python durch den offenen im Smali-Code:
import os words_replace=dict() words_replace["0018aacad3d146266317d8d8c51785fd"]="imei" words_replace["016d15e4d0a72667c61428e736a6f3b8"]="WakeLock" words_replace["032c534efb6c9990cd845a08c5a08b95"]="inbox" #… .. # smali- # def change(path): print("file="+path) file_handle = open(path, 'r') context_full = file_handle.read() file_handle.close() for i in words_replace: context_full=context_full.replace(i, words_replace[i]) #print (i+""+words_replace[i]) file_handle = open(path, 'w') context_full = file_handle.write(context_full) file_handle.close() # smali- for top, dirs, files in os.walk('C:\\work\\test'): for nm in files: path=os.path.join(top, nm) print (path) change(path)
Wir sammeln kleine Dateien in Dex:

Dies kann nun irgendwie analysiert werden (indem das erste Argument aus der gesamten Konstruktion gelesen wird):

Analyse
Wir haben also 20.000 mehr oder weniger lesbare Codezeilen. Wir müssen keine vollständige Analyse durchführen. Es ist notwendig, die Funktionalität als Ganzes zu verstehen. Hier ist in der Tat nur die Fähigkeit erforderlich, Java-Quellcode zu lesen. Gehen Sie durch den Code, sehen Sie sich Querverweise an, benennen Sie Variablen und Funktionen um.
Was ist der beste Weg, um eine Android-Anwendung zu analysieren, insbesondere eine große?
Option 1: Sie können aus der Manifest-Datei wechselnVersuchen Sie beispielsweise nacheinander von LAUNCHER, die gesamte Anrufkette abzuwickeln. Vergessen Sie übrigens nicht, dass es immer noch "Empfänger" und "Dienst" gibt, die die lineare Ausführung des Programms ändern können.

Vollständige Manifestdatei <?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="xfmpuwon.mtnbupnc.ihqdgjal.ndgmqawx.bjunzerq.cznfpnoq.fzevcuym.jmpdiqft"> <uses-permission android:name="xfmpuwon.mtnbupnc.ihqdgjal.ndgmqawx.bjunzerq.cznfpnoq.fzevcuym.jmpdiqft.permission.C2D_MESSAGE"/> <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/> <uses-permission android:name="android.permission.SEND_SMS"/> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/> <uses-permission android:name="android.permission.RECEIVE_SMS"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.QUICKBOOT_POWERON"/> <uses-permission android:name="android.permission.READ_SMS"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> <permission android:name="xfmpuwon.mtnbupnc.ihqdgjal.ndgmqawx.bjunzerq.cznfpnoq.fzevcuym.jmpdiqft.permission.C2D_MESSAGE" android:protectionLevel="signature"/> <application android:allowBackup="true" android:icon="@drawable/icon" android:label="@string/tgiwmpqy" android:noHistory="true"> <activity android:configChanges="orientation" android:excludeFromRecents="true" android:label="@string/tgiwmpqy" android:launchMode="singleTop" android:name="zemquyog.csrtmnak.xrkfygen.wkahrnjd.acnfunjh.rgipxbuf.lruiwxeg.blqndche.dcjihbou" android:screenOrientation="portrait"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activity android:configChanges="orientation" android:launchMode="singleTop" android:name="xbfrscou.hxrvwnoi.djvpcqri.enlnrfio.aoegxbiu.heywzmnb.znfnxcht.nazcxobq" android:screenOrientation="portrait"/> <activity android:configChanges="orientation" android:launchMode="singleTop" android:name="hcfkagds.timkagsd.oetvghzr.fcioynvl.psynofdj.slcghdjz.tapnwsdk.gzvwnban.htenafdb.qwebhzgy" android:noHistory="true" android:screenOrientation="portrait"/> <activity android:configChanges="orientation" android:excludeFromRecents="true" android:launchMode="singleTop" android:name="njfbwmre.voefarqx.ftuxvngl.wrmshxqj.zdenywgn.eiwyunlg.jysgkbam.yrijthab.vstqxpuo.iplamgxf" android:priority="2147483647" android:screenOrientation="portrait"/> <receiver android:name="gfbaznoc.asyoqtnm.kbetoqca.mqysobzu.gqwfibrv.dorxijuk.wgzkmiep.ywnnurzv.csfpqhrn" android:permission="android.permission.BIND_DEVICE_ADMIN"> <meta-data android:name="@string/pkzrlscm" android:resource="@xml/ynqukvnb"/> <intent-filter android:priority="2147483646"> <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/> </intent-filter> </receiver> <receiver android:name="ykwbodxc.gymjhibn.kgmdfqor.hbasvmfz.yegkmaif.ortzknvm.quplincn.cuxytvhs.fqonzuts.cyuoxgqi.znumwyct" android:permission="com.google.android.c2dm.permission.SEND"> <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE"/> <action android:name="com.google.android.c2dm.intent.REGISTRATION"/> <action android:name="com.google.android.c2dm.intent.UNREGISTRATION"/> <category android:name="xfmpuwon.mtnbupnc.ihqdgjal.ndgmqawx.bjunzerq.cznfpnoq.fzevcuym.jmpdiqft"/> </intent-filter> </receiver> <receiver android:enabled="true" android:exported="true" android:name="kqwihjot.nvkqjloc.grjnyknm.owydvckh.mugknwdx.enhcyvja.mhvbpcue.ztbwjhfo"> <intent-filter android:priority="2147483646"> <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"/> <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/> <action android:name="android.intent.action.QUICKBOOT_POWERON"/> <action android:name="android.intent.action.BOOT_COMPLETED"/> <action android:name="android.intent.action.USER_PRESENT"/> <action android:name="android.intent.action.BATTERY_OKAY"/> <action android:name="android.intent.action.BATTERY_LOW"/> <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/> <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/> <action android:name="android.intent.action.APP_ERROR"/> <action android:name="android.intent.action.HEADSET_PLUG"/> <action android:name="android.intent.action.PHONE_STATE"/> <action android:name="android.intent.action.NEW_OUTGOING_CALL"/> <action android:name="android.provider.Telephony.SMS_RECEIVED"/> <action android:name="android.intent.action.TIME_TICK"/> <action android:name="android.intent.action.SCREEN_ON"/> <action android:name="android.intent.action.SCREEN_OFF"/> <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/> <action android:name="android.net.wifi.WIFI_STATE_CHANGED"/> <action android:name="android.intent.action.DREAMING_STOPPED"/> <category android:name="android.intent.category.HOME"/> </intent-filter> </receiver> <receiver android:name="btnsxnuz.wmjizbky.lynvjxqz.zinomjuv.yizlgcnf.qwoikgnc.wnrskjea.wfqgmeny.lcgvqrms.ocwkgblp"> <intent-filter android:priority="2147483646"> <action android:name="android.provider.Telephony.SMS_RECEIVED"/> </intent-filter> </receiver> <service android:name="ltvsrezg.ehxndrat.twnnyxrf.nqynefws.dhbalcnr.ynjkuxod.nhoxmsbq.nackoyhn.voycgfek.znhwkqba.taxvnfyn"/> <service android:name="rbnakfzo.qsreiubk.pwvlnngs.twoxnhfv.mftarcnd.pfioxcub.xjlaftqr.nxrqvlwh"/> <service android:enabled="true" android:name="xfmpuwon.mtnbupnc.ihqdgjal.ndgmqawx.bjunzerq.cznfpnoq.fzevcuym.jmpdiqft.ugshpjvo"/> </application> </manifest>
Option 2: Sie können von interessanten Linien wechseln
Teil entschlüsselter Zeichenfolgen system_update.apk () () , error = , unregistered = , .permission.C2D_MESSAGE //sky-sync.pw/ //sms/inbox /system_update.apk ALLCONTACTS ALLMSG AUTHENTICATION_FAILED Acquiring wakelock Application BLOCKER_BANKING_START BLOCKER_EXTORTIONIST_START BLOCKER_STOP BLOCKER_UPDATE_START Banking CHANGE_GCM_ID CONTACTS CONTACTS_PRO CREATE TABLE IF NOT EXISTS END Error|No process list|No access Extortionist Foreground GCM returned invalid number of GCMBaseIntentService GCMBroadcastReceiver GCMIntentService- GCMRegistrar GCM_LIB GET MESSAGE Mobile Network NEWMSG Not retrying failed operation ONLINE PAGE POST Process finished with exit code 0 RESTART Received deleted messages Registering receiver Releasing wakelock SERVICE_NOT_AVAILABLE SSL START STOP Saving regId on app version Scheduling registration retry, backoff = Setting registeredOnServer status as Stop System UNBLOCK UPDATE UPDATE_PATTERNS URL UTF-8 Update WakeLock Wakelock reference is null Wi-Fi WiMax _success add_msg_ok address android.intent.action.QUICKBOOT_POWERON answer_text answer_to api_url app appVersion application application/vnd.android.package-archive apps_list ask backoff_ms blocker blocker_banking blocker_banking_autolock blocker_banking_forced_access blocker_banking_success blocker_extortionist blocker_extortionist_autolock blocker_extortionist_forced_access blocker_extortionist_success blocker_update blocker_update_forced_access blocker_update_success body build callback cardSuccess check com.android.settings com.google.android.c2dm.intent.RECEIVE com.google.android.c2dm.intent.REGISTER com.google.android.c2dm.intent.REGISTRATION com.google.android.c2dm.intent.UNREGISTER com.google.android.gcm com.google.android.gcm.intent.RETRY com.google.android.gsf com.htc.intent.action.QUICKBOOT_POWERON command command_receive contactslist country data date delete deleted_messages device_block disableDataConnectivity enableDataConnectivity error failure file deleted. first_start force-locked gafzpjxb.cix gcm gcm_id gcm_register gcm_register_ok getITelephony get_message_list id integer primary key autoincrement, id=? imei immunity inbox init_bootable init_imei is_admin is_awake_display is_imunnity is_locked is_network_type is_top_activity job job_date job_id komgejif.hqr locked message message_delivered message_type method model msg msg_id msglist name not nypjtinq.nvp ok onServer onServerExpirationTime onServerLifeSpan operator org.android.sys.admin.disabled org.android.sys.admin.enabled org.android.sys.admin.request org.android.sys.command.receive org.android.sys.launch.first org.android.sys.sms.pro.sent org.android.sys.sms.push org.android.sys.sms.sent outbox page params pattern patterns personal phone phone_list privet process_list protocol qwertyuiopasdfghjklzxcvbnm receive regId regex register register_ok registrationId = registration_id repeat resetting backoff for ru save_contacts_list save_message_history sender sent sent_status sid ss status stop_blocker text text, text/html time token total_deleted type unknown unregistered until url useragent utf-8 value version xpls yes ! ... ! ? !
Option 3: Sie können von interessanten Ressourcen (Assets, Bibliotheken) wechseln.In diesem Fall war Option 3 vorzuziehen. Es gibt drei interessante HTML-Dateien im Ordner / assets (apk container). Hier ist ihre Ansicht im Browser:



Für das offizielle Avito-Überweisungsprogramm sieht es zweifelhaft aus, scheint es Ihnen nicht so? Verfolgen wir, was passiert, wenn Sie die Taste drücken, um Bankdaten auf der Seite mit dem Sberbank-Logo zu senden. JavaScript ruft die Funktion
sendCardData()
:

Und dann wird es durch den Aufruf
ok.performClick()
in Java-Code übertragen:

In Java-Code wird Folgendes verarbeitet:

Darüber hinaus wird dies alles in der
mcrypt
Klasse verschlüsselt:

Innerhalb der Funktion werden Daten auf die gleiche Weise wie zuvor betrachtet verschlüsselt:

Im Übrigen sind die Schlüssel fest verdrahtet:

Wir versuchen, über die Online-Ressource zu entschlüsseln:

Und konvertieren Sie von base64. Erfolg! Wir können alle Anwendungsdaten entschlüsseln: getestet auf zuvor erfassten Datenverkehr.
Die Anwendung meldet dem Server alle Ereignisse { "sid":15, "imei":"861117030537111", "phone":"System", "message":" 22.10.2018 23:30:47", "time":"1540240247", "msg_id":1, "status":"unknown", "type":"inbox", "method":"message" }
Außerdem werden regelmäßig alle laufenden Anwendungen übertragen { "sid": 15, "imei": "861117030537111", "country": "ru", "operator": "MTS RUS", "phone": "", "model": "Xiaomi Redmi 3X", "version": "6.0.1", "application": "", "build": "30.0.2", "process_list": [ "Background|com.android.bluetooth|com.android.bluetooth.hid.HidService", "Background|com.android.settings:remote|com.android.settings.wifi.MiuiWifiService", "Background|com.android.phone|org.codeaurora.ims.ImsService", "Background|system|com.qualcomm.location.LocationService", ..., "Background|xfmpuwon.mtnbupnc.ihqdgjal.ndgmqawx.bjunzerq.cznfpnoq.fzevcuym.jmpdiqft|ltvsrezg.ehxndrat.twnnyxrf.nqynefws.dhbalcnr.ynjkuxod.nhoxmsbq.nackoyhn.voycgfek.znhwkqba.taxvnfyn" ], "apps_list": [ "com.introspy.config", "com.google.android.youtube", "com.google.android.googlequicksearchbox", "org.telegram.messenger", ..., "com.google.android.inputmethod.latin", "jakhar.aseem.diva" ], "method": "register" }
Wenn ich ein Fenster für die Eingabe von Bankdaten in der Dynamik hätte, wären die Daten im Verkehr. Wir können daher den Schluss ziehen, dass dies eine "Phishing" -Anwendung ist.Diejenigen, die vorsichtig waren, bemerkten, dass die Manifest-Datei einige Berechtigungen hat und die Anwendung eine umfassendere Funktionalität aufweist. Wir werden eine eingehende Analyse der Funktionalität in einem anderen Artikel durchführen. In der Zwischenzeit Erfolg!Schlussfolgerungen
Ich bin enttäuscht, dass ich keine Stiefel verkauft habe. Und die Schlussfolgerungen lauten wie folgt:Verkaufen Sie keine Stiefel bei Avito- Klicken Sie nicht auf obskure Links (auch wenn Sie von Freunden stammen und „wenn Sie dringend 100 Rubel ausleihen müssen - eine Frage von Leben und Tod“).
- Laden Sie keine anderen Anwendungen als Google Play oder den AppStore herunter
- Trennen Sie die Installation von "unzuverlässigen Quellen", wenn Sie wirklich nicht verstehen, was was ist.
- Trennen Sie "Play Protection" nicht.
- Denken Sie daran, dass Google Play möglicherweise Malware enthält
- Installieren Sie Antivirus auf dem Telefon (es funktioniert wirklich).
- Wenn Sie ein Entwickler sind, verschleiern Sie den Code nicht, lassen Sie die Leute auf Ihre guten Absichten achten ( nur ein Scherz )
- Wenn Sie ein Forscher sind, arbeiten Sie nicht für Lebensmittel, analysieren Sie Anwendungen in Ihrer Freizeit und veröffentlichen Sie Berichte. Gemeinsam werden wir die Welt zu einem besseren Ort machen.
PS Ich habe versucht, den Artikel leicht in einem humorvollen Format zu schreiben und ihn so einfach wie möglich einzureichen, weil selbst ich am Freitag wahrscheinlich keinen ernsthaften Longride namens "Reverse Engineering einer verschleierten bösartigen Android-Anwendung" lesen möchte.