2015-11-02 7 views
5

Mein Ziel ist es, die AOSP zu instrumentieren, um alle Java-oder JNI-Aufrufe von einer gezielten App, mit oder ohne die Argumente und Rückgabewert dynamisch protokollieren. Ich möchte die Anwendung nicht ändern, deshalb suche ich den Android-Quellcode zu ändern. Ich bin nicht sehr erfahren mit AOSP und seiner Vielzahl von Bibliotheken und Frameworks, deshalb suche ich nach Ratschlägen, weil ich nicht weiß, wo ich anfangen soll. Darüber hinaus muss der Prozess effizient sein (dh ich glaube nicht, dass eine Debug-ähnliche Methode, bei der eine Hook-Klasse für jede Hook-Methode implementiert werden muss),Android App: Java/JNI Anruf Einhaken Strategien

Was? Bisher habe ich verstanden:

Mit dem relativ neuen ART-System kompiliert es den DEX-App-Quellcode in eine Art maschinenausführbaren Code (OAT?) Und ist im Vergleich zu Dalvik komplexer zu instrumentieren.

Der Ausführungsfluss: Kompilierter Java-Bytecode der App (der von der kompilierten Android API abhängt) + libs.so -> DVM -> gegabelte Zygote VM -> Ausführung der App.

Wenn ich versuche, an der Wurzel (Android API + libs.so) Haken wird es erfordert eine anspruchsvolle Arbeit an jedem Anruf zu haken. Das Ideal wäre eine Stelle, an der alle Java-Aufrufe passieren. Gibt es einen solchen Ort sogar bei ART?

Der AOSP-Quellcode ist schwer zu verstehen, da es anscheinend kein Dokument gibt, das die Rolle jeder Quelldatei in der globalen Architektur angibt. Also wo ist es besser, die Anrufe zu haken?

EDIT (n)

Dieses Thema nicht gut abgedeckt ist, so zeige ich Informationen für alle Interessierten.

Meine Forschungen stießen auf diesen Blog: http://blog.csdn.net/l173864930/article/details/45035521. (+ Google übersetzen) Wer zu dieser interessanten Java verbindet und ELF (Arm) -Aufruf Einhaken Projekt: https://github.com/boyliang/AllHookInOne

Es ist nicht genau das, was ich suche, aber ich werde versuchen, eine AOSP Patch für die dynamische Analyse, dass paßt zu implementieren meine Bedürfnisse.

Antwort

9

Ich habe es geschafft, meine Frage zu beantworten. Für das, was ich aus dem Quellcode verstehen könnte, ist es 3 mögliche Eintrittspunkte für die Java-Anrufe:

  • ArtMethod :: Invoke (Kunst/runtime/Spiegel/art_method.cc)
  • Execute (Kunst/Laufzeit /interpreter/interpreter.cc)
  • DoCall (Kunst/runtime/Interpret/interpreter_common.cc)

ArtMethod :: Invoke scheint für die Reflexion verwendet werden soll und für das Verfahren direkt mit einem Zeiger auf die OAT Aufruf Codeabschnitt. (Wiederum keine Dokumentation, es kann ungenau sein).

Führen Sie am Ende Calling DoCall im Allgemeinen.

Es gibt einige Optimierungen von ART, die das Studium von Java-Aufrufen erschweren, wie Methodeninlining und direktes Offset-Adress-Calling.

Der erste Schritt ist die Sperrung dieser Optimierungen:

In device/Marken-Name/Typ/device.mk (in meinem Fall device/LGE/Hammer/device.mk für ein Nexus-5):

Fügen Sie die Option "nur interpretieren" zu dex2oat hinzu. Mit dieser Option kompiliert ART nur den Boot-Klassenpfad, sodass die Anwendungen nicht in OAT kompiliert werden.

PRODUCT_PROPERTY_OVERRIDES := \ 
    dalvik.vm.dex2oat-filter=interpret-only 

