检查类函数是否被覆盖,一般包含分类覆盖和hook覆盖,这里给出代码快速检测是否被覆盖
1.检测分类函数列表
在要检测的类中引入头文件
#import <objc/runtime.h>
#import <objc/message.h>
在要检测的类中实现如下函数, 并调用进行打印类函数列表(原类 + 分类)
- (void)runTests
{
unsigned int count;
Method *methods = class_copyMethodList([self class], &count);
for (int i = 0; i < count; i++)
{
Method method = methods[i];
SEL selector = method_getName(method);
NSString *name = NSStringFromSelector(selector);
// if ([name hasPrefix:@"test"])
NSLog(@"方法 名字 ==== %@",name);
if (name)
{
//avoid arc warning by using c runtime
// objc_msgSend(self, selector);
}
NSLog(@"Test '%@' completed successfuly", [name substringFromIndex:4]);
}
}
2.检测是否被Hook
方法Hook一般是在Load函数中实现的,所以可以在AppDelegate.m中进行检测
实现如下函数
BOOL isSiwwzledOrOverridden(Class cls, SEL selector) {
NSMutableDictionary *offsetDict = @{}.mutableCopy;
unsigned classCount = 0;
Class *allClasses = objc_copyClassList(&classCount);
for (unsigned classIndex = 0; classIndex < classCount; ++classIndex) {
@autoreleasepool {
Class cls = allClasses[classIndex];
//只管UI NS开头的类
if ([NSStringFromClass(cls) hasPrefix:@"UI"] || [NSStringFromClass(cls) hasPrefix:@"NS"]) {
unsigned methodCount = 0;
Method *methods = class_copyMethodList(cls, &methodCount);
for (unsigned methodIndex = 0; methodIndex < methodCount; ++methodIndex) {
Method mtd = methods[methodIndex];
NSString *mtdString = [NSString stringWithUTF8String:sel_getName(method_getName(mtd))];
//_开头的内部方法忽略
if ([mtdString hasPrefix:@"_"]){
continue;
}
IMP imp = method_getImplementation(mtd);
int offset = (long) cls - (long) imp;
offsetDict[[NSString stringWithFormat:@"[%@ %s]", NSStringFromClass(cls), sel_getName(method_getName(mtd))]] = @(offset);
}
}
}
}
//省略部分代码。。。
if (offsetDict){
NSNumber *num = offsetDict[[NSString stringWithFormat:@"[%@ %s]", NSStringFromClass(cls), sel_getName(selector)]];
if (num == nil){
NSLog(@"Could not find selector!");
return NO;
}
IMP imp = [cls instanceMethodForSelector:selector];
int offset = (long) cls - (long) imp;
if (offset != [num integerValue])
return YES;
}
return NO;
}
然后调用如下函数检查,这里以检查 UIViewController
的 viewDidLoad
方法为例
BOOL ret = isSiwwzledOrOverridden([UIViewController class], @selector(viewDidLoad));
// ret YES 表示被Hook或者被覆盖
// ret NO 表示没有被Hook
网友评论