【Lawliet的iOS逆向实验室】「某视频软件」部分功能安全性研究

391 阅读5分钟

Hi 👋

My apps

-扫雷Elic 无尽天梯梦见账本
类型游戏财务
AppStoreElicUmemi

逆向,是为了更好的正向开发

一、逆向目标

  • 逆向研究功能逻辑,提升逆向分析思维
  • 发现功能风险点,提升防护手段

下面我们开始分析

二、class-dump 工具导出头文件

提前准备好砸壳🔗的应用

如果需要砸壳的包的话可以通过上顶端的方式联系我。

使用class-dump导出头文件,便于我们定位目标。

class-dump -H MachO文件名 -o 输出的文件夹/

三、登录态处理

通过在Headers中搜索isLogin看到一个很可能是用来判断登录态的东西:

  • UserInfoConfig 疑似用户管理对象 renren01.png

3.1 hook登录态

这里用到了Logos语法进行快捷的Hook代码编写。官网

@interface UserInfoConfig

+ (bool)isLogined;

- (bool)isLogined;

@end

%hook UserInfoConfig

+ (bool)isLogined {
    return YES;
}

- (bool)isLogined {
    return YES;
}

%end

3.2 检验登录态

未处理

renren03.jpeg

Hook之后

通过!这里的立即登录已经变成立即开通了,只不过用户信息都是空的。

  • 这样简单的就改变了登录态。这对于有账号体系的应用来说是比较重要的一个点。
  • 需要思考一下怎么更好的保护好。

renren02.png

这里因为是直接改写了登录状态的get方法,所以这里有了大量的接口报错提示:

2021-05-23 14:52:09.592113+0800 PUClient[6981:2390642] You should call login api before calling any im related api

3.3 找到VIP态

从UI层开始分析

renren04.png

a.找到容器: RRVipUserInfoView

  • 看看内部有没有做数据模型
    • 并没有发现疑似点
    • 去父视图看下

renren05.png

b.父视图:RRVipBannerTopCell

  • 这里只有一个RRTopBannerModel *bannerModel;模型,但看起来和VIP无关
    • 暴力搜索看下吧

renren06.png

c.搜索VIP相关字眼

  • 通过Headers查找VIP关键字,逐个查看,发现RRIMManager
    • 但疑似IM功能相关类,和视频无关。忽略

renren07.png

下面又找到几个,可能的文件

d.RrmjUser 疑似用户对象

其中有这样一个属性:@property(retain, nonatomic) RRMedalModel *vipMedal;

e.RRMedalModel 疑似会员对象

  • 查看Header后发现很多疑似会员功能的字段
@interface RRMedalModel : NSObject <NSCoding>
{
    _Bool _isExpired;// 字面意思是否过期
    long long _medalId; // 疑似会员类型
    NSString *_imgUrl;
    NSString *_name;
    NSString *_endTime;// 到期时间
}

+ (id)modelCustomPropertyMapper;
+ (id)replacedKeyFromPropertyName;
- (void).cxx_destruct;
@property(nonatomic) _Bool isExpired; // @synthesize isExpired=_isExpired;
@property(copy, nonatomic) NSString *endTime; // @synthesize endTime=_endTime;
@property(copy, nonatomic) NSString *name; // @synthesize name=_name;
@property(copy, nonatomic) NSString *imgUrl; // @synthesize imgUrl=_imgUrl;
@property(nonatomic) long long medalId; // @synthesize medalId=_medalId;
- (id)endTimeTextString;
- (id)endTimeString;
- (_Bool)isPermanent;// 字面意思 是否永久
- (id)initWithCoder:(id)arg1;
- (void)encodeWithCoder:(id)arg1;

@end

前面的UserInfoConfig中发现有RrmjUser属性存在。推测是用来保存当前用户的,这里准备在运行时set一个我们自己创建的对象,以便能够调用到我们重写的会员是否过期的get方法。

3.4 完整Logos代码

#pragma mark - RRMedalModel

@interface RRMedalModel: NSObject

- (bool)isPermanent;
- (bool)isExpired;

@end

%hook RRMedalModel

- (bool)isPermanent {
    return YES;
}

- (bool)isExpired {
    return NO;
}

%end

#pragma mark - RrmjUser

@interface RrmjUser: NSObject

@end

%hook RrmjUser

- (id)vipMedal {
    id vip = [[%c(RRMedalModel) alloc] init];
    return vip;
}

%end

#pragma mark - UserInfoConfig-这里Hook了登录态

