Ziel c
(Wahrscheinlich nur, wenn unter Mac OS X mit Clang kompiliert)
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
void unusedFunction(void) {
printf("huh?\n");
exit(0);
}
int main() {
NSString *string;
string = (__bridge id)(void*)0x2A27; // Is this really valid?
NSLog(@"%@", [string stringByAppendingString:@"foo"]);
return 0;
}
@interface MyClass : NSObject
@end
@implementation MyClass
+ (void)load {
Class newClass = objc_allocateClassPair([NSValue class], "MyClass2", 0);
IMP imp = class_getMethodImplementation(self, @selector(unusedMethod));
class_addMethod(object_getClass(newClass), _cmd, imp, "");
objc_registerClassPair(newClass);
[newClass load];
}
- (void)unusedMethod {
Class class = [self superclass];
IMP imp = (IMP)unusedFunction;
class_addMethod(class, @selector(doesNotRecognizeSelector:), imp, "");
}
@end
Dieser Code verwendet mehrere Tricks, um zur nicht verwendeten Funktion zu gelangen. Erstens ist der Wert 0x2A27. Dies ist ein markierter Zeiger für die Ganzzahl 42, die den Wert im Zeiger codiert, um die Zuweisung eines Objekts zu vermeiden.
Weiter ist MyClass
. Es wird nie verwendet, aber die Laufzeit ruft die +load
Methode beim Laden vorher auf main
. Dadurch wird dynamisch eine neue Klasse erstellt und registriert, die NSValue
als Oberklasse verwendet wird. Es wird auch eine +load
Methode für diese Klasse hinzugefügt, die MyClass
's -unusedMethod
als Implementierung verwendet. Nach der Registrierung wird die load-Methode für die neue Klasse aufgerufen (aus irgendeinem Grund wird sie nicht automatisch aufgerufen).
Da die Lademethode der neuen Klasse dieselbe Implementierung wie verwendet unusedMethod
, wird dies effektiv aufgerufen. Es nimmt die Superklasse von sich und fügt sie unusedFunction
als Implementierung für die doesNotRecognizeSelector:
Methode dieser Klasse hinzu . Diese Methode war ursprünglich eine Instanzmethode von MyClass
, wird jedoch als Klassenmethode für die neue Klasse aufgerufen, ebenso wie self
das neue Klassenobjekt. Daher ist die Superklasse NSValue
, für die auch die Superklasse ist NSNumber
.
Endlich main
läuft. Es nimmt den Zeigerwert und speichert ihn in einer NSString *
Variablen (die __bridge
und erste Umwandlung, void *
um dies mit oder ohne ARC zu ermöglichen). Dann wird versucht, stringByAppendingString:
diese Variable aufzurufen . Da es sich tatsächlich um eine Zahl handelt, die diese Methode nicht implementiert, doesNotRecognizeSelector:
wird stattdessen die Methode aufgerufen, die durch die Klassenhierarchie dahin wandert, NSValue
wo sie mit implementiert wird unusedFunction
.
Hinweis: Die Inkompatibilität mit anderen Systemen ist auf die Verwendung von getaggten Zeigern zurückzuführen, die meines Erachtens nicht von anderen Implementierungen implementiert wurden. Wenn dies durch eine normal erstellte Nummer ersetzt wird, sollte der Rest des Codes einwandfrei funktionieren.