Reparieren, hacken, graben. Löse die Online Quest Droid Mission



Letztes Jahr haben wir eine Online-Suche nach mobilen Entwicklern durchgeführt - Droid Mission. Innerhalb eines Monats mussten die Teilnehmer so viele Probleme wie möglich in drei Richtungen lösen: Fix it! (Fehlersuche und Code-Recherche), hack es! (Reverse Engineering) und graben Sie es! (Lernen Sie die Funktionen von Android). Insgesamt hatte die Suche 23 Aufgaben - sie sind denen sehr ähnlich, denen Android-Spezialisten in der realen Arbeit begegnen. In der Post zeigen wir alle Voraussetzungen und die richtigen Lösungen.


Suche nach Fehlern und Code-Recherche


repariere es! # 1

Verfasserin: Anastasia Laushkina

An einem ruhigen Freitagabend bleiben zwei Agenten lange auf und führen einen unlösbaren Streit. Sie wurden angewiesen, eine große Menge geheimer Daten in einer SQLite-Datenbank mit einem ganzzahligen Schlüsselschlüssel zu speichern.

Agent A erstellt eine Tabelle mit einer Abfrage der Form: CREATE TABLE t (Schlüssel INT PRIMARY KEY, secret_value_1, secret_value_2) und Agent B mit einer Abfrage der Form CREATE TABLE t (Schlüssel INTEGER PRIMARY KEY ASC, secret_value_1, secret_value_2).

Agent A ist sich absolut sicher, dass seine Anfrage fehlerfrei ist. Agent B hat jedoch ein Argument dagegen: Er macht geltend, dass die Integrität der Daten während der Annäherung von Agent A verletzt werden kann.

Liste mit einem Komma: die Spalte oder Spalten, die für die Integrität von Agent B verantwortlich sind, aber nicht für Agent A verantwortlich sind; sowie die Datenstruktur in russischer Sprache, aufgrund derer die Anfrage von Agent B schneller sein wird.

Hinweise
Antwortformat: [Spaltenname 1], [Spaltenname N], [Strukturname] (ohne Klammern, mit kleinem Buchstaben)

Antwortbeispiel: x, y, array

Lösung

Es geht um rowId und seine Beziehung zum Primärschlüssel.

Im Fall von "CREATE TABLE t (Schlüssel INTEGER PRIMARY KEY ASC, secret_value_1, secret_value_2)" ist der Schlüssel ein Alias ​​für rowId. Bei "CREATE TABLE t (Schlüssel INT PRIMARY KEY, secret_value_1, secret_value_2)" - Nr. Der Grund ist in der Dokumentation zu finden .

In Abwesenheit einer Schlüsselbeziehung zu rowId wird daher eine Anforderung des Formats "INSERT IN TO VALUES (" some "," y "," z ")" erfolgreich ausgeführt, wodurch möglicherweise die Datenintegrität verletzt wird. Wenn eine solche Verbindung besteht, tritt ein Datentyp-Nichtübereinstimmungsfehler auf.

Die Antwort wurde als Paar aus Schlüssel, Zeilen-ID und Schlüssel / Zeilen-ID getrennt betrachtet (da sie sich bei bestehender Verbindung auf dieselbe Spalte beziehen).

Geschwindigkeit wird durch Speicherung in Form eines Suchbaums erreicht.

repariere es! # 2

Verfasserin: Anastasia Laushkina
Binärdatei

Um Feinde schnell zu erkennen, entwickelt Agent Kew eine Anwendung mit einer Liste bekannter Krimineller. Er hat es leicht geschafft, diese Liste in der Anwendung anzuzeigen, entscheidet jedoch, dass solche wichtigen Informationen auf dem Hauptbildschirm angezeigt werden sollen.

Dazu benötigt er ein Widget. Ein Problem: Aus irgendeinem Grund zeigt das Widget keine Liste an. Ein Instinkt teilt dem Agenten mit, dass das Problem nur in einer Zeile besteht.

Nennen Sie es mit einem Komma sowie der Zeile, durch die Sie es ersetzen müssen, um die optimale Lösung zu erhalten.

Hinweise
Antwortformat: [Zeile 1], [Zeile 2] (ohne Klammern)

Antwortbeispiel: FrameLayout, ScrollView

Lösung

