iOS 逆向 day06 theos tweak

Theos是什么?
Theos是国外大神DHowett发明的开发 iOS 越狱插件的工具,DHowett的 Theos 大幅简化了编写越狱程序的流程。

Theos工作流程?
开发者编写 hook 代码 -> deb插件 -> 安装到手机

一、安装 thoes

  1. 环境介绍:
  • macOS Catalina 10.15.4
  • theos 2.5
  • iPhone 6 / iOS 12.3.1
  • Xcode 11.5
  1. 安装 ldid 签名库
 brew install ldid xz
  1. 设置环境变量
//  ~/.bash_profile  文件添加如下两句
export THEOS=~/theos
export PATH=$THEOS/bin:$PATH

再运行 source ~/.bash_profile 指令让配置立刻生效

  1. 下载 theos 代码
git clone --recursive https://github.com/theos/theos.git $THEOS

为什么我们不在 Github 直接利用浏览器 clone 按钮下载呢?
解答:打开 theos 中的 .gitmodules 文件我们发现,它依赖了很多子模块,直接下载代码会导致依赖的子模块未下载。

  1. 下载 theos 需要的 iOS SDK
    从 Xcode7.3 开始,不在提供私有库供我们使用,所以我们需要执行下面指令去下载。
 curl -LO https://github.com/theos/sdks/archive/master.zip
 TMP=$(mktemp -d)
 unzip master.zip -d $TMP
 mv $TMP/sdks-master/*.sdk $THEOS/sdks
 rm -r master.zip $TMP

二、使用 theos,结合结合之前的工具把某 APP 的广告去掉。

去掉图中广告
  1. 使用 Reveal 工具分析,如上图所示,我们找到该广告的类为 XMPlayPageAdView

  2. 因为该 APP 是我们从 App Store 下载的,需要使用 dumpdecrypted 工具进行动态脱壳。

  3. 脱壳完成后,使用 class-dump 工具抽取该 APP 的头文件。

  4. 分析头文件:


    该类没有初始化方法

    我们找它的父类
  5. 结论:我们需要使用 theos 来 hook 掉 XMBaseAdView- (id)initWithFrame:(struct CGRect)arg1; 方法。

  6. 在 mac 上 输入 nic.pl 指令初始化一个 theos 项目。

carrotdeMacBook-Pro:ting carrot__lsp$ nic.pl 
NIC 2.0 - New Instance Creator
------------------------------
  [1.] iphone/activator_event
  [2.] iphone/activator_listener
  [3.] iphone/application_modern
  [4.] iphone/application_swift
  [5.] iphone/cydget
  [6.] iphone/flipswitch_switch
  [7.] iphone/framework
  [8.] iphone/library
  [9.] iphone/notification_center_widget
  [10.] iphone/notification_center_widget-7up
  [11.] iphone/preference_bundle_modern
  [12.] iphone/theme
  [13.] iphone/tool
  [14.] iphone/tool_swift
  [15.] iphone/tweak
  [16.] iphone/tweak_with_simple_preferences
  [17.] iphone/xpc_service
Choose a Template (required): 15
Project Name (required): tingtweak
Package Name [com.yourcompany.tingtweak]: com.mj.tingtweak
Author/Maintainer Name [carrot__lsp]: carrot
[iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: com.gemd.iting
[iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]: 
Instantiating iphone/tweak in tingtweak/...
Done.

初始化过程如上所示,唯一注意的是 MobileSubstrate Bundle filter 这是我们需要 hook 的项目的 BundleID,我们可以使用 cycript 去手机上获取。

  1. 配置 theos 项目。


    打开项目,配置手机 ip 和端口
// Tweak.x 文件中加入的代码 
%hook XMBaseAdView
- (id)initWithFrame:(struct CGRect)arg1 {
    return nil;
}
%end
  1. 分别 在 theos 项目中运行 make clean -> make -> make package -> make install 四个命令。如果顺利,我们手机将会重启 SpringBoard,打开刚刚我们 hook 的 APP。
    效果图,广告不见了

三、使用 theos 可能会遇到的问题

  1. 没有按照以上步骤按照,导致命令无法成功执行
  2. theos2.5 我使用 usb 进行 make install 的时候会导致卡住,最后发现使用 Wifi 模式一下就成功了。(暂时还不确定是什么问题)

四、使用 theos 让 iPhone 桌面上所有烦人的小红点消息提示永远消失。

让设置和 App Store 的小红点消失

我们看的 iPhone 桌面,也是运行在 iOS 上的一个 APP,它的名字叫做 SpringBoard,但是我们无法用 Reveal 这个 App 的页面结构。

  1. 在 iPhone 上使用 ps -A 指令找到 SpringBoard
15519 ??         1:17.68 /System/Library/CoreServices/SpringBoard.app/SpringBoard
  1. 使用 cycript -p SpringBoard 登陆它
  2. 打印出当前页面所有的 view
    密密麻麻的 view

    这时候就要考验开发经验了,通常我们开发红点的时候一般会叫做 badge,这个名字,我们拿着这个名字,去搜索,发现可以找到
    SBIconParallaxBadgeView

    我们如何确定是否是我们需要控制的红点 view 呢?我可以拿到它的地址,通过如下代码验证
#0x145248c10.hidden=1

结果设置身上的红点消失了,说明我们找对了。

  1. 接下来我们找到 SpringBoardMach-O 文件,发现并不需要脱壳,所以重复上面二、使用 theos,结合结合之前的工具把某 APP 的广告去掉的思路,即可将红点隐藏了。
屏幕红点永久去除了

四、使用 theos 给 qq 加些页面。

任务要求:1.添加一个带有开关音乐cell,保存开关的状态。2.添加一个能退出程序的退出按钮。


在红框位置修改
  1. 使用 Reveal 找到相关 view 的所在控制器。
    Reveal 分析

    分析可知这些 cell 都是在 QQRecommendViewController
  2. 利用 dumpdecrypted 脱壳,然后用 class-dump 导出头文件,找到 QQRecommendViewController 的头文件,发现里面有 tableView 相关方法。
发现目标文件
  1. 接下来的思路就是用 theos 来 hook 这些方法,添加我们自己的 cell 了。
// hook 代码如下


@interface QQRecommendViewController
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
@end

@interface QQRecomViewTableViewCell
@property(retain, nonatomic) UILabel *titleNickLabel;
@property(retain, nonatomic) UIView *accessoryView;

@end

@class QQRecommendViewController;
@class QQRecomViewTableViewCell;

%hook QQRecommendViewController
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return %orig;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return %orig;
}
- (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (([self numberOfSectionsInTableView:tableView] - 1) == indexPath.section) {
        if (indexPath.row == 0) {
                    QQRecomViewTableViewCell *musicCell = (QQRecomViewTableViewCell*)%orig;
                    musicCell.titleNickLabel.text = @"音乐开关";
                    UISwitch *musicSwitch = [[UISwitch alloc] init];
                    musicSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:@"CarrotMusicSwitch"];
                    musicCell.accessoryView = musicSwitch;
                    [musicSwitch addTarget:self action:@selector(musicSwitchClicked:) forControlEvents:UIControlEventValueChanged];
                    return musicCell;
                } else {
                    QQRecomViewTableViewCell *logoutCell = (QQRecomViewTableViewCell*)%orig;
                    logoutCell.titleNickLabel.text = @"退出登录";
                    return logoutCell;
                }
    } else {
        return  %orig;
    }
}
%new
- (void)musicSwitchClicked:(UISwitch*)musicSwitch {
    [[NSUserDefaults standardUserDefaults] setBool:musicSwitch.on forKey:@"CarrotMusicSwitch"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (([self numberOfSectionsInTableView:tableView] - 1) == indexPath.section) {
      return 44;
    } else {
      return %orig;
    }
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    if (([self numberOfSectionsInTableView:tableView] - 1) == indexPath.section) {
            [tableView deselectRowAtIndexPath:indexPath animated:YES];
      if (indexPath.row == 0) { 

            } else {
                exit(0);
            }
    } else {
      %orig;
    }
}
%end
  1. 最终效果图

四、使用 theos,实现改造 QQ 任务实现的注意点。

  1. %hook 类里面的代码,默认的行为是只能替换,不能新创建方法。
  2. 所以我们 musicSwitchClicked 这个方法前面要使用 %new 老告诉 theos,我们需要创建新的方法。
  3. 使用 %orig 是让代码执行原有代码的逻辑,自己会自动传原本需要的参数。
  4. 如果需要再 theos 调用其他类和方法,需要用 @class@interface 进行声明,不然会报错。
  5. 如果 thoes 报错 control reaches end of non-void function ,是表示有些方法必须有返回值,而我们没有给返回值。
  6. 如果在我们添加 hook 代码之后,程序奔溃了怎么办呢?我们可以 Xcodewindow 菜单中找到 Devices and Simulator ,里面可以查看 iPhone 的崩溃信息。

你可能感兴趣的:(iOS 逆向 day06 theos tweak)