iOS 非越狱下的代码注入

免责声明

  • 本文为一篇严肃的学术研究型文章,文中所提及的注入手段仅供 iOS 底层技术的学习与交流,不针对任何公司与 App。

  • 为防止读者将本文用于商业或者非法用途,本文不提供任何注入工具与重签名脚本。

  • 读者如果将本文用于商业或者非法用途,则所产生的后果由读者自行承担。

非越狱下的代码注入步骤

  • 材料与工具

    1. WeChat.ipa 包(已脱壳)
    2. class-dumpSublime Text
    3. yololibMachOView
    4. XCodeiPhone
    5. 重签名脚本
  • 解压 WeChat.ipa 包,获取 WeChatMachO 文件,使用 class-dumpMachO 文件中导出 Objective-C 类的头文件

    将导出的 Objective-C 类的头文件拖入 Sublime Text 中,以备后面分析 App 时查找和使用

  • 新建 iOS - App 工程 InjectCodeDemo

    在工程 InjectCodeDemo 的根目录下新建 IPA 目录,并将已脱壳的 WeChat.ipa 拖入 IPA 目录中

  • 在工程 InjectCodeDemo 中新建动态库 HzpService.frameworkHcgService.dylib

    关于 HzpService.framework

    1. 新建注入工具类 HzpInjectTool

    关于 HcgService.dylib

    1. 新建注入工具类 HcgInjectTool
    2. Target(HcgService) - Build Settings - Architectures - Base SDK 修改为 iOS
    3. Target(HcgService) - Build Settings - Signing - Code Signing Identity 修改为 iOS Developer
  • 在工程 InjectCodeDemo 中导入新建的动态库 HzpService.frameworkHcgService.dylib
    并修改 Target(InjectCodeDemo) - Build Phases
    导入动态库

  • 将重签名脚本拷贝到工程 InjectCodeDemo 的根目录下
    并在 Target(InjectCodeDemo) - Build Phases 中添加 New Run Script Phase

    注意:
    Run Script 的顺序需要在 Embed Frameworks 之前
    即需要先使用 WeChat.app 覆盖 InjectCodeDemo.app,然后再将动态库拷贝到 WeChat.app/Frameworks 目录下
    添加 New Run Script Phase

  • 连入 iPhone 真机,并将 Target(InjectCodeDemo) 改为真机调试

  • 注意:

    1. App 安装期间需要保持 iPhone 处于开启状态
      否则会提示 Unlock iPhone to Continue
    2. 因为 XCode 编译阶段动态库拷贝机制的问题
      所以每次在运行 App 之前,都需要使用 Command + Shift + K 清空 XCode 缓存
      以保证(执行脚本)和(拷贝动态库)之间相对顺序的正确性
      否则会提示 The file "InjectCodeDemo" couldn’t be opened because you don’t have permission to view it.

使用 ViewDebug 和导出的 Objective-C 类的头文件分析目标 App

  • ① 分析登录按钮点击事件

    登录按钮的类型为 FixTitleColorButton,继承自 UIButton
    点击登录按钮将会触发 WCAccountMainLoginViewController 类的 onNext 方法
    登陆按钮 ①
    通过 class-dump 导出的头文件进行验证,确实在 WCAccountMainLoginViewController.h 中找到了 -onNext 方法
    登陆按钮 ②

  • 分析账号输入框和密码输入框

    账号输入框和密码输入框的类型均为 WCUITextField,均继承自 UITextField
    账号输入框
    密码输入框
    WCAccountMainLoginViewController.h 中找到了疑似存储账号和密码的成员变量:
    存储账号的成员变量:WCAccountTextFieldItem* _textFieldUserNameItem
    存储密码的成员变量:WCAccountTextFieldItem* _textFieldUserPwdItem
    关系 1
    那么,WCAccountMainLoginViewController 类中存储账号和密码的成员变量(WCAccountTextFieldItem 类型)和 ViewDebug 中的账号密码输入框(WCUITextField 类型)之间有什么联系呢?我们尝试在继承链中查找一下:
    WCAccountTextFieldItem 继承自 WCBaseTextFieldItem
    关系 2
    WCBaseTextFieldItem 中有 WCUITextField 类型的 m_textField 成员变量
    关系 3
    WCUITextField 又继承自 UITextFieldUITextField 可以通过 text 属性拿到输入框中的内容
    关系 4

  • 理一下登录按钮与账号密码输入框之间的联系

    1. 点击登录按钮将会触发 WCAccountMainLoginViewController 类的 -onNext 方法
    2. 账号密码输入框是 WCAccountMainLoginViewController 类中两个 WCAccountTextFieldItem 类型的成员变量(_textFieldUserNameItem_textFieldUserPwdItem
    3. -onNext 方法中可以拿到成员变量 _textFieldUserNameItem_textFieldUserPwdItem
    4. WCAccountTextFieldItem 继承自 WCBaseTextFieldItem
      WCBaseTextFieldItem 中有 WCUITextField 类型的成员变量 m_textField
      WCUITextField 又继承自 UITextField
      UITextField 可以通过 text 属性拿到输入框中的内容

Objective-C 方法常见的 Hook 方式

  • ① 使用 method_exchangeImplementations

    备注:onceToken 应该定义为静态局部变量 static dispatch_once_t onceToken;
    ① 使用 method_exchangeImplementations

  • ② 使用 class_replaceMethod

    备注:onceToken 应该定义为静态局部变量 static dispatch_once_t onceToken;
    ② 使用 class_replaceMethod

  • ③ 使用 method_getImplementation 和 method_setImplementation

    备注:onceToken 应该定义为静态局部变量 static dispatch_once_t onceToken;
    ③ 使用 method_getImplementation 和 method_setImplementation

  • 注意

    Objective-C 方法中,self 代表当前实例对象或者当前类对象,这种说法不准确
    Objective-C 方法中,self 代表的是当前方法调用者

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值