1. Wir suchen nach einer Layoutdatei für das Widget, in der ein ungültiges ConstraintLayout-Element angezeigt wird (siehe developer.android.com/guide/topics/appwidgets#CreatingLayout ).
2. Ändern Sie es in das akzeptable und optimale - LinearLayout / FrameLayout.

Obwohl die Verwendung von FrameLayout das Layout der Elemente im Widget beeinträchtigt hat, wurde es dennoch als Antwort akzeptiert.

repariere es! # 3

Urheber: Artyom Viter
Binärdatei

Die Tester stellten einen abnormalen Anstieg des RAM-Verbrauchs fest. Es besteht der Verdacht, dass irgendwo ein Leck vorliegt.

Sie müssen das Problem untersuchen und lokalisieren. Geben Sie in der Antwort den Namen der Anwendungsklassenmethode und den Ort ihres Aufrufs an, was zu einem Speicherverlust führt. Wenn Sie mehrere Probleme finden, listen Sie sie alle auf.

Antwortformat: [Name der Klasse, in der die Methode aufgerufen wird]: [Zeilennummer in dieser Datei]: [Methodenname] (ohne Klammern)

Geben Sie mehrere Antworten in lexikografischer Reihenfolge an, getrennt durch ein #.

Ein Beispiel:

Wenn Sie glauben, dass die Datei ExampleFileName.java einen Speicherverlust aufweist,

class ExampleFileName {   public problemMethodName(Sting arg) {}   public test(Sting arg) {     problemMethodName(arg); //  8   ExampleFileName.java   } } 

Antwortbeispiel: ExampleFileName: 8: problemMethodName

Lösung

Der erste Weg ist die Code-Analyse.

  1. Wir studieren den Anwendungscode.
  2. Das erste Leck ist offensichtlich. Dies ist eine BroadCastReceiver-Registrierung in der SecondActivity-Klasse. Eine Meldung zu diesem Problem wird in logcat angezeigt, wenn Sie die Anwendung ausführen.
  3. Wenn Sie auf die startTimer () -Methode achten, werden Sie feststellen, dass die CountDownTimer-Klasse dem Haupt-Thread-Handler einen Abschluss mit einem Link zu textView hinzufügt. Und bevor die Aktivität zerstört wird, ruft die Instanzklasse (CountDownTimer) die cancel () -Methode nicht auf. Dies ist der zweite Speicherverlust.

Der zweite Weg sind Werkzeuge. Sie können die Leakcanary- Bibliothek in der Anwendung implementieren, einen Heap-Dump über ADB oder Android Profiler abrufen und die empfangenen Berichte analysieren. Eclipse Memory Analyzer (MAT) kann bei der Analyse helfen. Um heapdump in MAT zu öffnen, müssen Sie es mit dem Dienstprogramm hprof-convd in ein für MAT verständliches Format konvertieren.

repariere es! # 4

Gepostet von: Vali Ibragimov
Binärdatei

Ivan hat seinen ersten Tag in einem Online-Kino. Da er ein cooler Entwickler ist, wurde er sofort gebeten, den Absturz beim Ansehen eines Films zu beheben. Gleichzeitig entschloss er sich zum Refactoring. Der Code ist prägnanter und übersichtlicher geworden, der Fehler wurde nicht mehr reproduziert.

Später stellte sich jedoch heraus, dass die aktuelle Position des Films nicht an das Backend gesendet wurde. Hilf Ivan zu verstehen, welche Klasse er vertauscht hat.

Die Antwort ist der Name der Klasse, die verwendet werden soll.

Lösung

Um alle fünf Sekunden eine Betrachtungsposition zu senden und zum Netzwerk zu gehen, wird ExecutorService verwendet. Einen ScheduledThreadPoolExecutor für eine periodische Aufgabe erstellen, dachte Ivan - warum nicht damit ins Netzwerk? Schließlich ist ScheduledThreadPoolExecutor der Nachkomme von ThreadPoolExecutor. Ivan ahnte nicht einmal, dass ScheduledThreadPoolExecutor nur einen Thread verwendet, und wenn Sie zum Netzwerk wechseln, müssen Sie auf den Abschluss der regelmäßigen Task warten.

 scheduleFuture = scheduledExecutorService.scheduleAtFixedRate(() -> {                    try {                        timingsApi.sendTiming(filmId, player.getContentPosition()).get();                    } catch (Exception e) {                        e.printStackTrace();                    }                },                0, PERIOD_SECONDS, TimeUnit.SECONDS); 

Die Lösung des Problems wurde noch dadurch erschwert, dass wir im UI-Thread - und in der neuen Version 2.9 - nicht auf ExoPlayer zugegriffen haben. * ExoPlayer begann, diesbezügliche Warnungen in die Protokolle zu schreiben. Aber jetzt ist dies nur eine Warnung und kein Fehler, den Ivan begangen hat.

repariere es! # 5

Verfasser: Alexander Tsybin
Binärdatei

Ein Unternehmen entwickelte ein Farmer Simulator-Spiel.

In diesem Spiel konnte sich nur ein Spieler frei bewegen. Alle anderen Objekte waren entweder bewegungslos oder hatten eine klar definierte Bewegungsbahn. Irgendwann beschlossen sie, dem Spiel Feinde hinzuzufügen, die für den Spieler zu einem Hindernis werden würden.

Entwickler Vasya wurde angewiesen, die Feinde zu realisieren. Während der Implementierung ist Vasya auf ein Leistungsproblem gestoßen. Er entschied sich, es wegen Multithreading zu beheben. Da Vasya mit Multithreading nicht vertraut war, nutzte er die Lösungen von Stackoverflow. So wurde er Leistungsprobleme los.

In der Testphase stellte sich jedoch heraus, dass das Spiel manchmal einfriert. Hilf Vasya, den Grund zu finden.

Geben Sie als Antwort die Nummern der problematischen Codezeilen ein - durch Kommas getrennt, in aufsteigender Reihenfolge und ohne Leerzeichen. Wie folgt: 1,17,42

Lösung

Boxing-Primitivtypen (z. B. int in Integer) sind teure Operationen. Zu Optimierungszwecken verwenden Java-Maschinen solche Objekte manchmal wieder. Linien sind keine Ausnahme.

Die Zeilen ENEMY_LOCK und DECISIONS_LOCK werden im Code für die Synchronisation verwendet. Wenn sich also Orte im Projekt mit Synchronisierung in denselben Zeilen befinden, kann ein Deadlock auftreten.

Im Allgemeinen können Sie String / Integer usw. nicht für die Synchronisation verwenden.

Antwort: 7.8

repariere es! # 6

Verfasser: Ivan Pukhov
Binärdatei

Das Bildverarbeitungsteam hat eine neue native Bibliothek veröffentlicht. Sie müssen sie ausprobieren und auf etwaige Probleme hinweisen.

Lösung

Dies ist eine leichte Aufgabe zum Aufwärmen. In den Ressourcen liegt die Bibliothek selbst und die Header-Datei dafür. In der Kopfzeile gibt die einzige Funktion ein Jobobjekt zurück.

Sie müssen nur noch ein Testprojekt erstellen (durch Installieren von NDK) und es aufrufen! Ein Funktionsaufruf im Hauptthread löst eine Ausnahme aus, in der Sie gefragt werden, ob Sie ihn nicht auf diese Weise aufrufen möchten. Wir übertragen die Ausführung auf irgendeine Weise auf einen anderen Thread - und alles funktioniert.

Jetzt lohnt es sich, das zurückgegebene Objekt zu überprüfen - ist es wirklich eine Bitmap? Am einfachsten ist es, sie sofort in einer ImageView anzuzeigen. Wir werden ein Bild mit einer Textzeichenfolge sehen, und die Aufgabe erfordert eine Antwort auch als Zeichenfolge. Dies ist wahrscheinlich kein Zufall. :)

repariere es! # 7

Urheber: Dmitry Zaitsev
Binärdatei

Es gibt eine Anwendung mit Codes, bei der der gewünschte Code eingerahmt ist. Leider war das Layout fehlerhaft und muss wiederhergestellt werden, um den Code zu finden.

Hinweise
Nach der Korrektur des Codes durchläuft der Rahmen genau 22 Zeichen, die gegen den Uhrzeigersinn aufgelistet werden müssen, beginnend mit der oberen linken Ecke des Rahmens.

Antwortbeispiel: ScQG1jxbazmjbcARefbRMo

Lösung

Jetzt ist Dolch der De-facto-Standard in der Android-Entwicklung geworden. Wenn die DI bereits konfiguriert ist, ist es sehr einfach, Inject vor den Konstruktor zu schreiben und den Rest der Arbeit an Dagger zu übergeben. Es ist so einfach, dass Sie später nicht mehr darüber nachdenken können, wie Abhängigkeiten bereitgestellt werden. Auch in Android müssen Sie häufig mit der Context-Klasse und ihren Nachkommen arbeiten: Application and Activity. Die Anwendung ist an den Lebenszyklus der Anwendung und die Aktivität an den Lebenszyklus des Bildschirms gebunden. Bei der Arbeit mit diesen Klassen ist es daher wichtig, viele Funktionen zu beachten. Die Aufgabe basiert genau auf der Verwendung des falschen Kontexts, und all dies wird mit DI getarnt.

Zum Lösen können Sie die folgenden Schritte ausführen:

  1. Untersuchen Sie die Projektdateien, und beachten Sie, dass ItemStyle auf alle TextViews angewendet wird.
  2. Stellen Sie sicher, dass der Stil nicht wirklich angewendet wird. Dies sollte zu dem Gedanken führen, dass das Problem mit dem Thema und daher mit dem Kontext der Aktivität zusammenhängt.
  3. Verstehen Sie das Abhängigkeitsdiagramm und verstehen Sie, dass der Anwendungskontext im Adapter bereitgestellt wird.
  4. Ändern Sie im ContestAdapter den Kontexttyp in Activity.

repariere es! # 8

Gepostet von: Vali Ibragimov
Binärdatei

Ivan erhielt die Aufgabe, die Anwendung umzugestalten, um mithilfe von DI über ContentProvider eine Liste von Aufgaben zu erhalten. Er überarbeitete die Anwendung mit Dagger, und als sie gestartet wurde, stürzte die Anwendung ab.

Hilf Ivan, den Grund zu verstehen:

  1. Geben Sie die Zeilennummer mit dem Klassennamen an, den Sie an eine andere Klasse übertragen möchten.
  2. Stellen Sie einen Link zur Dokumentation mit einem Anker an einer Stelle bereit, um zu verstehen, warum die Anwendung abstürzt.

Hinweise
Antwortformat: [Klassenname]: [Zeilennummer] -> [Klassenname]: [Zeilennummer], [Link]

Beispiel beantworten:

Erste Klasse: 12-> Zweite Klasse: 45, https://developer.android.com/reference/android/app/Activity#activity-lifecycle

Lösung

Die Aufgabe bestand aus zwei Teilen:

1. Verstehen und Bereitstellen einer Absturzlösung in ContentProvider beim Zugriff auf die DI-Komponente. Die richtige Lösung bestand darin, die Initialisierung der DI-Komponente auf den ContentProvider zu übertragen.



Die onCreate-Methode in ContentProvider wird früher als in Application aufgerufen. Dies lässt sich leicht überprüfen, wenn Sie den Anwendungsstartcode in der ActivityThread-Klasse und der handleBindApplication-Methode untersuchen.



2. Geben Sie einen Link an, der beschreibt, dass onCreate for ContentProvider früher als Application aufgerufen wird. Google erwähnt dies nicht auf der ContentProvider-Dokumentationsseite. Aber hier ist ein Auszug aus der Beschreibung der Methode onCreate Aplication:

Wird beim Starten der Anwendung aufgerufen, bevor Aktivitäts-, Dienst- oder Empfängerobjekte (mit Ausnahme von Inhaltsanbietern) erstellt wurden.

repariere es! # 9

Verfasser: Alexander Tsybin
Binärdatei

Dem Entwickler wurde die Aufgabe übertragen, die Ansicht für eine Liste von Elementen zu implementieren. In TK gab es eine wichtige Anforderung - die Liste zum ersten und letzten Element zu scrollen, damit diese Elemente in der Mitte des Bildschirms angezeigt werden. Der Entwickler hat die Funktionalität implementiert, aber beim Testen stellte sich heraus, dass die Zentrierung manchmal nicht funktioniert. Helfen Sie dem Entwickler, die problematischen Zeilen im Code zu finden.

Hinweise
Antwortformat:

<Dateiname ohne Erweiterung>: <Zeilennummern durch Kommas getrennt>

<Dateiname ohne Erweiterung>: <Zeilennummern durch Kommas getrennt>

Zeilen müssen in lexikografischer Reihenfolge sortiert sein. Zeilennummern sollten in aufsteigender Reihenfolge sortiert werden.

Beispiel beantworten:

BarFoo: 1

FooBar: 12,13,14,99

Lösung

Es gibt zwei Probleme im Code:

1. Gemessen am Code wird davon ausgegangen, dass der Aufruf von onViewDetachedFromWindow immer nach onBindViewHolder erfolgt, dies ist jedoch nicht der Fall. Die Doppelmethode für onViewDetachedFromWindow ist onViewAttachedToWindow. Infolgedessen wird holder.view.reset () aufgerufen und die Zentrierung verschwindet, wenn der Bildlauf langsam ist.

2. Unter Android vor Version 7 funktioniert addView (rootView, params) nicht wie erwartet.

Wenn Sie eine Ansicht hinzufügen, wird ein LayoutParam generiert, das folgendermaßen aussieht:

Marshmallow - github.com/aosp-mirror/platform_frameworks_base/blob/marshmallow-release/core/java/android/widget/FrameLayout.java#L403
Nougat - github.com/aosp-mirror/platform_frameworks_base/blob/nougat-release/core/java/android/widget/FrameLayout.java#L384

FrameLayout.LayoutParams verfügt über zwei Konstruktoren, von denen einer ViewGroup.MarginLayoutParams verwendet und die Ränder in sich selbst kopiert: github.com/aosp-mirror/platform_frameworks_base/blob/nougat-release/core/java/android/view/ViewGroup.java#L14

Der zweite Konstruktor akzeptiert ViewGroup.LayoutParams und ignoriert die Ränder: github.com/aosp-mirror/platform_frameworks_base/blob/nougat-release/core/java/android/view/ViewGroup.java#L7328

Infolgedessen funktioniert die Zentrierung unter Android bis Version 7 nicht.

Die Antwort lautet:
ItemView: 35
Hauptaktivität: 53

Reverse Engineering


Hack es! # 1

Verfasser: Valentin Baryshev
Binärdatei

Ein Entwickler beeilte sich und testete nicht einmal die endgültige .apk-Datei, bevor er sie an den Wettbewerb übermittelte.

Es stellte sich heraus, dass er eine Ansichtsgruppe in activity_main.xml vertauscht hatte. Zusätzlich platzierte er jeden Buchstaben des Schlüssels in einer eigenen Textansicht. Infolgedessen trennten sich alle Ansichten des Layouts und es kam zu völliger Empörung auf dem Bildschirm.

Versuchen Sie festzustellen, welche Ansichtsgruppe anstelle der aktuellen sein soll.

Die Antwort auf das Problem ist der Code, der nach dem Ersetzen der richtigen Ansichtsgruppe auf dem Bildschirm angezeigt wird.

Lösung

Es ist notwendig, .apk auf jede verfügbare Weise zu dekompilieren (z. B. durch Online-Dekompilierer) und das Projekt durch Code neu zu erstellen.

Wenn wir main_layout analysieren, können wir anhand der Attribute erraten, dass die Stammansichtsgruppe ConstraintLayout sein sollte.

Antwort: tniartsnoc

Hack es! # 2

Verfasser: Alexander Tsybin
Binärdatei

Ein erfahrener Benutzer hat die Anwendung zum Absturz gebracht. Er war nicht überrascht, öffnete die Protokolle, fand die Zeile, die den Fehler verursachte: N72XbphDx5NnFl6CKMNl8w == und schickte sie an den technischen Support.

Es stellte sich heraus, dass er eine veraltete Version der Anwendung verwendete, die vor der Verwendung von Code-Repositorys entwickelt wurde, sodass der Entschlüsselungscode verloren ging. Es wurde jedoch die .apk der alten Version der Anwendung gefunden.

Helfen Sie die Nachricht zu entschlüsseln.

Lösung

Es ist notwendig, .apk auf jede verfügbare Weise zu dekompilieren (z. B. durch Online-Dekompilierer) und das Projekt durch Code neu zu erstellen.

Der Code selbst enthält sowohl die Verschlüsselungs- als auch die Entschlüsselungsfunktion, auf die Sie den verschlüsselten String geben und eine Antwort erhalten können.

Die Antwort lautet:
TF: Gute Arbeit!

Hack es! # 3

Verfasser: Valentin Baryshev
Binärdatei

Wie gut kennen Sie den Lebenszyklus einer Android-Anwendung?

Wussten Sie, dass das System in einigen Fällen den Bewerbungsprozess beenden kann?

Simulieren Sie diese Situation in der Anwendung.

Sie sehen die Antwort nach dem Wiederherstellen der Anwendung - in Form von Code.

Lösung

Es genügte, .apk auf dem Telefon zu installieren, auszuführen und den Fall zu ermitteln, wenn das System die Anwendung entlädt, aber gleichzeitig im Vorhang bleibt.

Eine Möglichkeit besteht darin, die Anwendung zu installieren, zu starten und zu minimieren (oder einfach zu einer anderen Anwendung zu wechseln). Dann verbinden wir uns über adb mit dem Computer. Wählen Sie in Android Studio die Registerkarte Logcat, wählen Sie den Prozess dieser Anwendung aus und klicken Sie auf das rote Stoppsymbol. Öffnen Sie dann die zuvor minimierte Anwendung aus dem Vorhang. Der Bildschirm zeigt die Antwort an: sss2384gxcxxX.

Hack es! # 4

Verfasser: Ivan Pukhov
Binärdatei

Ein Front-End-Kollege hat eine Demo des neuen Moduls veröffentlicht, aber vergessen, Spezifikationen zu senden. Jetzt schläft er in einer anderen Zeitzone und eine Demo muss in ein paar Minuten fertig sein. Nach einem Gespräch mit einem Kollegen erinnern Sie sich an seinen Satz "Ja, dort ist es einfach, Sie müssen nur Stichwörter schreiben, und es wird funktionieren."

Laden Sie das Archiv herunter und versuchen Sie, ohne einen Kollegen fertig zu werden.

Lösung

Dies ist eine einfache Aufgabe, die jedoch einige Neugier und Ausdauer erfordert.

Laden Sie das Archiv herunter, laden Sie den Inhalt auf den lokalen Testserver hoch, erstellen Sie ein Projekt mit WebView und führen Sie es aus. Nach einer kurzen Zeit wird die Meldung „Ausrichtung kalibrieren“ angezeigt. Und alle. Aber die Nachricht deutet darauf hin, dass Sie vielleicht das Telefon in Ihren Händen drehen sollten? Danach wird eine verdächtige Nachricht über die ausgelöste Ausnahme angezeigt - mit einem Aufruf zum Überprüfen der Konsolenausgabe.

Wir öffnen die Konsole und sehen einen Aufruf einer nicht vorhandenen Methode für das API-Objekt. Wir fügen dem WebView ein Objekt hinzu, um die JS-API zu implementieren, und versuchen erneut, die Anwendung zu testen.

Anscheinend lohnt es sich, einen Rückgabewert hinzuzufügen. Wir wählen aus, fügen hinzu - es funktioniert. Aber es gibt nirgendwo eine Linie mit der Antwort. Schalten Sie das Telefon erneut ein - eine neue Methode wird aufgerufen. Fügen Sie es auch hinzu. Nach mehreren Iterationen erhalten wir den Aufruf finalizeCalibrating und anschließend storeResult, in dem unsere Leitung eintrifft.

Wenn Sie die Quelle herunterladen, möchten Sie möglicherweise nichts lösen, sondern sie öffnen und die Antwort herausziehen. Diese Methode funktioniert, aber ein paar kleine Rechen erwarten Sie auf dem Weg.

Hack es! # 5

Verfasser: Ivan Pukhov

Die Entwickler-Assembly der neuen Android-Version ist in das Netzwerk gelangt, in dem der neue Mechanismus zur Anwendungssignierung direkt auf dem Gerät debuggt wurde. In dieser Assembly wird der private Schlüssel zum Signieren in den Quellcode des Systems eingenäht, und die Entwickler haben Teile der Benutzeroberfläche verlassen, um ihn zu erhalten. Finde den Schlüssel.


Lösung

1. Wenn Sie den Emulator ausführen, bemerken Sie die SecretActivity-Anwendung. Wenn Sie es öffnen, wird ein Toast angezeigt, in dem Sie aufgefordert werden, die Protokolle anzuzeigen. Da es sich um eine Debugging-Assembly handelt, gibt es viele Protokolle, die nach dem Namen der Anwendung gefiltert werden müssen.

 adb logcat | grep 'SecretActivity' 

1898 1898 E SecretActivity: Try broadcast ZggwxXsaQ9SapPKyHpnwnYmALHazVFWX

2. Wir versuchen Broadcasts mit Action aus dem Log zu werfen:

 adb shell am broadcast -a ZggwxXsaQ9SapPKyHpnwnYmALHazVFWX 

3. Auf dem Bildschirm wird ein Toast mit dem Vorschlag angezeigt, die Protokolle anhand des SecretReceiver-Tags anzuzeigen.

 adb logcat | grep 'SecretReceiver' 

1898 1898 E SecretReceiver: ISecretService.aidl
1898 1898 E SecretReceiver: package android.app;
1898 1898 E SecretReceiver: interface ISecretService {
1898 1898 E SecretReceiver: String getSecret();
1898 1898 E SecretReceiver: }
1898 1898 E SecretReceiver: See global settings to bind SecretService


4. Wir untersuchen die globalen Einstellungen, um eine Aktion zum Herstellen einer Verbindung mit SecretService zu finden.

 adb shell settings list global 

...
bind_secret_service_action=g8mNyGQZR8aHLTXNWcjdwJJYZ85Ewx83
...


5. Wir schreiben einen Client für den ISecretService-Dienst unter Verwendung dieser Hilfsschnittstelle.

 public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = new Intent(); intent.setAction("g8mNyGQZR8aHLTXNWcjdwJJYZ85Ewx83"); PackageManager pm = getPackageManager(); List<ResolveInfo> resolveInfoList = pm.queryIntentServices(intent, 0); if (resolveInfoList == null || resolveInfoList.size() != 1) { return; } ResolveInfo serviceInfo = resolveInfoList.get(0); ComponentName component = new ComponentName(serviceInfo.serviceInfo.packageName, serviceInfo.serviceInfo.name); Intent explicitIntent = new Intent(intent); explicitIntent.setComponent(component); bindService(explicitIntent, new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { ISecretService secretService = ISecretService.Stub.asInterface(service); try { Log.d("MainActivity", secretService.getSecret()); } catch (Exception e) { Log.e("MainActivity", "RemoteException", e); } } @Override public void onServiceDisconnected(ComponentName name) { } }, Context.BIND_AUTO_CREATE); } } 

