iOS逆向与安全2.3:代码注入Hook方式

Method Swizzle

利用OC的Runtime特性,动态改变SEL(方法编号)和IMP(方法实现)的对应关系,达到OC方法调用流程改变的目的。主要用于OC方法。

在OC中,SEL 和 IMP之间的关系,就好像一本书的“目录”。
SEL 是方法编号,就像“标题”一样。
IMP是方法实现的真实地址,就像“页码”一样。
他们是一一对应的关系

Runtime提供了交换两个SEL和IMP对应关系的函数.


image.png
iOS逆向与安全2.3:代码注入Hook方式_第1张图片
image.png
iOS逆向与安全2.3:代码注入Hook方式_第2张图片
image.png

通过这个函数交换两个SEL和IMP对应关系的技术,我们称之为Method Swizzle(方法欺骗)

class_addMethod方式:

  • 利用AddMethod方式,让原始方法可以被调用,不至于因为找不到SEL而崩溃

class_addMethod 参数:
class_addMethod(Class _Nullable __unsafe_unretained cls, <#SEL _Nonnull name#>, <#IMP _Nonnull imp#>, <#const char * _Nullable types#>)
<#SEL _Nonnull name#>:ClassName
<#IMP _Nonnull imp#> :IMP 方法编号
<#const char * _Nullable types#>):方法类型(返回值+参数):比如"V@:",可通过method_getTypeEncoding(Method)来获得

class_replaceMethod方式:

  • 利用class_replaceMethod,直接给原始的方法替换IMP

method_setImplementation方式:

  • 利用method_setImplementation,直接重新赋值原始的新的IMP
+(void)load{
    //原始的Method
    old_onNext = method_getImplementation(class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext)));
    class_replaceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext), new_onNext, "v@:");
       
 
}
IMP (*old_onNext)(id self,SEL _cmd);
//新的IMP
void new_onNext(id self,SEL _cmd)
{
    //拿出用户密码!
    UITextField * pwd = [[self valueForKey:@"textFieldUserPwdItem"] valueForKey:@"m_textField"];
    NSLog(@"密码是:%@",pwd.text);
    old_onNext(self,_cmd);
}

BOOL best_Swizzle(Class aClass, Class bClass,SEL originalSel,SEL swizzleSel){
    
    Method originalMethod = class_getInstanceMethod(aClass, originalSel);
    Method swizzleMethod = class_getInstanceMethod(bClass, swizzleSel);
    BOOL didAddMethod = class_addMethod(aClass, originalSel, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
    if (didAddMethod) {
        class_replaceMethod(aClass, swizzleSel, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    }else{
        method_exchangeImplementations(originalMethod, swizzleMethod);
    }
    
    return YES;
}
example
  • 方法交换
+(void)load{

//获取原方法
  Method URLWithStr = class_getClassMethod(self, @selector(URLWithString:));
    
//新方法
    Method LHURL = class_getClassMethod(self, @selector(LHURLWithStr:));
    
    //交换
    method_exchangeImplementations(URLWithStr, HKURL);
}

+(instancetype)LHURLWithStr:(NSString *)str{
    //调用系统原来的方法
    NSURL * url = [NSURL LHURLWithStr:str];
    if (url == nil) {
       str = [str stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    }
    url = [NSURL HKURLWithStr:str];
    
    return url;
}


调试方法

通过地址对象方法的调用
[(ClassName*)0x999999999  method];

通过对象方法的调用
//从textField中取text
NSString *textString = [[[self valueForKey:@"_textFieldUserPwdItem"] valueForKey:@"m_textField"] performSelector:@selector(text)];

###
添加新方法
+(void)load{

  //1.拿到原始的Method
    Method onNext = class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), sel_registerName("onNext"));
//2.添加新的方法
  BOOL didAdd = class_addMethod(object_getClass(@"ClassName"), @selector(new_onNext), my_next, "V@:");

//3.获取到添加的新方法
 Method newOnNext = class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), sel_registerName("new_onNext"));

//4.交换
    method_exchangeImplementations(onNext, newOnNext);

}

void my_next(id self,SEL _cmd){
    NSString * pwd = [[[self valueForKey:@"_textFieldUserPwdItem"]valueForKey:@"m_textField"] performSelector:@selector(text)];
    NSLog(@"密码是!%@",pwd);//获取到密码
    //调用原来的方法

[self performSelector:@seleceor(new_onNest)];
}

###替换方法
+(void)load{

  //1.拿到原始的Method
    Method onNext = class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), sel_registerName("onNext"));

//保存原始IMP 
  old_onNext = method_getImplementation(onNext);

//3.替换方法

 class_replaceMethod(objc_getClass("WCAccountMainLoginViewController"),  @selector(onNext), my_next, "v@:");
}

IMP (*old_onNext)(id self,SEL _cmd);

void my_next(id self,SEL _cmd){
    NSString * pwd = [[[self valueForKey:@"_textFieldUserPwdItem"]valueForKey:@"m_textField"] performSelector:@selector(text)];
    NSLog(@"密码是!%@",pwd);//获取到密码
    //调用原来的方法
old_onNext(self,_cmd);
}

### set方法
+(void)load{

  //1.拿到原始的Method
    Method onNext = class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), sel_registerName("onNext"));

//保存原始IMP 
  old_onNext = method_getImplementation(onNext);

//3.set方法
    method_setImplementation(onNext, (IMP)my_next);

}

IMP (*old_onNext)(id self,SEL _cmd);

void my_next(id self,SEL _cmd){
    NSString * pwd = [[[self valueForKey:@"_textFieldUserPwdItem"]valueForKey:@"m_textField"] performSelector:@selector(text)];
    NSLog(@"密码是!%@",pwd);//获取到密码
    //调用原来的方法
old_onNext(self,_cmd);
}

你可能感兴趣的:(iOS逆向与安全2.3:代码注入Hook方式)