> For the complete documentation index, see [llms.txt](https://ryukiedev.gitbook.io/wiki/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ryukiedev.gitbook.io/wiki/ni-xiang/24.-shi-zhan-ren-ren-shi-pin-po-jie.md).

# 24.实战人人视频破解

## 一、class-dump

> 提前准备好[砸壳🔗](https://github.com/RyukieSama/RyukieDevGitBook/tree/571119c68a246a6c21c887dca5f05e105ecbd920/逆向/逆向/23.应用砸壳.md)的应用（人人视频5.5.1）

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

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

## 二、确定逆向目标

这里我想要实现非VIP用户可以查看VIP视频。

一般情况下我们会通过类似`isVIP`这样的字眼去进行相关的判断。

Cycript链接手机进行分析

## 三、登录态

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

![1](/files/-MaNQBf9848ONp1P_7ul)

### 3.1 hook登录态

```cpp
@interface UserInfoConfig

+ (bool)isLogined;

- (bool)isLogined;

@end

%hook UserInfoConfig

+ (bool)isLogined {
    return YES;
}

- (bool)isLogined {
    return YES;
}

%end
```

### 3.2 检验登录态

***原版***

![3](/files/-MaNQBfAUkXSSnhOfgkH)

***Hook版***

通过！这里的`立即登录`已经变成`立即开通`了

![2](/files/-MaNQBfBoJUpHswlRL18)

> 这里因为是直接改写了登录状态的返回值，所以这里有了大量的错误提示：
>
> `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层开始分析

![4](/files/-MaNQBfCxp44tB1v0Buc)

#### a.找到容器: `RRVipUserInfoView`

> 看看它内部有没有做数据逻辑

![5](/files/-MaNQBfDxpDvxTGkYBmW)

> 看起来`resetStatus`&`reloadUIData`是有做些请求的，我们先记录一下。继续分析。

#### b.父视图：`RRVipBannerTopCell`

![6](/files/-MaNQBfEdMvPqUv4aJm-)

> 这里看到一个`@property(retain, nonatomic) RRTopBannerModel *bannerModel;`
>
> 但是没有和用户相关的模型属性，推测`VIP`的判断是在`RRVipUserInfoView`内部！

#### c.VIP相关类

![7](/files/-MaNQBfFC7y7EWxG4IsO)

通过Headers查找VIP关键字，逐个查看，发现`RRIMManager`疑似。而且还是个单例。我们Hook看下有什么效果。

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

#### f.RrmjUser

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

#### g.RRMedalModel

```cpp
@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
```

> 查看Header后发现疑似VIP相关字段
>
> 在第二步的`UserInfoConfig`中发现有`RrmjUser`属性存在，这里准备在运行时set一个我们自己创建的对象，重写会员是否过期的方法。

Logos代码：

```cpp
#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
```

**结果**

![8](/files/-MaNQBfGEEMGIwQpiggq)

> 之前`开通会员`的入口都变成了续费了。哈哈哈哈
>
> 但是观看会员视频还是只能试看5分钟
>
> 下面的目标就是解除5分钟的限制了！

## 四：无限制调广告

> 试着直接把广告加载的方法Return了，但是直接不能加载视频了。于是改成不用等就能点跳过。

```cpp
#pragma mark - RRPlayerControlAdPlay
@interface RRPlayerControlAdPlay: NSObject

- (bool)canJump;

@end

%hook RRPlayerControlAdPlay

- (bool)canJump {
    return YES;
}

%end
```

## 五：改变视频权限

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

![](/files/-MbEfHCP69A9vsTPg5-J)

### 5.2 调试找出关键字段的区别

![](/files/-MbEfHCQywA2-yqcLlbr)

### 5.3 Hook

```cpp
#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标签

![](/files/-MbEfHCR-0vszrHzvAR-)

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

![](/files/-MbEfHCSoeUZrcADkukR)

## 六：视频流

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

免费的视频流，在浏览器即可访问

```cpp
(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看的视频流，调整参数也不能访问完整视频。从域名看的话免费的放在腾讯云收费的放在阿里云。

```cpp
(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)
```

### 6.1 暂时的结论

基本可以确定，VIP视频的逻辑是有在视频流做处理的，不能简单通过客户端调整进行破解操作。

人人视频破解暂时告一段落。

不过也算挺有收货的
