作者:海浪宝宝
链接:https://juejin.cn/post/6876355054236860429

hook注册按钮

获取target和action

首先我们拿到wechat包放到重签名工程的APP目录中,然后真机运行,运行后我们点击Debug view Hierarchy按钮,也就是下面按钮

旋转一下,然后我们看到我们可以拿到当前页面的图层层级

通过左边的层级,我们选择一下注册按钮,然后在右边侧栏中,可以发现这个按钮的target和action的名字

hook target的action

我们试着hook查询到的target的action方法试下实际上是否和真实的一样

+(void)load{

    NSLog(@"erwerwetwtwetwe");
    //破坏注册!
    Method oldMethod = class_getInstanceMethod(objc_getClass("WCAccountLoginControlLogic"), @selector(onFirstViewRegister));
    Method newMethod = class_getInstanceMethod(self, @selector(HK_onFirstViewRegister));

    method_exchangeImplementations(oldMethod, newMethod);
}

-(void)HK_onFirstViewRegister{

    NSLo***击了注册按钮");
}

然后运行,点击注册按钮,发现打印台上出现了log日志,说明我们hook的就是微信点击注册按钮的方法

获取微信密码

找到密码存储位置

点击方法我们可以hook到,我们来试着获取微信的密码,继续运行工程,然后点击登录按钮进入到登录页面,我们点击一下下一步,进入到输入密码页面,然后再点击Debug view Hierarchy按钮,通过左边的view层级,我们找到对应的密码输入框,发现这个密码输入框是WCUITextField类型的

然后再选择一下登录按钮,发现登录按钮的target和action是 WCAccountNewPhoneVerifyViewController和onNext

但是点击按钮没有参数,我们没法通过hook来拿到密码,这个时候我们就考虑通过kvc来拿密码了

首先登录按钮的target是WCAccountNewPhoneVerifyViewController,我们猜测密码是这个类的一个属性,我们可以通过class-dump来获取ipa包里类的头文件,前提这个ipa包是已经砸过壳的

我们拿到class-dump可执行文件,然后从.app中拿到WeChat的可执行文件放在同一目录,然后终端cd到该目录,通过下面命令就可以拿到WeChat的全部头文件

./class-dump -H WeChat -o ./wechatHeaders/
这样就把wechat包里的头文件都导入到wechatHeaders文件夹了

我们看了一下头文件有一万五千多个,如果都放在XCode,估计会把XCode卡死,所以推荐Sublime Text工具,通过搜索,我们发现WCAccountNewPhoneVerifyViewController下面有一个WCAccountTextFieldItem的对象类似密码对象(即使定义在.m文件的属性和成员变量,我们也能拿到)

我们再找一下WCAccountTextFieldItem类,

发现没啥玩意,再找一下它的父类WCBaseTextFieldItem

在父类里面我们找到了WCUITextField属性,这个就是密码输入框的类,我们再找一下这个类,看看密码是怎么存储的

我们发现这个类就是继承自UITextField的,所以我们直接拿WCUITextField的text属性即可

    //拿出用户的密码
    UITextField * pwd = [[self valueForKey:@"_textFieldUserPwdItem"] valueForKey:@"m_textField"];
    NSLog(@"窃取到用户的密码是%@",pwd.text);

其中self就是WCAccountMainLoginViewController的对象

分析如何拿到密码了,下面我们就通过hook的方式来获取微信的密码

KVC获取密码

首先我们先hook类WCAccountMainLoginViewController的onNext方法


+(void)load{

    NSLog(@"erwerwetwtwetwe");
    //原始微信的登录方法
    Method oldMethod = class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext));
    Method newMethod = class_getInstanceMethod(self, @selector(zjj_onNext));
    method_exchangeImplementations(oldMethod, newMethod);
}

-(void)zjj_onNext{

    NSLo***击了注册按钮");

    [self zjj_onNext];
}

但是我们操作时候发现当点击时候,会报WCAccountMainLoginViewController找不到方法

这是为什么呢?

因为method_exchangeImplementations交换的是方法指针,也就是方法名对应的方法指针当WCAccountMainLoginViewController对象调用onNext方法时候,因为onNext对应的方法实现已经被交换了,就会调用到zjj_onNext里面来,但是当zjj_onNext里面调用zjj_onNext时候,因为self是WCAccountMainLoginViewController对象,但是它里面是没有zjj_onNext方法的,所以就会报错

所以我们要换一种交换方式,也就是先给WCAccountMainLoginViewController添加一个zjj_onNext方法,然后再进行交换

+(void)load{

    NSLog(@"erwerwetwtwetwe");

    //添加新方法
    /**
     * 1、给哪个类添加方法
     * 2、方法编号
     * 3、方法实现(地址)
     */
    //获取函数的指针
    IMP zjj_onNext = [[self new] methodForSelector: @selector(zjj_onNext)];
    //给WCAccountMainLoginViewController添加方法
    BOOL didAddMethod = class_addMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(zjj_onNext), zjj_onNext, "v@:");

    //原始微信的登录方法
    Method oldMethod = class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext));
    //原始微信的登录方法
    Method newMethod = class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(zjj_onNext));
    if (didAddMethod) {
        NSLog(@"交换成功");
        method_exchangeImplementations(oldMethod,newMethod);
    }
}

-(void)zjj_onNext{
    //拿出用户的密码
    UITextField * pwd = [[self valueForKey:@"_textFieldUserPwdItem"] valueForKey:@"m_textField"];
    NSLog(@"窃取到用户的密码是%@",pwd.text);
    [self zjj_onNext];
}

再运行点击:

我们发现我们窃取到了微信的登录密码,拿手机号类似,就不做演示了

拓展

  • 对于方法的本质是一个函数,所谓IMP其实也就是一个函数指针指向函数的实现,
  • 既然方法交换是交换两个方法的函数指针,那么直接点,我自定义格一个函数,然后将要交换的方法的函数指针用我自定义的函数替换掉不就行了吗,
  • 对于原来的函数实现,我在定义一个函数指针指向老的函数实现,然后在自定义的函数实现里面执行以下老的函数,这样是不是也达到交换的目的呢,我们实验一下
+(void)load{

    //保存老的函数体
     old_onNext = method_getImplementation(class_getInstanceMethod(objc_getClass("WCAccountNewPhoneVerifyViewController"), @selector(onNext)));
    //将方法编号onNext对应的函数指针重新set下
    method_setImplementation(class_getInstanceMethod(objc_getClass("WCAccountNewPhoneVerifyViewController"), @selector(onNext)), new_onNext);
}

//指针 ,用来保存老的函数。
IMP (*old_onNext)(id self,SEL _cmd);

//新的函数实现
void new_onNext(id self,SEL _cmd){
    //拿出用户的密码
    UITextField * pwd = [[self valueForKey:@"_textFieldPwdItem"] valueForKey:@"m_textField"];
    NSLog(@"窃取到用户的密码是%@",pwd.text);
    old_onNext(self,_cmd);
}
运行,输入密码,点击登录

完美

文章到这里就结束了,你也可以私信我及时获取最新资料。如果你有什么意见和建议欢迎给我留言。