美文网首页iOS 开发 Objective-C
iOS 底层原理 day06 theos tweak

iOS 底层原理 day06 theos tweak

作者: 望穿秋水小作坊 | 来源:发表于2020-08-01 13:41 被阅读0次

    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

        本文链接:https://www.haomeiwen.com/subject/vvgfrktx.html