Der zweite Schritt ist in der Technik inlining/Compiler/DEX/frontend.cc zu deaktivieren:

Uncomment "kSuppressMethodInlining".

/* Default optimizer/debug setting for the compiler. */ 
static uint32_t kCompilerOptimizerDisableFlags = 0 | // Disable specific optimizations 
    (1 << kLoadStoreElimination) | 
    // (1 << kLoadHoisting) | 
    // (1 << kSuppressLoads) | 
    // (1 << kNullCheckElimination) | 
    // (1 << kClassInitCheckElimination) | 
    (1 << kGlobalValueNumbering) | 
    // (1 << kPromoteRegs) | 
    // (1 << kTrackLiveTemps) | 
    // (1 << kSafeOptimizations) | 
    // (1 << kBBOpt) | 
    // (1 << kMatch) | 
    // (1 << kPromoteCompilerTemps) | 
    // (1 << kSuppressExceptionEdges) | 
    (1 << kSuppressMethodInlining) | 
    0; 

Der letzte Schritt ist die direkte Code-Offset-Aufruf in der Kunst/Compiler/Treiber/compiler_driver.cc zu deaktivieren:

-bool use_dex_cache = GetCompilerOptions().GetCompilePic(); 
+bool use_dex_cache = true; 

Mit diesen Änderungen alle verschiedenen Anrufe in der DoCall Funktion fallen, wo wir können Schließlich fügen Sie unsere gezielte Protokollierungsroutine hinzu.

In art/runtime/Interpreter/interpreter_common.h, am Anfang ADD des umfasst:

#ifdef HAVE_ANDROID_OS 
#include "cutils/properties.h" 
#endif 

In art/runtime/Interpreter/interpreter_common.cc, zu Beginn der Funktion DoCall hinzuzufügen:

#ifdef HAVE_ANDROID_OS 
    char targetAppVar[92]; 
    property_get("target.app.pid", targetAppVar, "0"); 

    int targetAppPID = atoi(targetAppVar); 

    if(targetAppPID != 0 && targetAppPID == getpid()) 
    LOG(INFO) << "DoCall - " << PrettyMethod(method, true); 
#endif 

Zum Targeting der Anwendung verwende ich eine Eigenschaft, die die Ziel-PID festlegen. Dafür benötigen wir das lib system/core/libcutils und diese lib steht nur zur Verfügung, wenn das AOSP für ein echtes Telefon kompiliert wurde (ohne mit den aktuellen Makefiles zu verfahren).
Also die Lösung wird nicht für einen Emulator funktionieren. ( Nur Raten, nie ausprobiert EDIT: bestätigt, "cutils/properties.h" kann nicht zum Build eines Emulators hinzugefügt werden).

Nach dem Kompilieren und Flashen des gepatchten AOSP, starten Sie eine App, ps | grep für die PID zu finden und legen Sie die Eigenschaft in root:

[email protected]:/ # ps | grep contacts          
u0_a2  4278 129 1234668 47356 ffffffff 401e8318 S com.android.contacts 

[email protected]:/ # setprop target.app.pid 4278 

