2016-10-01 2 views
7

Ich arbeite an einer statischen Bibliothek, die vertrauliche Daten behandelt. Es ist zwingend erforderlich, dass der Entwickler, der die Bibliothek verwendet, keine Reflektion für die Bibliothek verwenden kann.verhindern Reflexion (Objc/Laufzeit) auf iOS

Auf Android, lösen wir das Problem durch eine aar Datei mit service s Entwicklung und die service in separaten Prozess ausgeführt, (Wenn der Dienst in einem anderen Prozess ausgeführt wird, dann kann der Entwickler nicht Reflexion verwenden), aber ich frage mich, ob etwas Ähnliches existiert in iOS?

Können wir eine statische Bibliothek in einen separaten Prozess ausführen? Wenn nicht, wie können wir Reflexionen über unsere statischen Bibliotheken vermeiden?

Zum Beispiel:

 MyTestObject *obj = [[[myTestView alloc] init ]; 

     //=========================================== 

     Class clazz = [obj class]; 
     u_int count; 
     Ivar* ivars = class_copyIvarList(clazz, &count); 
     NSMutableArray* ivarArray = [NSMutableArray arrayWithCapacity:count]; 
     for (int i = 0; i < count ; i++) 
     { 
      const char* ivarName = ivar_getName(ivars[i]); 
      [ivarArray addObject:[NSString stringWithCString:ivarName encoding:NSUTF8StringEncoding]]; 
     } 
     free(ivars); 

     objc_property_t* properties = class_copyPropertyList(clazz, &count); 
     NSMutableArray* propertyArray = [NSMutableArray arrayWithCapacity:count]; 
     for (int i = 0; i < count ; i++) 
     { 
      const char* propertyName = property_getName(properties[i]); 
      [propertyArray addObject:[NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]]; 
     } 
     free(properties); 

     Method* methods = class_copyMethodList(clazz, &count); 
     NSMutableArray* methodArray = [NSMutableArray arrayWithCapacity:count]; 
     for (int i = 0; i < count ; i++) 
     { 
      SEL selector = method_getName(methods[i]); 
      const char* methodName = sel_getName(selector); 
      [methodArray addObject:[NSString stringWithCString:methodName encoding:NSUTF8StringEncoding]]; 
     } 
     free(methods); 

     NSDictionary* classDump = [NSDictionary dictionaryWithObjectsAndKeys: 
            ivarArray, @"ivars", 
            propertyArray, @"properties", 
            methodArray, @"methods", 
            nil]; 

     NSLog(@"%@", classDump); 

     //====================================================== 

     int v2 = [[obj valueForKey:@"testValue"] intValue]; 

     SEL s = NSSelectorFromString(@"wannatTestIt"); 
     [obj performSelector:s]; 

MyTestObject ist eine Klasse aus meiner Bibliothek. In der ersten Zeile initialisiere ich ein Objekt aus dieser Klasse.

In der nächsten Zeile lese ich die Variablen, Methoden und Eigenschaftenliste der Klasse und protokolliere sie. Hier ist das Ergebnis:

{ 
    ivars =  (
     testValue 
    ); 
    methods =  (
     printTestValue, 
     wannatTestIt, 
     "initWithFrame:" 
    ); 
    properties =  (
    ); 
} 

wannaTestIt ist eine private Methode und testValue ist eine private Variable. Ich erwarte daher, dass der Entwickler, der die Bibliothek verwendet, nicht darauf zugreifen kann. Da der Benutzer der Bibliothek jedoch den Namen abrufen kann, kann der Benutzer die Methode schließlich aufrufen, um den Wert der iVar zu lesen.

Wie kann ich das verhindern?

Antwort

5

Wenn Sie Reflexion vollständig "verhindern" wollen, dann müssen Sie eine andere Sprache verwenden. In Objective C ist Reflection ein Schlüsselelement und es ist nicht möglich, es zu "blockieren" oder "zu deaktivieren".

Sie können diese Laufzeitinformationen für den Forscher jedoch viel weniger nützlich machen, indem Sie sie verschleiern. Schauen Sie sich beispielsweise dieses Tool an: https://github.com/Polidea/ios-class-guard. Dies ist nur ein Beispiel. Ich bin nicht mit diesem speziellen Projekt verbunden und Sie können einen anderen Obfuscator frei wählen oder Ihren eigenen schreiben.

Wenn das, was Sie brauchen, ist nur Reflexion für die öffentliche API zu begrenzen und sogar eine Reihe von privaten Methoden und ivars (ohne ihre tatsächlichen Namen) Offenlegung ist nicht in Ordnung, wenn Sie dann haben Sie keine andere Wahl haben, als Sie sensible Code schreiben in einer anderen Sprache. Sie können Pimpl Designmuster verwenden, um zu erreichen, was Sie wollen. Auf diese Weise würden Ihre Klassen nur öffentliche Methoden und einen einzigen privaten ivar _impl (oder etwas ähnliches) haben. Dabei ist _impl eine Instanz der Implementierungsklasse, die in C++ geschrieben ist (oder Objective C++, wenn Sie Zugriff auf ObjC-APIs benötigen), und alle öffentlichen Methoden verhalten sich wie ein Proxy. Etwas wie folgt aus:

- (NSInteger)computeSuperSensitiveStuffWithFoo:(Foo *)foo Bar:(Bar *)bar { 
    return _impl->computeStuff(foo, bar); 
} 

Auf diese Weise alle Ihre privaten Daten und Methoden würden in der MyClassImpl Klasse gekapselt werden. Wenn Sie die Deklaration und Implementierung einer solchen Klasse privat halten (d. H. Keine MyClassImpl.h Datei mit Ihrer Bibliothek verteilen) und eine Sprache wie C++ verwenden, um sie zu implementieren, dann werden Sie erreichen, was Sie wollen.

Beachten Sie auch, dass, wenn Sie Objective C++ wählte dann MyClassImpl eine C++ Klasse sein sollte (deklariert mit class Schlüsselwort) und nicht Objective C-Klasse (deklariert mit @interface/@end Block und implementiert innerhalb @implementation/@end Block).Ansonsten stehen Ihnen alle privaten Daten ohnehin zur Reflektion zur Verfügung, aber es würde noch ein paar zusätzliche Schritte vom Forscher erfordern.

+0

meine Bibliothek haben uiviewcontrollers auch. Können wir Codes mit C++ entwickeln, die auch uiviewcontrollers unterstützen? –

+0

@HuseinBehboodiRad, sicher. Keine Änderungen für UIViewControllers erforderlich. Erstellen Sie einfach eine gewöhnliche 'UIViewController'-Unterklasse (zB' MyViewController'), erstellen Sie eine in Objective C++ geschriebene Implementierungsklasse (zB 'MyVCImpl'). Und mache genau die gleichen Dinge, die ich in meiner Antwort beschrieben habe. In 'MyViewController' fügen Sie' _impl' ivar hinzu, das auf die Instanz von 'MyVCImpl' zeigt. Proxy alle öffentlichen Methoden zu "_impl" und behalten Sie alle privaten Methoden/Felder in 'MyVCImpl'. Sie können 'self' an den Konstruktor von' MyVCImpl' übergeben, um Zugriff auf den eigentlichen View-Controller aus dem Inneren der Implementierungsklasse zu erhalten. –