Cel C
(Prawdopodobnie tylko jeśli jest skompilowany z clang na Mac OS X)
#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
Ten kod wykorzystuje kilka sztuczek, aby dostać się do nieużywanej funkcji. Pierwsza to wartość 0x2A27. Jest to oznakowany wskaźnik dla liczby całkowitej 42, który koduje wartość we wskaźniku, aby uniknąć przydzielenia obiektu.
Dalej jest MyClass. Nigdy nie jest używany, ale środowisko wykonawcze wywołuje +loadmetodę po jej załadowaniu, wcześniej main. To dynamicznie tworzy i rejestruje nową klasę, wykorzystując NSValuejako jej nadklasę. Dodaje również +loadmetody dla tej klasy, używając MyClass„s -unusedMethodjak wdrożenie. Po rejestracji wywołuje metodę load na nowej klasie (z jakiegoś powodu nie jest wywoływana automatycznie).
Ponieważ metoda ładowania nowej klasy wykorzystuje tę samą implementację co unusedMethod, jest to skutecznie wywoływane. Pobiera samą nadklasę i dodaje unusedFunctionjako implementację doesNotRecognizeSelector:metody tej klasy . Ta metoda była pierwotnie metodą instancji MyClass, ale jest wywoływana jako metoda klasy w nowej klasie, podobnie selfjak obiekt nowej klasy. W związku z tym nadklasa jest NSValue, która jest również nadklasą NSNumber.
Wreszcie maindziała. Pobiera wartość wskaźnika i umieszcza ją w NSString *zmiennej ( __bridgei pierwszy rzut, aby void *umożliwić użycie z ARC lub bez). Następnie próbuje wywołać stringByAppendingString:tę zmienną. Ponieważ w rzeczywistości jest to liczba, która nie implementuje tej metody, doesNotRecognizeSelector:metoda jest wywoływana zamiast niej, która przechodzi przez hierarchię klas do miejsca, w NSValuektórym jest implementowana unusedFunction.
Uwaga: niekompatybilność z innymi systemami wynika z użycia oznakowanego wskaźnika, który, jak sądzę, nie został zaimplementowany przez inne implementacje. Jeśli zostałby zastąpiony normalnie utworzoną liczbą, reszta kodu powinna działać poprawnie.