Schließlich gibt es keine Möglichkeit zu verhindern, dass jemand Ihr Programm entführt, wenn Sie es auf seinem Gerät laufen lassen. Es gibt Möglichkeiten, es schwieriger zu machen, aber es gibt keine Möglichkeit, es unmöglich zu machen.
ich diese großen Möglichkeiten der Injektion von Code in eine Anwendung denken:
- Objective-C-Methoden mit der Laufzeit Swizzling;
- Swizzling virtueller Swift-Methoden durch Analysieren der ausführbaren Datei und Berechnen der richtigen Bits zum Ändern;
- Ändern von Anrufzielen;
- Swizzling importierter Symbole durch Ändern von Stub-Zielen;
- Verwenden von dyld, um Bibliotheken zwangsweise zu laden oder zu ändern, welche Bibliotheken Ihr Programm lädt;
- ersetzt die Bibliotheken, gegen die Ihr Programm verknüpft ist.
Und es gibt keinen 100% effektiver Weg, eine diese in einer Umgebung zu verhindern, dass der Benutzer vollständig kontrolliert. Sie sollten entscheiden, ob Sie sich Sorgen machen oder nicht, abhängig von Ihrem Bedrohungsmodell.
Swizzling Objective-C Laufzeit-Verfahren mit dem
Method Swizzling ist eine Technik, in dem Sie die Implementierung eines Verfahrens zur Laufzeit mit beliebigem, verschiedenem Code zu ändern (in der Regel für einen anderen Zweck). Häufige Anwendungsfälle sind das Umgehen von Prüfungen oder das Protokollieren von Parametern.
Das Swizzling in Objective-C war eine große Sache, weil die Laufzeit Metadaten benötigt, die jede Methode und jedes Instanzfeld identifizieren. Ich kenne keine andere Sprache, die mit dem nativen Maschinencode kompiliert wird und so viele Metadaten enthält. Wenn Sie etwas wie -[AccessControl validatePassword:]
haben, machen Sie es einfach für die bösen Jungs. Mit method_setImplementation
ist dies nur zu betteln.
Da Swift-Klassen von Objective-C-Klassen erben können, ist dies immer noch etwas, worauf Sie achten müssen. Neue Methoden für Klassen, die von einer Objective-C-Klasse erben, werden jedoch nur dann der Objective-C-Laufzeit ausgesetzt, wenn sie das @objc
-Attribut besitzen (oder wenn die Klasse selbst das Attribut @objc
hat), wodurch die Angriffsfläche im Vergleich zu Objective eingeschränkt wird -C.
Darüber hinaus kann der Swift-Compiler die Objective-C-Laufzeit umgehen, um Swift-Methoden aufzurufen, die nicht mit dynamic
markiert wurden, selbst wenn sie mit @objc
markiert wurden.Dies bedeutet, dass Swizzling in einigen Fällen nur für Anrufe möglich ist, die über Objective-C versendet werden.
Und natürlich ist es völlig unmöglich, wenn Ihre Klasse oder Methode der Objective-C-Laufzeit nicht ausgesetzt ist.
Swizzling virtuelle Methoden Swift durch die ausführbare Datei Parsen und die richtigen Bits herauszufinden, müssen Sie die Objective-C-Laufzeit-Implementierungen tauschen Methode nicht jedoch
zu ändern. Swift verfügt weiterhin über virtuelle Tabellen für seine virtuellen Methoden und befindet sich seit Februar 2015 im Segment __DATA
der ausführbaren Datei. Es ist beschreibbar, also sollte es möglich sein, Swift virtuelle Methoden zu swizzle, wenn Sie die richtigen Bits zum Ändern herausfinden können. Es gibt keine praktische API dafür.
C++ - Klassen können ebenfalls geändert werden, aber Swift-Methoden sind standardmäßig virtuell, die Angriffsfläche ist viel größer. Der Compiler kann Methoden als Optimierung devirtualisieren, wenn er keine Überschreibung findet, sich aber auf Compiler-Optimierungen als Sicherheitsfunktion verlässt.
Standardmäßig sind die implementierten Swift-Executables strip ped. Informationen für nicht-public
/open
Symbole werden verworfen, und das macht die Identifizierung der Symbole, die Sie ändern möchten, im Vergleich zu Objective-C viel schwieriger. Public
/open
Symbole werden nicht entfernt, da angenommen wird, dass andere externe Codeclients sie möglicherweise benötigen.
Wenn jedoch jemand herausfindet, welche Funktionsimplementierung er auslagern möchte, muss er lediglich die Adresse der neuen Implementierung in den richtigen virtuellen Tabellensteckplatz schreiben. Sie werden wahrscheinlich ihren eigenen Mach-O-Parser erstellen müssen, aber das ist sicherlich nicht außerhalb der Reichweite der Leute, die Dinge wie Cyclin machen.
Schließlich reduzieren final
Methoden dieses Risiko, da der Compiler sie nicht über die Vtable aufrufen muss. Auch struct
Methoden sind niemals virtuell.
Ändern Rufzielen
Wenn alles andere fehlschlägt, kann der Angreifer immer noch zu Fuß durch Ihre Maschinencode und ändern Sie die bl
oder call
Operanden-Befehl, um überall würden sie besser gefällt. Dies ist komplizierter und ziemlich schwer/unmöglich, mit einer automatisierten Methode 100% richtig zu machen, besonders wenn Symbole fehlen, aber jemand, der genug ist, wird es schaffen. Sie entscheiden, ob jemand es irgendwann für Ihre Bewerbung als lohnend empfinden wird.
Dies funktioniert für virtuelle und nicht-virtuelle Methoden. Es ist jedoch extrem schwierig, dies zu tun, wenn der Compiler Inline aufruft.
Swizzling importierte Symbol Symbole durch Ändern Stub Ziele
importierte Symbol, unabhängig von der Sprache geschrieben es wurde und wird und die Sprache aus verwendet wird ist, ist anfällig für Swizzling. Dies liegt daran, dass externe Symbole zur Laufzeit gebunden sind. Wenn Sie eine Funktion aus einer externen Bibliothek verwenden, generiert der Compiler einen Eintrag in einer Nachschlagetabelle. Dies ist ein Beispiel dafür, was ein Aufruf an fopen
aussehen könnte, wenn Sie die ausführbare Datei in C-Code zurückgegeben:
FILE* locate_fopen(const char* a, const char* b) {
fopen_stub = dyld->locate("fopen"); // find actual fopen and replace stub pointer to it
return fopen_stub(a, b);
}
FILE* (*fopen_stub)(const char*, const char*) = &locate_fopen;
int main() {
FILE* x = fopen_stub("hello.txt", "r");
}
Der erste Aufruf fopen_stub
die tatsächlichen fopen
findet und ersetzt die Adresse mit ihm durch fopen_stub
hingewiesen.Auf diese Weise muss dyld nicht die Tausenden von externen Symbolen auflösen, die von Ihrem Programm und seinen Bibliotheken verwendet werden, bevor es überhaupt gestartet wird. Dies bedeutet jedoch, dass ein Angreifer fopen_stub
durch die Adresse einer Funktion ersetzen kann, die er stattdessen aufrufen möchte. Dies ist, was Ihr CyScript-Beispiel tut.
Kurz von Ihrem eigenen Linker und dynamischen Linker, ist Ihr einziger Schutz gegen diese Art von Angriff, keine geteilten Bibliotheken oder Frameworks zu verwenden. Dies ist keine praktikable Lösung in einer modernen Entwicklungsumgebung, so dass Sie wahrscheinlich damit umgehen müssen.
Es könnte Möglichkeiten geben, sicherzustellen, dass Stubs dorthin gehen, wo Sie sie erwarten, aber es wäre irgendwie flockig, und diese Überprüfungen können immer von einem entschlossenen Angreifer ausgeführt werden nop
. Darüber hinaus können Sie diese Überprüfungen nicht einfügen, bevor Sie über gemeinsam genutzte Bibliotheken keine Kontrolle über importierte Symbole haben. Diese Überprüfungen wären ebenfalls nutzlos, wenn der Angreifer sich dazu entschließen würde, die gemeinsam genutzte Bibliothek einfach durch eine zu ersetzen, die sie kontrollieren.
Nebenbei können Launch-Verschlüsse dyld 3 diese Lookup-Tabellen durch vorgebundene Informationen ersetzen. Ich denke nicht, dass Launch-Closures derzeit schreibgeschützt sind, aber es sieht so aus, als könnten sie irgendwann sein. Wenn dies der Fall ist, werden die Swizzling-Symbole schwieriger.
dyld Verwendung zu erzwingen Last Bibliotheken oder zu ändern, die Ihr Programm lädt Bibliotheken
Dyld supports kraft dem Laden von Bibliotheken in der ausführbaren Datei. Diese Funktion kann verwendet werden, um fast jedes importierte Symbol zu ersetzen, das von der ausführbaren Datei verwendet wird. Mag nicht das normale ? Schreiben Sie eine dylib
, die es neu definiert!
Dyld wird nicht mit dieser Methode zusammenarbeiten, wenn die ausführbare Datei als eingeschränkt markiert ist. Es gibt three ways diesen Status zu erreichen (suchen Sie nach pruneEnvironmentVariables
):
- das setuid Bit oder dem setgid-Bit für die ausführbare Datei ermöglichen;
- mit dem Code signiert sein und die Berechtigung "Nur eingeschränkt eingeschränkt" für OS X haben;
- haben einen Abschnitt namens
__restrict
in einem Segment namens __RESTRICT
.
können Sie erstellen den __restrict
Abschnitt und das __RESTRICT
Segment mit dem folgenden "Other Linker Flags":
-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null
Beachten Sie, dass alle diese ziemlich leicht zu brechen. Die Bits setuid und setgid sind einfach zu löschen, wenn der Benutzer die Ausführungsumgebung steuert, eine Codesignatur kann leicht entfernt werden, und der Abschnitt oder das Segment muss nur umbenannt werden, um den eingeschränkten Status ebenfalls zu entfernen.
die Bibliotheken austauschen, die Ihr Programm Links gegen
Wenn alles andere fehlschlägt, kann ein Angreifer noch die gemeinsamen Bibliotheken ersetzen, die ausführbare Datei verwendet, um es zu tun, was sie wollen. Du hast keine Kontrolle darüber.
tl; dr
in einer Swift Anwendung Injizieren Code ist schwieriger, als es für eine Objective-C-Anwendung, aber es ist immer noch möglich. Die meisten Methoden, die zum Einfügen von Code verwendet werden können, sind sprachunabhängig. Das bedeutet, dass keine Sprache für mehr Sicherheit sorgt.
Zum größten Teil gibt es nichts, was Sie tun können, um sich davor zu schützen. Solange der Benutzer die Ausführungsumgebung steuert, wird Ihr Code auf seinem System als Gast ausgeführt, und er kann damit fast alles machen, was er möchte.
fantastische Aktualisierung Ihrer ursprünglichen Antwort! Vielen Dank. –