[email protected]:/ # logcat 
[...] 
I/art  (4278): DoCall - int android.view.View.getId() 
I/art  (4278): DoCall - void com.android.contacts.activities.PeopleActivity$ContactsUnavailableFragmentListener.onCreateNewContactAction() 
I/art  (4278): DoCall - void android.content.Intent.<init>(java.lang.String, android.net.Uri) 
I/art  (4278): DoCall - void android.app.Activity.startActivity(android.content.Intent) 
I/ActivityManager( 498): START u0 {act=android.intent.action.INSERT dat=content://com.android.contacts/contacts cmp=com.android.contacts/.activities.ContactEditorActivity} from uid 10002 on display 0 
V/WindowManager( 498): addAppToken: AppWindowToken{3a82282b token=Token{dc3f87a ActivityRecord{c0aaca5 u0 com.android.contacts/.activities.ContactEditorActivity t4}}} to stack=1 task=4 at 1 
I/art  (4278): DoCall - void android.app.Fragment.onPause() 
I/art  (4278): DoCall - void com.android.contacts.common.list.ContactEntryListFragment.removePendingDirectorySearchRequests() 
I/art  (4278): DoCall - void android.os.Handler.removeMessages(int) 
I/art  (4278): DoCall - void com.android.contacts.list.ProviderStatusWatcher.stop() 
I/art  (4278): DoCall - boolean com.android.contacts.list.ProviderStatusWatcher.isStarted() 
I/art  (4278): DoCall - void android.os.Handler.removeCallbacks(java.lang.Runnable) 
I/art  (4278): DoCall - android.content.ContentResolver com.android.contacts.ContactsActivity.getContentResolver() 
I/art  (4278): DoCall - void android.content.ContentResolver.unregisterContentObserver(android.database.ContentObserver) 
I/art  (4278): DoCall - void android.app.Activity.onPause() 
I/art  (4278): DoCall - void android.view.ViewGroup.drawableStateChanged() 
I/art  (4278): DoCall - void com.android.contacts.ContactsActivity.<init>() 
I/art  (4278): DoCall - void com.android.contacts.common.activity.TransactionSafeActivity.<init>() 
I/art  (4278): DoCall - void android.app.Activity.<init>() 
I/art  (4278): DoCall - void com.android.contacts.util.DialogManager.<init>(android.app.Activity) 
I/art  (4278): DoCall - void java.lang.Object.<init>() 
[...] 

Wenn es vorbei ist:

[email protected]:/ # setprop target.app.pid 0

Voilà!

Die Überlastung ist aus Benutzersicht nicht wahrnehmbar, aber das logcat wird schnell gefüllt.

PS: Dateipfade und -namen stimmen mit der Android 5-Version (Lollipop) überein, sie unterscheiden sich wahrscheinlich von den höheren Versionen.

PS ': Wenn man die Argumente der Methoden ausdrucken möchte, rate ich dazu, art/runtime/utils.cc für die PrettyArguments-Methode zu betrachten und irgendwo im Code eine praktische Implementierung zu finden.

+0

Vielen Dank dies zu erläutern. Ich habe eine Frage. Wenn ich den AOSP-Code wie beschrieben patchen und ein Android-Systemabbild für einen Emulator erstellen möchte, wo sollte ich die Option "nur interpretieren" hinzufügen? Ich konnte die Datei device.mk für den Emulator nicht finden. Bitte lass es mich wissen. – aMa

+0

Was ist Ihr Zielgerät? Mein war ein Nexus 5 Hammerhead, also ist mein Pfad /device/lge/hammerhead/device.mk. –

+0

Sry, ich habe gerade zu schnell gelesen. Ich habe nie versucht für einen Emulator und Sie werden wahrscheinlich Probleme mit libcutils für die Funktion property_get haben. Hast du es schon ohne die Änderungen an der device.mk versucht? Es sollte im schlimmsten Fall ohne es funktionieren. Ohne es ist das Schlimmste, was passieren kann, dass Sie einige der Anrufe verpassen. –

2

Vielleicht können Sie weitere Ideen aus Xposed Projekt erhalten, ist es den gleichen Ansatz folgen, indem sie die Methode inlining und direkte Verzweigung Optimierung zu deaktivieren:

https://github.com/rovo89/android_art/commit/0f807a65612f77a46120a53d3caa12c2

https://github.com/rovo89/android_art/commit/92e8c8e0309c4a584f4279c478d54d8ce036ee59

+0

Danke für Ihr Interesse. Ich kenne das Xposed-Projekt bereits. Nachdem ich herausgefunden habe, wie man das Inlining deaktiviert, habe ich das github-Projekt gefunden und jeden einzelnen Git-Commit überprüft. Ich habe festgestellt, dass ich das, was du die direkte Verzweigung nennst, deaktiviert habe, alle Credits für diesen Titel gelten für den/die Autor (en) von Xposed. –