6. Führen Sie aus, in den Protokollen erhalten wir die Antwort:

 adb logcat | grep 'MainActivity' 

1898 1898 E MainActivity: VENHz=qWr7y!t3ZhP!8Skw!!kcTkt7V%

Hack es! # 6

Verfasser: Pavel Vorobkalov
Binärdatei

Herr Tupper schrieb eine Android-App, die Nachrichten sendet.

Entschlüsseln Sie die Nachricht und fahren Sie fort.

Antwortformat: Zeichenfolge als Link.

Lösung

Installieren Sie die Anwendung und führen Sie sie auf dem Gerät aus. Wir sehen zwei Schaltflächen: Nachricht senden und Formel senden. Wenn Sie darauf klicken, geschieht nichts Sichtbares. Sie müssen herausfinden, wie und wohin die Anwendung etwas sendet.



Wir öffnen .apk-Anwendungen mithilfe einiger Methoden für das Reverse Engineering und sehen uns die Hauptaktivität an. Dort sehen Sie die Methoden onSendMessageClick und onSendFormulaClick. Sie erstellen eine Absicht mit der Aktion "com.yandex.tupper.action.NEW_MESSAGE" und zusätzlich mit dem Schlüssel "com.yandex.tupper.message" und senden sie aus der Liste an die Anwendungen (unter Verwendung der allgemeinen Methode). Sie erhalten die Liste durch Aufrufen von PackageManager.queryBroadcastReceivers.

