Hook微信并截取登录密码-真机实测
2018-12-08 本文已影响878人
co5der
- 在上一篇介绍重签名,并真机进行view debug后, 可以试着一些简单的Hook, 以下是主要操作步骤
- 创建新工程,配置证书啥的,并运行到真机
- 复制appsign.sh脚本,yololib到工程根目录,在工程下,创建APP目录,并拷贝脱壳的ipa包到APP目录(appsign.sh, yololib 需要可执行权限, chmox +x yololib 加权)
- 在TARGET下添加 run script ,添加:${SRCROOT}/appsign.sh
- 运行即可
- 成功后,添加一个framework, 并创建个类, 在load 方法中,打印下log
- 在appsign.sh 添加注入的代码${SRCROOT}/yololib framework路径
- 运行(如果出现image not funded等, 尝试clean后再运行, 成功后,可以看到 load中的打印的log)
- 准备工作:使用class-dump-z 工具,从微信包导出头文件 (class-dump-z -H /xxx/WeChat.app -o /Users/xxx/Desktop/WCHeads)
- 上述操作之后,就可以View Debug了
- 在账号密码登录界面,进行view debug, 可以在xcode 右侧找到密码框,登录按钮的 一些信息,Target <WCAccountMainLoginViewController>, Action onNext (ps: 最新xcode好像只显示类似<__NSDictionaryI: 0x282a71f80>, 那么,可以在 lldb中po出来 )
#通过po找出target等 #(lldb)po 0x282a71f80 { className = NSTaggedPointerString; memoryAddress = 0x8babeb562c16e467; } #(lldb)po po 0x8babeb562c16e467 onNext #(lldb)po 0x2807c5d40 { className = WCAccountMainLoginViewController; memoryAddress = 0x11e0e9400; }
- 通过上面的动态分析,我们可以知道我们要Hook的就是 WCAccountMainLoginViewController 里面的 onNext 方法
- 接下来,我们分析怎么在onNext获取密码,在微信头文件里,我们可以找到文件:WCAccountMainLoginViewController.h 在里面有找到onNext 方法 及 _textFieldUserPwdItem (猜测应该就是密码,不过类型跟UI view debug中 密码输入框: WCUITextField 不大一致)
@interface WCAccountMainLoginViewController : WCAccountBaseViewController <CountryCodePickerDelegate, UITextFieldDelegate, ILinkEventExt> { id<WCAccountMainLoginViewControllerDelegate> _delegate; UIView* _phoneHeaderView; WCAccountTextFieldItem* _textFieldCountryCodeSelectItem; WCAccountTextFieldItem* _textFieldCountryCodeItem; WCAccountTextFieldItem* _textFieldPhoneNumberItem; PhoneNumberFormatLogic* _phoneNumFormatter; CountryCodeWrap* _curCountryCode; UIView* _userHeaderView; WCAccountTextFieldItem* _textFieldUserNameItem; WCAccountTextFieldItem* _textFieldUserPwdItem; //省略部分变量 } //省略部分方法 -(void)onNext;
```
* _textFieldUserPwdItem 类型为WCAccountTextFieldItem, 通过查找微信头文件找到WCAccountTextFieldItem的父类WCBaseTextFieldItem ,里面有变量:WCUITextField* m_textField, m_textField 我们就从者获取密码,可以在 lldb在测试动态获取到
```java
(lldb) po 0x10d961000
<WCAccountMainLoginViewController: 0x10d961000>
(lldb) po [(WCAccountMainLoginViewController *)0x10d961000 valueForKey:@"_textFieldUserPwdItem"]
<WCAccountTextFieldItem: 0x282251a40>
(lldb) po [(WCAccountTextFieldItem *)0x282251a40 valueForKey:@"m_textField"]
<WCUITextField: 0x10d975200; baseClass = UITextField; frame = (20 0; 345 44); text = 'ffggggg'; opaque = NO; tintColor = UIExtendedSRGBColorSpace 0.00784314 0.733333 0 1; gestureRecognizers = <NSArray: 0x2809de250>; layer = <CALayer: 0x2806b12a0>>
(lldb) po [(WCAccountTextFieldItem *)0x282251a40 valueForKey:@"m_textField"].text
error: no known method '-valueForKey:'; cast the message send to the method's return type
(lldb) po [[(WCAccountTextFieldItem *)0x282251a40 valueForKey:@"m_textField"] valueForKey:@"text"]
ffggggg
```
* 动态分析,就到此结束, 下一步就是写hook代码
- Hook编写获取密码代码
#import <objc/runtime.h>
#define USE_3 1 //USE_1 USE_2
@implementation TulipObject
+(void)load
{
NSLog(@"Tulip hook success");
//总体思路:对WCAccountMainLoginViewController 这个对象的onNext hook,valueForKey获取密码
//获取要hook的 class
Class wcClass = objc_getClass("WCAccountMainLoginViewController");
// “v@:" 可以通过帮助里 查找class_addMethod ,查看Type Encodings相关介绍, 也可以用 ""放空白 ,还可以 method_getTypeEncoding(hook_next)
//获取要Hook的 旧的实例method,
//ps: sel_registerName("onNext") == @selector(onNext)
Method old_onNextMethon = class_getInstanceMethod(wcClass, sel_registerName("onNext"));
#ifdef USE_1
/** 方法一: 方法交换 method_exchangeImp */
//添加一个新的方法,用于交换
//新添加sel名
SEL new_onNext = sel_registerName("new_onNext");
BOOL disAddMethod = class_addMethod(wcClass, new_onNext, (IMP)hook_next, "v@:");
if (disAddMethod) {
Method newAddMethod = class_getInstanceMethod(wcClass, new_onNext);
method_exchangeImplementations(old_onNextMethon, newAddMethod);
NSLog(@"method_exchangeImp 实现.");
}
#endif
#ifdef USE_2
/** 方法二: replaceMethod */
//获取原来的IMP
old_onNextImp = method_getImplementation(old_onNextMethon);
//ps: 如果onNext不存在,replace会变成 添加
class_replaceMethod(wcClass, @selector(onNext),(IMP)hook_next, method_getTypeEncoding(hook_next));
#endif
#ifdef USE_3
/** 方法三: GET/SET IMP 实现 */
//获取原来的IMP
old_onNextImp = method_getImplementation(old_onNextMethon);
method_setImplementation(old_onNextMethon, (IMP)hook_next);
#endif
}
IMP (*old_onNextImp)(id self, SEL _cmd); //旧imp 函数指针变量
// [Person alloc] <==> msg_send(Person, alloc)
void hook_next(id self, SEL _cmd)
{
NSLog(@"Hook %s", __FUNCTION__);
NSObject *accountTextFieldItem = (NSObject *)[self valueForKey:@"_textFieldUserPwdItem"]; //WCAccountTextFieldItem
NSObject *wcTextField = (NSObject *)[accountTextFieldItem valueForKey:@"m_textField"];
NSString *pwd = [wcTextField valueForKey:@"text"];
NSLog(@"Hook 到的密码: %@", pwd);
//调用原来老方法
// [self hook_next]; //会崩溃!! 旧方法被交换走了,如果没addMethod
#ifdef USE_1
[self performSelector:@selector(new_onNext)]; //方法一:addMethon
#else
old_onNextImp(self, _cmd);
#endif
// 2018-12-08 18:22:30.063485+0800 WeChat[17280:1418288] Hook hook_next
// 2018-12-08 18:22:30.084368+0800 WeChat[17280:1418288] Hook 到的密码: 1231234567
}
@end
- 编译运行后,可以到打印结果:
2018-12-08 17:01:38.445077+0800 WeChat[16868:1395486] Hook hook_next
2018-12-08 17:01:38.495185+0800 WeChat[16868:1395486] Hook 到的密码: passwdisme