Objective-C
(Вероятно, только если скомпилировано с Clang на 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
Этот код использует несколько приемов, чтобы добраться до неиспользуемой функции. Во-первых, это значение 0x2A27. Это помеченный указатель для целого числа 42, который кодирует значение в указателе, чтобы избежать выделения объекта.
Дальше есть MyClass
. Он никогда не используется, но среда выполнения вызывает +load
метод при его загрузке ранее main
. Это динамически создает и регистрирует новый класс, используя NSValue
его как суперкласс. Он также добавляет +load
метод для этого класса, используя MyClass
«S в -unusedMethod
качестве реализации. После регистрации он вызывает метод load для нового класса (по некоторым причинам он не вызывается автоматически).
Так как метод загрузки нового класса использует ту же реализацию unusedMethod
, что и, он эффективно вызывается. Он берет суперкласс сам по себе и добавляет unusedFunction
в качестве реализации doesNotRecognizeSelector:
метод этого класса . Этот метод изначально был методом экземпляра MyClass
, но вызывается как метод класса для нового класса, так же self
как и новый объект класса. Следовательно, суперкласс есть NSValue
, который также является суперклассом для NSNumber
.
Наконец-то main
работает. Он принимает значение указателя и помещает его в NSString *
переменную ( __bridge
и первое приведение, чтобы void *
позволить использовать его с ARC или без него). Затем он пытается вызвать stringByAppendingString:
эту переменную. Поскольку на самом деле это число, которое не реализует этот метод, doesNotRecognizeSelector:
вместо этого вызывается метод, который перемещается вверх по иерархии классов туда, NSValue
где он реализован с использованием unusedFunction
.
Примечание. Несовместимость с другими системами связана с использованием тегового указателя, который, как я полагаю, не был реализован другими реализациями. Если это было заменено на обычно создаваемый номер, остальная часть кода должна работать нормально.