Nachdem Sie die oben genannten Tools beherrschen, können Sie mit der Entwicklung von Plug-Ins beginnen. Zunächst sollten Sie über die Anforderungen nachdenken, die das Plug-in implementieren muss, und die relevanten Ansichten und Controller finden. Der erste Schritt besteht darin, Class-Dump zu verwenden, um die geshellte APP zu analysieren. Class-Dump kann alle Klassennamen und Methodendeklarationen basierend auf der Symboltabelle in der Mach-O-Datei analysieren.
~ » ./class-dump -H -o /header/path WeChat
Nach dem Exportieren der Header-Dateien ziehen Sie diese Header-Dateien in ein XCode-Projekt, um nachfolgende Suchvorgänge zu erleichtern.
Nachdem Sie die Header-Datei haben, müssen Sie sie an die Controller-Klasse der relevanten Schnittstelle binden. Verwenden Sie OpenSSH, um eine Verbindung zum iPhone mit Jailbreak mit Mac herzustellen, verwenden Sie Cycript, um den Prozess einzuschleusen, rufen Sie die Methode [[UIApp keyWindow] recursiveDescription]
auf, um die Hierarchie der aktuellen Ansicht abzurufen, rufen Sie die Adresse einer Ansicht ab und rufen Sie wiederholt die Methode [#0x2b2b2b00 nextResponder]
-Methode erhalten Sie schließlich die Interface-Controller-Klasse.
An diesem Punkt gibt es im Allgemeinen zwei Einstiegspunkte, um die umgekehrte Analyse fortzusetzen.
Wenn wir möchten, dass die Hook-Operation durch das Berührungsereignis einer Ansicht auf der Benutzeroberfläche ausgelöst wird, gibt es im Allgemeinen zwei Möglichkeiten, die Aktion zu lokalisieren:
[button allTargets]
auf, um die Targets-Adresse abzurufen, [button actionsForTarget: Targets forControlEvent: [button allControlEvents]]
um die entsprechende Aktionsmethode abzurufen.Beim Schreiben des Plug-Ins kann die Datenquelle des Controllers verwendet werden. Die Datenquelle kann durch Analyse der Mitgliedsvariablenliste der Controller-Klasse oder durch Analyse der Datenquellen-Proxy-Methode einiger Ansichten (z. B. TableView) ermittelt werden. Mit einer Datenquelle können umfassendere Informationen über den Controller abgerufen werden.
Ein einfaches Plug-in kann das Ziel möglicherweise nur mit Cycript sperren und einbinden, aber in vielen Fällen verfügt die Zielfunktion über mehrere Parameter und die Logik ist relativ komplex. Wenn Sie die Details ihrer internen Implementierung kennen möchten, müssen Sie dies tun Verwenden Sie das statische Analyseartefakt IDA ---- Es kann in Objective-C geschriebenen Code in Assemblercode dekompilieren, und die Implementierungsdetails der Funktion sind auf einen Blick klar. Bei der Analyse der Zerlegungsergebnisse ruft der allgemeine Nachrichtenversand aufgrund der Nachrichtenübermittlungseigenschaften von Objective-C tatsächlich die Funktion objc_msgSend
auf. Denken Sie einfach an die Bedeutung jedes Parameters von objc_msgSend
und die Aufrufkonvention der ARM-Architektur, und Sie können den Funktionsaufruf erfolgreich aus dem Assemblycode wiederherstellen. Die Aufrufkonvention besteht darin, dass die ersten vier Parameter der Funktion mithilfe der allgemeinen Register R0–R3 übergeben werden, weitere Parameter auf den Stapel verschoben werden und der Rückgabewert im R0-Register gespeichert wird. Dann entspricht [aObject aMessage: arg1];
objc_msgSend(aObject, aMessage, arg1);
R0 speichert die Empfängeradresse der Nachricht, R1 speichert den Selektor und R2 speichert die erste Parameteradresse. Das Nachrichtenformat für weitere Parameter ist wie folgt:
objc_msgSend(R0, R1, R2, R3, *SP, *(SP + sizeOfLastArg), …)
Durch das obige Format kann die Logik in einer bestimmten Funktion Schritt für Schritt analysiert werden. Wenn dies durch das dynamische Einzelschritt-Debugging und das Breakpoint-Tracking-Debugging von LLDB an der Adresse einer bestimmten Assembly-Anweisung ergänzt wird, hilft dies, die Details der Funktionsimplementierung zu verstehen.
Es gibt viele Lösungen für die Hook-Zielfunktion, aber im Prinzip basieren sie alle auf den dynamischen Eigenschaften von Objective-C und verwenden Method Swizzling, um die ursprüngliche Implementierung zu ersetzen. Dieses Mal werden wir die Verwendung der CaptainHook-Bibliothek im Detail vorstellen. Diese Bibliothek ist basierend auf MSHookMessageEx()
in Cydia Substrate implementiert. Die Deklaration dieser Funktion lautet:
void MSHookMessageEx(Class _class, SEL message, IMP hook, IMP *old);
Nachdem iOSOpenDev installiert wurde, können Sie die CaptainHook Tweak-Vorlage verwenden, um ein Projekt zu erstellen. Die CaptainHook-Bibliothek führt eine neue Syntax zum Schreiben von Hook-Funktionen ein. Laden Sie zunächst die Klasse, in der sich die einzubindende Funktion in CHConstructor()
befindet, z. B. CHLoadLateClass(UIView)
. Registrieren Sie dann die Funktion CHHook(argNumber, className, arg1, arg2)
als Hooked. Die Makrodefinition von CHConstructor
lautet wie folgt:
#define CHConcat(a, b) CHConcat_(a, b)
#define CHConstructor static __attribute__((constructor)) void CHConcat(CHConstructor, __LINE__)()
Der Inhalt nach __attribute__((constructor))
wird garantiert ausgeführt, wenn die Dylib geladen wird, normalerweise beim Start des Programms. In ähnlicher Weise werden andere Symbole durch Makrodefinitionen eingeführt.
Lassen Sie mich vorstellen, wie Sie mit CaptainHook die Hook-Funktion deklarieren und direkt in den Code implementieren.
CHDeclareClass ( BXViewController );
CHOptimizedMethod ( 0 , self , void , BXViewController , viewDidLoad ) {
CHSuper ( 0 , BXViewController , viewDidLoad );
/* HERE TO WRITE YOUR CODE */
}
CHDeclareMethod0 ( void , BXViewController , addFriends ) {
/* HERE TO WRITE YOUR CODE */
}
Nachdem der Schreibvorgang abgeschlossen ist, stellen Sie zum Kompilieren eine Verbindung zum vorhandenen iPhone her, um sicherzustellen, dass eine der Architektur entsprechende dynamische Bibliothek generiert wird.
Verwenden Sie das Tool yololib, um die kompilierte Dylib-Datei in die Liste der Ladebefehle der ausführbaren Mach-O-Datei einzufügen.
~ » ./yololib [binary] [dylib file]
Die Struktur von Mach-O-Dateien besteht hauptsächlich aus drei Teilen. Der Front-End-Teil ist die Header-Struktur, in der der Plattformtyp, der Dateityp, die Anzahl der LoadCommands und andere Informationen gespeichert werden. Durch das Parsen dieses Teils wird die logische Struktur der Datei gespeichert Sein Speicherort in der virtuellen Datei kann bestimmt werden. Das yololib-Tool ändert die Informationen im Abschnitt „Ladebefehle“, um dylib zu laden. Der spezifische Implementierungsprozess ist wie folgt:
Da sich die Informationen zu den Ladebefehlen ändern, ändern sich sowohl ncmds als auch sizeofcmds in der entsprechenden Header-Struktur. Daher muss zuerst der Header geändert werden:
// 取出 Header
fseek(newFile, top, SEEK_SET);
struct mach_header mach;
fread(&mach, sizeof(struct mach_header), 1, newFile);
NSData* data = [DYLIB_PATH dataUsingEncoding:NSUTF8StringEncoding];
// 计算 dylib 的大小
uint32_t dylib_size = (uint32_t)[data length] + sizeof(struct dylib_command);
dylib_size += sizeof(long) - (dylib_size % sizeof(long));
// 修改 cmds 和 sizeofcmds
mach.ncmds += 1;
uint32_t sizeofcmds = mach.sizeofcmds;
mach.sizeofcmds += dylib_size;
// 写回修改后的 Header
fseek(newFile, -sizeof(struct mach_header), SEEK_CUR);
fwrite(&mach, sizeof(struct mach_header), 1, newFile);
Ändern Sie dann den Abschnitt „Ladebefehle“ und fügen Sie Dylib-Ladeinformationen hinzu:
fseek(newFile, sizeofcmds, SEEK_CUR);
// 创建一个 dylib 类型的 command
struct dylib_command dyld;
fread(&dyld, sizeof(struct dylib_command), 1, newFile);
// 修改 dyld 结构体数据
dyld.cmd = LC_LOAD_DYLIB;
dyld.cmdsize = dylib_size;
dyld.dylib.compatibility_version = DYLIB_COMPATIBILITY_VERSION;
dyld.dylib.current_version = DYLIB_CURRENT_VER;
dyld.dylib.timestamp = 2;
dyld.dylib.name.offset = sizeof(struct dylib_command);
// 写回修改
fseek(newFile, -sizeof(struct dylib_command), SEEK_CUR);
fwrite(&dyld, sizeof(struct dylib_command), 1, newFile);
Die letzten in Dylib geschriebenen Daten.
fwrite([data bytes], [data length], 1, newFile);
Verwenden Sie den Befehl codesign
, um die generierte dynamische Bibliothek und alle ausführbaren Dateien in der APP (einschließlich der APP-Erweiterung im Plugin-Ordner) neu zu signieren. Verwenden Sie den Befehl xcrun -sdk iphoneos PackageApplication -v
um die dynamische Bibliothek und alle Dateien zusammenzupacken. Sie werden den gesamten Prozess verstehen. Wenn ein Unternehmenszertifikat vorhanden ist, kann die signierte und verpackte Anwendung auf einem iPhone ohne Jailbreak installiert werden, das dem Zertifikat vertraut. Ein Ruderstar!