0%
前言
- 工具:
- Reveal查看App视图层级
- class-dump导出App所有头文件
- theos插件开发工具
- IDA反汇编,可以友好地生成伪代码
- restore-symbol恢复App符号信息
- 注意:此文仅限于技术交流,如果损害了App方利益,请发邮件
xxoo@hotmail.com
,谢谢。
- 目的:去除开屏广告和允许内部打开网页链接
新建插件
- 新建内容如下:
1 2 3 4 5 6 7 8 9 10 11
| $ nic.pl NIC 2.0 - New Instance Creator ------------------------------ ... [10.] iphone/tweak [11.] iphone/xpc_service Choose a Template (required): 10 ... [iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: com.sina.weibo ... Done.
|
- 更改Makefile,增加内容如下
1 2
| ARCHS = arm64 arm64e TARGET = iPhone:latest:10.0
|
- 目前支持的架构有armv7 armv7s arm64 arm64e等
- 添加
ARCHS = armv7 armv7s arm64
表示支持 armv7 armv7s arm64 三种处理器架构
- 对于最新的A12处理器(iPhoneX以后)的设备,需要添加arm64e,否则生成的dylib文件不能正常加载
- 指定目标规范:
TARGET = iPhone:BaseSDK:DeploymentTarget
BaseSDK
代表编译用的SDK版本
Deployment Target
是最低兼容的系统版本,
开屏广告
- 定位到微博开屏广告界面,使用Reveal查看界面层级,发现
WBAdFlashAdView
是广告视图。
- 使用class-dump导出所有头文件。打开
WBAdFlashAdView.h
文件,很容易发现closeAd
和showAd
。我们首先这样做:在执行弹出广告的时候去关闭广告,代码如下:1 2 3 4 5 6 7 8 9
| @interface WBAdFlashAdView - (void)closeAd; @end
%hook WBAdFlashAdView - (void)showAd { [self closeAd]; } %end
|
- 执行安装,安装成功后,重新打开微博发现还是有开屏广告,why?第一反应是在执行
closeAd
方法时肯定是有其它判断的,判断通过了才会真正地执行跳过广告的代码。
- 把微博Mach-O文件拖进去IDA,使用IDA查看
closeAd
伪代码,发现如下伪代码1 2 3
| if ( (unsigned int)-[WBAdFlashAdView isShowing](self, "isShowing") ) {
}
|
- 查看以上说明,要想真正地执行
closeAd
,[self isShowing]
必须成立,所以最终代码为1 2 3 4 5 6 7 8 9 10 11
| @interface WBAdFlashAdView - (void)closeAd; - (void)setIsShowing:(BOOL)isShowing; @end
%hook WBAdFlashAdView - (void)showAd { [self setIsShowing: YES]; [self closeAd]; } %end
|
- 安装后发现确实跳过了开屏广告。
内部打开网页链接
寻找内部浏览器
- 如上图所示,当点击网页链接时,并不会执行打开,而是显示链接地址,提示用户手动复制到到浏览器中进行打开。这样的操作太麻烦了,所以有了下面的文章
- 点击网页链接会进入一个控制器,使用Reveal查看界面层级,发现
WBTopNavigationWebViewController
就是展示网页的控制器。
- 那么接下来要干什么呢,其实是一脸懵逼的。那我们不妨先这么干:恢复符号,然后断点
WBTopNavigationWebViewController
所有方法,判断初始化时会调用哪些方法。
恢复符号
- macOS步骤如下:
- restore-symbol Weibo -o WeiboWithSymbol
- ldid -e WeiboWithSymbol > WeiboWithSymbol.entitlements
- 使用VSCode软件打开WeiboWithSymbol.entitlements,添加如下,然后保存。
1 2
| <key>platform-application</key> <true/>
|
- ldid -SWeiboWithSymbol.entitlements WeiboWithSymbol
- 把WeiboWithSymbol上传到iPhone里面的Weibo.app目录
- iPhone上步骤如下:
- cd /var/containers/Bundle/Application/62CA4E3D-37BE-4CF9-8564-3863BD3928CF/Weibo.app/
- mv Weibo WeiboNoSymbol // 备份原有的
- mv WeiboWithSymbol Weibo // 改成新的
- 重新启动微博
寻找原始URL
- 执行如下命令,断点
WBTopNavigationWebViewController
所有方法,找到了73个断点位置1 2
| (lldb) br set -r '\[WBTopNavigationWebViewController .*\]' Breakpoint 1: 73 locations.
|
- 点击
网页链接
首先命中了-[WBTopNavigationWebViewController generateWithOpenUrlLink:inAppParas:]
方法,下文把这个方法叫做生成
;然后命中了-[WBTopNavigationWebViewController initWithURL:parameters:]
方法,下文把这个方法叫做初始化
。
- 我们试想一下:为什么有的链接可以直接打开,而有的链接只能在外部浏览器打开?答案是在发送微博时,微博对链接进行过包装,在点击链接时,会传入包装过的URL,然后通过判断包装好的参数来区分是内部还是外部打开。那么我们要做的就是拿到最原始的URL替换掉微博封装的URL,这样就可以内部打开链接。
生成
和初始化
都传入了URL,我们在这两个方法里面都可以拿到原始URL,我们这里在初始化
里面拿最原始的URL,Why?当LLDB里面命中初始化
时,执行bt
查看一下调用堆栈,发现生成
里面调用了初始化
,初始化
层级更深,更核心。
- 命中
初始化
断点时,打印URL参数。确实如我们上面所说,原始的URL被封装了,我们需要提取出来。1 2 3 4 5 6 7 8 9
| (lldb) c * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 frame #0: 0x0000000103ae2bd4 Weibo` -[WBTopNavigationWebViewController initWithURL:parameters:] Weibo`-[WBTopNavigationWebViewController initWithURL:parameters:]: (lldb) po $x2 http://weibo.cn/sinaurl?toasturl=https%3A%2F%2Fiosre.com%2Ft%2Fswift-runtime-frida-alamofire%2F17602
(lldb) po [$x2 class] NSURL
|
- 从打印值发现
初始化
的第一个参数是NSURL类型并且进行了转义操作,所以我们进行反转义,得到能被肉眼识别的字符串1 2 3
| (lldb) e NSString *$query = (NSString *)[((NSURL *)$x2) query] (lldb) po [$query stringByRemovingPercentEncoding] toasturl=https://iosre.com/t/swift-runtime-frida-alamofire/17602
|
- 在这里就很容易提取原始URL,然后在进行转义,最后封装成NSURL类型,代码如下
1 2
| NSString *lastStr = [[query componentsSeparatedByString:@"="] lastObject]; NSURL *lastURL = [NSURL URLWithString:lastStr];
|
- Tweak.x里面填写如下代码,进行安装,安装成功后,发现和原来效果一样,还是不能内部打开链接,怎么回事呢?
1 2 3 4 5 6 7 8 9 10 11 12 13
| %hook WBTopNavigationWebViewController
- (id)initWithURL:(NSURL *)url parameters:(NSDictionary *)arg2 { NSString *query = [[url query] stringByRemovingPercentEncoding]; if (![query containsString:@"toasturl="]) { return %orig; } NSString *lastStr = [[query componentsSeparatedByString:@"="] lastObject]; NSURL *lastURL = [NSURL URLWithString:lastStr]; return %orig(lastURL,arg2); }
%end
|
禁用包装的URL
初始化
传入的URL为包装过的URL,而我们传入的URL为原始的URL,可能需要禁用掉包装过URL的其它逻辑,让它可以加载原始URL。往上面几步找线索,包装过URL里面有个sinaurl
,这个代表包装URL的特征。我们去WBTopNavigationWebViewController
查找关键字sinaurl
,发现- (_Bool)disablesSinaURL;
方法,禁用这个方法也许可以加载原始URL。最终代码如下:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| %hook WBTopNavigationWebViewController
- (BOOL)disablesSinaURL { return YES; }
- (id)initWithURL:(NSURL *)url parameters:(NSDictionary *)arg2 { NSString *query = [[url query] stringByRemovingPercentEncoding]; if (![query containsString:@"toasturl="]) return %orig; NSString *lastStr = [[query componentsSeparatedByString:@"="] lastObject]; NSURL *lastURL = [NSURL URLWithString:lastStr]; return %orig(lastURL,arg2); }
%end
|
- 安装后测试成功,网页链接都可以在微博内部打开