4、 ViewDebug、LLDB、class-dump分析微信登录页面
Step 1 ViewDebug
XCode跑起微信之后,跳转到登录页面,利用ViewDebug查看具体的详细的UI
可以看到,登录按钮是一个FixTitleColorButton对象,他的Target的名字存在地址0x280afaa40中,他的Action名字存在地址0x280afac00中。 用同样的方法查看账号密码的输入框,会发现他们都属于一个对象,叫做WCUITextField
Step 2 LLDB
利用LLDB查看登录按钮具体的Target和Action名称
得知: 登录按钮处于WCAccountMainLoginViewController这个页面之中 登录按钮的点击方法叫做onNext
Step 3 class-dump
class-dump,是可以把Objective-C运行时的声明的信息导出来的工具。其实就是可以导出.h文件。用class-dump可以把未经加密的app的头文件导出来。
点击这下载命令行工具:class-dump 提取码:v5ku 同样的,将class-dump拷贝到Mac的目录/usr/local/bin下,这样我们在终端中就可以使用class-dump命令了
运行命令将WeChat所有的头文件导出来。
// class-dump -H 「app的MachO文件」 -o 「输入的目录」
class-dump -H WeChat -o /Users/dengbin/Code/GitHub/HookWeChat/InjectFrameWork/APP/WeChat-H
Step 4 找到输入框里面的内容
利用文本工具,例如Sublime查看WeChat的头文件,找到前面发现的WCAccountMainLoginViewController
发现里面确实有方法
- (void)onNext;
,还有长得很像账号输入框,密码输入框的对象_textFieldUserNameItem
,_textFieldUserPwdItem
。
接下来就是找到密码输入框里面的字符串了,可以发现这两个都是WCAccountTextFieldItem对象,所有我们继续在导出的文件里面找到WCAccountTextFieldItem
在其中只发现一个tips对象m_labelTip,没有发现对应的textfiled,但是可以看到WCAccountTextFieldItem是继承于WCBaseTextFieldItem的,所以继续查找WCBaseTextFieldItem
从这就可以看到一个m_textField对象,这是个WCUITextField对象,疑似我们的目标textField,继续查看WCUITextField
果然,这就是一个UITextField文件,那么我们就可以通过text字段取出其string。
接下来在用LLDB试试看,验证下我们的猜想:
随便在账号栏输入:qwerty
然后在密码栏输入:123456
po [(WCAccountMainLoginViewController *)0x1128bbc00 valueForKey:@"_textFieldUserPwdItem"]
po [(WCAccountTextFieldItem *)0x28328e880 valueForKey:@"m_textField"]
po [(WCUITextField *)0x112163a00 text]
其中第一个地址0x1128bbc00是在前两部利用ViewDubg找到的。
可以发现最后确实找到了我们输入的密码
123456
,证明我们的分析是正确的。
5、Hook登录,自动获取密码
接下来又是代码Coding了。原理分析完,其实代码就很简单了,直接上代码:
+ (void)load {
NSLog(@"来了,老弟😁");
Method onNext = class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), sel_registerName("onNext"));
//1.保存原始的IMP
old_onNext = method_getImplementation(onNext);
//2.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)];
NSString *accountTF = [[[self valueForKey:@"_textFieldUserNameItem"] valueForKey:@"m_textField"] performSelector:@selector(text)];
NSLog(@"密码是!%@",pwd);
// 将密码追加在账号栏的后面
[[[self valueForKey:@"_textFieldUserNameItem"] valueForKey:@"m_textField"] performSelector:@selector(setText:) withObject:[NSString stringWithFormat:@"%@+%@",accountTF,pwd]];
//调用原来的方法
old_onNext(self,_cmd);
}
稍微解释一下,在前面我们发现登录的响声事件是onNext,所有我们利用Objective-C的Runtime特性,对onNext进行方法替换,在响应原有的onNext之前,我们加上我们自己的方法,比如代码中的,在账号栏中直接输入密码。
运行后结果如图:
我这用的是setIMP和getIMP的方式,对原方法进行HOOK,其实方法有多种:如:
class_replaceMethod()
,method_exchangeImplementations()
,这里只是举一个例子供大家参考。
这篇文章的所有代码都可以在这下载到:HookWeChat
6、总结:
- 先对APP重签名,让APP能在XCode运行起来
- 利用yololib注入Framework,让APP可以运行我们直接的代码
- 利用ViewDebug、LLDB、class-dump分析登录事件和密码框所在位置
- 利用Runtime的MethodSwizzle,Hook登录事件
这次只是简单的微信的一个静态页面进行了初步接触,虽然思路简单,但这运用到的工具,却是无数大神前辈们为我们铺好的路,感谢!
MachO文件在本文中只是初略的提及,其实在我们逆向过程中MachO是一个至关重要的存在,如:
- 对app的砸壳,其实就是对MachO解密
- 所有的方法名,静态字符串都是存在MachO中
- app的架构(arm64,arm7...)也是在MachO中区分的
- app加载其实也是对MachO的一步步操作
- ...
网友评论