@interface UserInfoConfig

+ (bool)isLogined;

- (bool)isLogined;

- (id)userInfo;

@end

%hook UserInfoConfig

+ (bool)isLogined {
    return YES;
}

- (bool)isLogined {
    return YES;
}

- (id)userInfo {
    id tempUser = [[%c(RrmjUser) alloc] init];
    return tempUser;
}

%end

3.5 结果

renren08.png

之前开通会员的入口都变成了续费了,我成为了”永久会员“。

四:广告逻辑

  • 试着直接把广告加载的方法Return了,但是直接不能加载视频了。
    • 于是试着把广告改成不用等倒计时结束,就能点跳过。
    • 对于有接入广告的应用来说,可以在这些逻辑加强防护。
#pragma mark - RRPlayerControlAdPlay
@interface RRPlayerControlAdPlay: NSObject

- (bool)canJump;

@end

%hook RRPlayerControlAdPlay

- (bool)canJump {
    return YES;
}

%end

五:研究视频权限

renren10.png

5.1结合正常显示的剧集数据对比非会员和会员的视频区别

  • 调试找出关键字段的区别

renren09.png

5.2 Hook

通过Hook相关get方法把所有视频类型改为Free

#pragma mark - MovieEpisode
@interface MovieEpisode: NSObject
/// 2 VIP nil free
- (long long)feeModeType;
- (NSString *)feeMode;

@end

%hook MovieEpisode

- (NSString *)feeMode {
    return @"free";
}

- (long long)feeModeType {
    return 0;
}

%end

5.4 结果

列表页显示成功,没有了VIp标签,在这里全部识别为了免费视频。

renren11.png

但是点击对应集数观看的时候就报错了

renren12.png

六:视频流分析

又试了很多数据模型进行改写都不行

  • 下面是免费的视频流,在浏览器即可访问
(lldb) po ((M3u8Model *)0x2828f1300).dibblingTotalDuration
0

(lldb) po ((M3u8Model *)0x2828f1300).url
https://tx-cdn-local.rr.tv/2a66f13043434abb9114720c3cc4f19c/d6372e9485f84ba38a4b82ab0f31bad2-0e37a229c0ddec2ae7b75fbcac9f6f55-ld.mp4?auth_key=1622396264-900b321e0b42e34f95ab888009a63e84-0-39b17c20f3adcd88504a446cd2496c25&clientType=ios_rrsp_jzsp&clientVersion=5.5.1&parseUsage=PLAY&uid=0
  • VIP视频免费5min看的视频流
    • 这里发现尾端有个end=300疑似就是控制表示5分钟时长。
    • 但是试着调整URL内的时间参数也不能访问完整视频。
    • 从域名看的话免费的放在腾讯云收费的放在阿里云。
(lldb) po ((M3u8Model *)0x2828d9280).url
https://ali-preview.rr.tv/da81107fbb414227bad8faafa68ba9e6/eb37b38567b44e34817a36d9a8b09c3f-74a18a8c38dc4be51298ea5519a1815c-ld.mp4?auth_key=1622396977-56748ddc75ea4acf87fe91146aecae62-0-fb83047d57857ce0deded4705ee8a6be&end=300

(lldb) po ((M3u8Model *)0x2828d9280).dibblingTotalDuration
0

(lldb) 
  • 可以推测在VIP视频流的参数中有一些对用户权限的校验,没有正确的key就无法正常获取视频流。
    • 这里的安全性还是比较到位的

七、总结与安全建议

  • 简单的重写一些get方法就已经能破解一些场景了
    • 对于工具类应用来说这类破解很致命,是会直接影响到收入的。
  • 重要的逻辑可以的话进行混淆,增大破解难度。
  • 最近有逆向研究另一个工具类项目,发现看了是Swift的。Dump header的时候,有遇到问题。等我有些进展再来和大家分享~
    • 侧面反映了用Swift写的项目也增加了逆向成本
  • 做逆向防护
    • 之前自己有进行过一些方案的研究初步写过一些
      • 不过感觉还总结的不够好,有兴趣可以到我的 技术文档归档 中先看看
    • 这个后面会再详细总结一篇分享给大家~

研究逆向的一些建议

  • 不要去碰一些比较重要的App比如银行之类的
  • 尽量不要在自用的手机上逆向
  • 不一定需要越狱机,但有越狱机更方便
  • 不要用自用的账号登录
  • 记住一点逆向,是为了更好的正向开发

如果你对逆向感兴趣,欢迎交流~