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 +load
metodę po jej załadowaniu, wcześniej main
. To dynamicznie tworzy i rejestruje nową klasę, wykorzystując NSValue
jako jej nadklasę. Dodaje również +load
metody dla tej klasy, używając MyClass
„s -unusedMethod
jak 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 unusedFunction
jako implementację doesNotRecognizeSelector:
metody tej klasy . Ta metoda była pierwotnie metodą instancji MyClass
, ale jest wywoływana jako metoda klasy w nowej klasie, podobnie self
jak obiekt nowej klasy. W związku z tym nadklasa jest NSValue
, która jest również nadklasą NSNumber
.
Wreszcie main
działa. Pobiera wartość wskaźnika i umieszcza ją w NSString *
zmiennej ( __bridge
i 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 NSValue
któ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.