Sie können weiterhin Reverse Engineering-Tools verwenden, um Nachrichten zu untersuchen, indem Sie sie aus dem Anwendungscode extrahieren. Dieser Pfad wird jedoch absichtlich (wenn auch geringfügig) durch zusätzliche RSA-Verschlüsselung erschwert.

Es gibt einen anderen Weg, der besser zur Android-Programmierung passt. Sie müssen eine Anwendung schreiben, die diese Broadcast-Absicht behandelt. Wir erstellen unsere Anwendung im Manifestregister Empfänger:

  <receiver android:name=".TupperMessageReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.yandex.tupper.action.NEW_MESSAGE" /> </intent-filter> </receiver> 

Im Handler erhalten wir die Nachricht von extra und führen unsere eigene Aktivität aus, in der wir das Ergebnis der Verarbeitung anzeigen:

 public class TupperMessageReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE); if (message == null) { return; } Intent activityIntent = new Intent(context, MainActivity.class); activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); activityIntent.putExtra(MainActivity.EXTRA_MESSAGE, message); context.startActivity(activityIntent); } } 

Lassen Sie uns nun die Entschlüsselung der Nachricht selbst behandeln. Wenn Sie in Yandex nach "Tuppers Nachricht" suchen, finden Sie einen Artikel über Wuppers Formel für Tuppers Formel. Es gibt ein Beispiel für eine codierte Formel in Form einer Zahl:

