Objectif c
(Probablement seulement si compilé avec clang sous 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
Ce code utilise plusieurs astuces pour accéder à la fonction non utilisée. Le premier est la valeur 0x2A27. Il s'agit d'un pointeur balisé pour le nombre entier 42, qui code la valeur dans le pointeur pour éviter d'affecter un objet.
Suivant est MyClass
. Il n'est jamais utilisé, mais le runtime appelle la +load
méthode lorsqu'elle est chargée, avant main
. Cela crée et enregistre dynamiquement une nouvelle classe en utilisant NSValue
comme super-classe. Il ajoute également une +load
méthode pour cette classe, en utilisant MyClass
s -unusedMethod
comme implémentation. Après l’enregistrement, il appelle la méthode de chargement sur la nouvelle classe (pour une raison quelconque, il n’est pas appelé automatiquement).
Étant donné que la méthode de chargement de la nouvelle classe utilise la même implémentation unusedMethod
, elle est effectivement appelée. Il prend la superclasse de lui-même et ajoute unusedFunction
une implémentation pour la doesNotRecognizeSelector:
méthode de cette classe . Cette méthode était à l'origine une méthode d'instance MyClass
, mais elle est appelée en tant que méthode de classe sur la nouvelle classe, de même que self
le nouvel objet de classe. Par conséquent, la super-classe est NSValue
, qui est également la super-classe de NSNumber
.
Enfin, main
court. Il prend la valeur du pointeur et la colle dans une NSString *
variable (la __bridge
première et la première conversion void *
permettant son utilisation avec ou sans ARC). Ensuite, il tente d’appeler stringByAppendingString:
cette variable. Puisqu'il s'agit en fait d'un nombre qui n'implémente pas cette méthode, la doesNotRecognizeSelector:
méthode est appelée à la place, qui parcourt la hiérarchie des classes jusqu'à NSValue
son implémentation unusedFunction
.
Remarque: l'incompatibilité avec d'autres systèmes est due à l'utilisation du pointeur étiqueté, qui, à mon avis, n'a pas été implémentée par d'autres implémentations. Si cela était remplacé par un nombre normalement créé, le reste du code devrait fonctionner correctement.