48584
4858450636189713423582095962494202044581400587983244549483093085061934704708809928450644769865524364849997247024915119110411605739177407856919754326571855442057210445735883681829823754139634338225199452191651284348332905131193199953502413758765239264874613394906870130562295813219481113685339535565290850023875092856892694555974281546386510730049106723058933586052544096664351265349363643957125565695936815184334857605266940161251266951421550539554519153785457525756590740540157929001765967965480064427829131488548259914721248506352686630476300

Diese Nummer wird als Nachricht gesendet, indem Sie auf die Schaltfläche Formel senden klicken. Das Ergebnis der Dekodierung der Nummer ist auch im Wikipedia-Artikel zu finden. Es kann verwendet werden, um die Implementierung des Dekodierungsalgorithmus zu debuggen.

Wir implementieren den Dekodierungsalgorithmus in Java und konvertieren der Schönheit halber die resultierende Binärzahl in eine monochrome Bitmap:

  public class TupperCodec { static final int TUPPER_R = 17; private TupperCodec() {} public static BigInteger decodeFromDecString(String decString) throws NumberFormatException { BigInteger data = new BigInteger(decString, 10); return data.divide(BigInteger.valueOf(TUPPER_R)); } public static String getNumberAsBinImage(BigInteger number) { String binString = number.toString(2); StringBuffer result = new StringBuffer(binString.length()); int i; for (i = 0; i < binString.length(); i++) { if ((i % TUPPER_R) == 0 && i > 0) { result.append('\n'); } result.append(binString.charAt(binString.length() - 1 - i)); } int numberOfRows = (binString.length() + TUPPER_R - 1) / TUPPER_R; for (; i < numberOfRows * TUPPER_R; i++) { result.append(~_~quot&#0;quot~_~); } return result.toString(); } public static Bitmap getBinImageAsBitmap(String binImage) { String[] lines = binImage.split("\n"); int[] colors = new int[lines.length * TUPPER_R]; for (int i = 0; i < lines.length; i++) { String line = lines[i]; assert line.length() == TUPPER_R; for (int j = 0; j < line.length(); j++) { colors[i * TUPPER_R + j] = line.charAt(j) == '0' ? Color.WHITE : Color.BLACK; } } return Bitmap.createBitmap(colors, TUPPER_R, lines.length, Bitmap.Config.ARGB_8888); } } 

Rufen Sie unter Aktivität die Dekodierung auf und zeigen Sie das Ergebnis als Bitmap in ImageView an:

  public class MainActivity extends AppCompatActivity { static final String EXTRA_MESSAGE = "com.yandex.tupper.message"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = getIntent(); if (intent != null && intent.hasExtra(MainActivity.EXTRA_MESSAGE)) { String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE); try { BigInteger data = TupperCodec.decodeFromDecString(message); String binImage = TupperCodec.getNumberAsBinImage(data); Bitmap bitmap = TupperCodec.getBinImageAsBitmap(binImage); ImageView imageView = findViewById(R.id.message_image); imageView.setImageBitmap(bitmap); CharSequence toastText = TextUtils.ellipsize(message, new TextPaint(), 400, TextUtils.TruncateAt.END); Toast.makeText(this, toastText, Toast.LENGTH_SHORT).show(); } catch (NumberFormatException ex) { Toast.makeText(this, getString(R.string.invalid_message), Toast.LENGTH_LONG).show(); } } } } 


Screenshot der dekodierten Nachricht

Die Antwort lautet clck.ru/FevR5 .

Hack es! # 7

Urheber: Igor Eremeev


.

. , , .

: - .



.apk zip- classes.dex — Java- . , , dex2jar Android Studio. dex2jar Java-, Android Studio class-. , .

, proguard ( android.support.* androidx.*, ), — com.yandex.contest.keygenme.MainActivity, Activity . , : MainActivity.a#doInBackground bbaab b , .



c d. N- π ( --), . , π hexed [c[i] + key[i]] = d[i], i = 0..11. , . 50 hex- π. : 537306089144. key_2056BE33E064.

, , — . doInBackground:



, , if (var12[0] == var8) {… }. var7 — i- . , var7 0 9 . . , .apk ( JVM) .

hack it! #8

:


N , . : Android 4.4, 1200 × 600, FM-. , , FM- . FM- , .

, FM-. .

, :

1. 106.00
2. (seek)
3. ,

, .

Hinweise
: . .

: , a(106.00) 106.00 , b(true) , c() , a(106.00);b(true);c()



: , FM- . .apk dex-. Java. , , — jadx.

.apk, . MainActivity. : fragment_holder RadioFullFragment . . RadioFullPresenter, ChangeRadioFrequencyUsecase, RadioRepo. .

«implements RadioRepo». : RadioRepoImpl. , b. ServiceConnection — . , b lambda$new$0$RadioRepoImpl. , $$Lambda$RadioRepoImpl$FYTR9gAgZEGvrLjkbkpAIup7OKw, serviceConnection IRadioService radioService. , RadioService.

: onServiceConnected «b radioManager = Stub.asInterface(service)». , . «bindService». bindService «com.some_company.help_service». , com.some_company.carradio.FmUtils. , , . , : j , : 8880 88.00 . 8800. a. , .

. : k z. RadioRepoImpl, enableRadio() disableRadio() k. z(boolean isForwardDirection), « (seek) ».

: a(10600);z(true);j().

hack it! #9

:


flatbuffers . GPX . . , .

FlatBuffers :

 namespace ru.yandex.android.task; struct GeoPoint { latitude:double; longitude:double; } table Points { items:[GeoPoint]; } root_type Points; 

: , sha256. .



, FlatBuffers.

1. fbs- .
2. Java-. JVM- , Gradle flatbuffers.
3. fbs-.
4. fbs-, - — . , FlatBuffers.
5. , . structs , struct table. .
6. Kotlin. FlatBuffers.

fbs , . FlatBufferBuilder input. input :

 val pointsList = Points.getRootAsPoints(buffer) val restoredPoints = (0 until pointsList.itemsLength()) .mapNotNull(pointsList::items) 

c , (lat, long). as-is GPX-.

GPX- ( ) . GPX XML. , XML- . XML- GPX-track-. XML- MAP- . «yandroid».

, . CLI-:

 echo "yandroid" | shasum -a 256 

.

Android


dig it! # 1

:


QA- .

:

— ( 'Screen 1')
— GO NEXT ( 'Screen 2')
— GO BACK
— GO NEXT,
— 5–10

: 'Screen 2'.

: , « ».

.apk .

Hinweise


C stack trace, .

Beispiel

stack trace …

 at android.os.MessageQueue.nativePollOnce(Native method) at android.os.MessageQueue.next(MessageQueue.java:326) at android.os.Looper.loop(Looper.java:160) at com.android.server.SystemServer.run(SystemServer.java:454) at com.android.server.SystemServer.main(SystemServer.java:294) at java.lang.reflect.Method.invoke(Native method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:838) 

… , RuntimeInit.java, 493, :

 com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 



, , « ».

/data/anr/traces.txt /data/anr/anr_* (https://developer.android.com/topic/performance/vitals/anr#pull_a_traces_file). adb-:

 adb root adb shell ls /data/anr adb pull /data/anr/<filename> 

( adb root , Google API.)

stack trace . — stack trace, :

 com.droid.mission.anrapk.MainActivity$2.onClick(MainActivity.java:43) 



dig it! # 2

:

Android Studio, , MultiDex. -, apk- .dex- (65536). / apk Andorid Studio .dex-.

— dex- , dex- ( , ) . dex- .

: multidex , android gradle plugin 3.0.0 – 3.1.4

.

?



, dex-. Gradle — , , .apk.

Java- dex- ART/Dalvik: transformClassesWithDexBuilderForDebug. dex-, . Android Gradle plugin (AGP) Gradle . , — , Gradle . , . AGP, — DSL- Gradle build.gradle.

3.1.* minimal-main-dex. , .

dig it! #3

:
— - .

?

: — .



, . Android WindowManager. . , WindowManager.LayoutParams . , , TYPE_APPLICATION .

, , . , , - .

, Android SDK, , . , WindowManager AOSP. , , , .

, , TYPE_BOOT_PROGRESS . getWindowLayerFromTypeLw WindowManagerPolicy. Javadoc :

Returns the layer assignment for the window type. Allows you to control how different kinds of windows are ordered on-screen

, , . switch-case , layer — TYPE_POINTER, 2018. .

dig it! #4

:

, - , .

. , , , .

Android , ?



, , Android SDK, .

startActivity Context . Context Activity — , startActivity . startActivityForResult. , Activity mInstrumentation.execStartActivity .

? startActivity ActivityManagerService, ServiceManager.getService(Context.ACTIVITY_SERVICE).

ActivityManagerService . startActivityAsUser, startActivity, ActivityStarter execute. , .

C startActivity . , abort , true START_ABORTED Activity.

, , mService.mIntentFirewall.checkStartActivity. , . :

This is called from ActivityManager to check if a start activity intent should be allowed.

, IntentFirewall . RULES_DIR . : ifw.

dig it! #5

:

. , (, ) — 8800. , , (+8800). , 8800 +8800 , / , .

. . , +8800 8800 .

, (java/c/c++). , .

: source.android.com
— : androidxref.com



Dialer , , URI authorities = "content://com.android.contacts" .

ContentProvider. URI ContactsPoviider. : , SQL- . :

 sb.append("PHONE_NUMBERS_EQUAL(" + Tables.DATA + "." + Phone.NUMBER + ", "); 

PHONE_NUMBERS_EQUAL — SQL-. sqlite .

sqlite, , . ContactsProvider , config_use_strict_phone_number_comparation, . Die Antwort lautet:

 <bool name="config_use_strict_phone_number_comparation">true</bool> 

Source: https://habr.com/ru/post/de484876/


All Articles