Swift 从获取所有 NSObject 对象聊起:ObjC、汇编语言以及底层方法调用链(一)

news2024/12/27 12:23:04

在这里插入图片描述

概览

Swift 语言给我们的印象是:简洁、现代化和可以“心安神泰”的完全信赖。不过,在一些特殊情况下我们唯有进入 Swift 底层的动态世界方能真正地“随遇而安”。

在这里插入图片描述

保安局“刘局长”曾语重心长的教导过我们:“非常时期,用非常方法!”。所以,这里就让我们彻底沉浸到 Swift 那深不见底的“千尺冰寒”中,来探寻 Objective-C 和汇编语言的奇妙世界吧!

在本篇博文中,您将学到以下内容:

  • 概览
  • 1. 获取当前所有 NSObject 对象的基本原理
  • 2. NSObject.init() 里面到底做了啥?
  • 3. 啥都不做也不行?你们是要闹哪样?
  • 总结

在下一篇博文中,我们将继续本次冒险之旅来进一步揭秘:为什么在 NSObject 构造器 init 方法上做钩子会如此“命运坎坷”,以及“逆天改命”的各种黑魔法!

好了,废话少叙!让我们马上开始奇妙的底层探险吧!

Let‘s Dive in!!!😉


1. 获取当前所有 NSObject 对象的基本原理

首先第一个问题是:为什么要获取 App 当前运行时所有的 NSObject 对象?

答案有两个:

  1. 好玩!
  2. 方便对它们做钩子(Hook)从而进一步实现自己的“天马行空”之梦想。

从 Xcode 的调试内存图(Debug Memory Graph)中,我们可以可以大致领略到 App 运行中那星罗棋布的海量对象实例:

在这里插入图片描述

那么第二个问题是:我们怎样才能像 Xcode 那样在运行时探查所有 NSObject 对象的实例呢?

一种方案是“古老”的 SWIZZ 方法,它存在于 Objective-C 语言的“远古”时代。

所谓 SWIZZ 是一种对系统的“欺骗”,一种运行时的“诡计”。它是利用 Swift 底层 ObjC 语言的动态特性实现在 App 进程活跃时修改 ObjC 运行时(Runtime)内容的方法。

在这里插入图片描述

SWIZZ 的一种常见应用就是钩子(Hook)。所谓钩子就是在 App 运行时动态的“勾住”(截获)对象方法从而起到监视、记录甚至修改对象原有方法的目的。

我们知道 NSObject 对象的诞生都必须经过 NSObject 类实例的构造器,也就是 NSObject.init() 方法来完成。那么如果我们在该方法上设置一个钩子,那么不就可以得偿所愿监控到所有 NSObject 对象了吗?

在这里插入图片描述

以下是我们的第一次尝试:

class func tryHookNSObjectInit() {
    let oldInitSel = #selector(NSObject.init)
    let oldInitMethod = class_getInstanceMethod(NSObject.self, oldInitSel)!
    
    let closure = {obj, sel in
        print(obj)
    } as @convention(block) (NSObject, Selector) -> Void
    
    let closureObject = unsafeBitCast(closure, to: AnyObject.self)
    let closureImp = imp_implementationWithBlock(closureObject)
    method_setImplementation(oldInitMethod, closureImp)
}

如上所示,我们通过 SWIZZ 机制将 NSObject 构造器 init() 方法非常 easy 的替换成了自己的 closure 闭包。

不过,假若你胆敢运行上面的代码,你绝对会“死得很惨”:

在这里插入图片描述

因为你可能还不知道,你此时正“命犯天煞孤星”:多处“隐秘”陷阱正在一起合计着准备把你撕扯的体无完肤。

也许有些小伙伴们会认为崩溃的原因很“一目了然”:因为我们没有在钩子方法中调用原来的 NSObject 构造器。

真相果真如此吗?

为了解答这个问题,我们先要来看看在 NSObject 的构造器里到底做了些神马?

2. NSObject.init() 里面到底做了啥?

首先,清除之前的钩子代码。然后在 Xcode 中新建符号断点(Symbolic Breakpoint),姑且就中断在 NSObject.init() 方法的第一行吧:

在这里插入图片描述

运行 App,系统会在某个 NSObject 对象创建时立即中断下来。

在我测试的例子里,中断会发生在一个线程(NSThread)对象创建时:

在这里插入图片描述

进入 NSObject 构造器 init 方法,你会发现里面其实只有一条返回指令(ret)真的是“空空如也”!
在这里插入图片描述

所以说,在钩子方法中没有调用原来的 NSObject 构造器这并不算一个问题,因为确切的说默认的 NSObject 构造器方法里“空无一物”,调不调用几乎是无所谓的事。

3. 啥都不做也不行?你们是要闹哪样?

为了充分发挥小伙伴们那名侦探般“灵气逼人”的洞察力,我们现在改变策略:不打印对象本身,而是尝试打印对象的地址试试。

let closure = {obj, sel in
    let address = Unmanaged.passRetained(obj).toOpaque()
    print(address)
} as @convention(block) (NSObject, Selector) -> Void

运行可以发现,我们在打印出第一个对象的地址后就很快又“GG”了:

在这里插入图片描述

看来打印对象地址这种“信手拈来”的简单操作也不行,那请允许我们退“一万步”:将钩子方法替换为一个“空”闭包总行了吧?

let closure = {obj, sel in
    // 空空如也!            
} as @convention(block) (Any, Selector) -> Void

不幸的是,结果和之前几乎如出一辙:你还是“死”了,而且同样“死”的很快!

现在小伙伴们可能有点意识到了:不是我们钩子代码的问题,而是整个调用体系的问题!

你们真是冰雪聪明!

不过,在揭秘真正的问题之前让我们先“站在巨人肩膀之上”来尝试另一种完全不同的解决方案吧!

在下一篇博文中,我们将再接再厉用第三方 Hook 包 SwiftHook 来重新探寻一番,期待吧!

总结

在本篇博文中,我们讨论了为什么要在 App 运行时“捕获”所有 NSObject 对象的实例、介绍了 NSObject 默认构造器方法里都做了神马事情,以及初步探讨了实现这一目的的基本原理。

虽然,眼前的团团迷雾让我们暂时还无法得偿所愿,但相信只要怀有坚定的信念,胜利就在眼前!

让我们在下篇继续跟随初心,拨开迷雾见青天吧!再会!😎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1532158.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MATLAB环境下基于机器学习的合成数据生成方法

合成数据是通过计算机程序人工生成的数据,而不是由真实事件生成的数据。采用合成数据来增加训练数据,可以节省数据采集费用,或满足隐私要求。随着计算能力的提高和云数据存储选项的崛起,合成数据比以往更容易获取。这无疑是一个积…

VO、RVO、ORCA(动态避障)算法

碰撞锥(碰撞区域) 上上图中假设B物体处于静止状态,A物体沿着向量v1和v2移动,刚好能和B擦肩而过,不会发生碰撞;若V1和V2的夹角再小一点的话就一定会发生碰撞。此时会产生碰撞区域: 红线画出来…

学生信息管理系统--修改信息(非常详细的修改,更新,撤销,删除逻辑)

目录 概述修改包括的操作修改在每个模块中的应用 详解修改与更新取消删除 特殊概念数据集游标 总结 概述 学生信息管理系统,功能相对简单且代码重复性高,应该采用复用的思想来减少代码的冗余和提高代码的可维护性。然而,对于基础入门项目来说…

【Web APIs】DOM获取元素

目录 1.Web API基本认识 2.获取DOM元素 3.设置/修改DOM元素内容 4.设置/修改DOM元素属性 4.1修改元素常用属性 4.2修改元素样式属性 4.3设置/修改表单属性 5.定时器-间歇函数 1.Web API基本认识 作用:就是使用js去操作html和浏览器 分类:DOM&am…

一网打尽音乐制作!FL Studio21.2.3中文版全能数字音频工作站

一网打尽音乐制作!FL Studio21中文版全能数字音频工作站,专业机构力荐 :打造专业音乐制作,让音乐梦想触手可及! FL Studio是一款广泛使用的数字音频工作站,被许多音乐制作人和DJ用来制作和混合音乐。最新版…

基于torch.compile和gptfast代码风格实现ChatGLM模型推理加速

目录 一、ChatGLM模型代码重构迁移 二、推理的代码重构 三、效果分析对比 参考文章 torch2.0发布以后模型训练和推理可以实现一行代码加速,试用之后发现效果并不明显。随后gptfast项目也发布,表明它确实是可以实现模型推理的加速,看来之前…

修改约束

目录 修改约束 创建数据库 添加约束 删除约束 Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 修改约束 如果说表结构的修改还在可以容忍的范畴之内,那么约束的修改是绝对 100% 禁止的 所有的约束一定要在…

微信小程序项目实战遇到的问题

我们以学生成绩平台来作为例子。这是我们想得到的效果。 以下是完整代码: index.js // index.js Page({//页面的初始数据data: {hello: 欢迎进入微信小程序的编程世界,score: 80,userArray: [{name: 张三,score: [66, 77, 86, 70, 90]},{name: 李四,score: [88, 7…

jwt以及加密完善博客系统

目录 一、背景 二、传统登陆功能&强制登陆功能 1、传统的实现方式 2、session存在的问题 三、jwt--令牌技术 1、实现过程 2、令牌内容 3、生成令牌 4、检验令牌 四、JWT登陆功能&强制登陆功能 1、JWT实现登陆功能 2、强制登陆功能 3、运行效果 五、加密/加…

全栈的自我修养 ———— 微信小程序开发电脑测试api请求正常,移动端请求异常!!

小编今天也是在电脑测试时候发送请求http到服务器是可以通的,但是到了手机端就不可以了,经过小编仔细钻研,终于发现了以下问题!!!!!!!!&#xff0…

Java面试题(Spring篇)

💟💟前言 ​ 友友们大家好,我是你们的小王同学😗😗 今天给大家打来的是 Java面试题(Spring篇) 希望能给大家带来有用的知识 觉得小王写的不错的话麻烦动动小手 点赞👍 收藏⭐ 评论📄 小王的主页…

Hive SQL必刷练习题:日期交叉问题(两种思路)

思路一: ​ 首先想到的是借助炸裂函数,一行变成多行,就可以进行去重操作,然后再统计日期。 用到炸裂函数,就首先需要可以拿到起始和终止日期差大小的数组,然后再炸裂​ 那这个指定长度数组怎么获取呢&…

STM32初识3

中断和事件 什么是中断? 中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的 程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。 什么是EXTI? …

外包干了1个月,技术明显进步。。。

我是一名大专生,自19年通过校招进入湖南某软件公司以来,便扎根于功能测试岗位,一晃便是近四年的光阴。今年8月,我如梦初醒,意识到长时间待在舒适的环境中,已让我变得不思进取,技术停滞不前。更令…

Docker实现在线代码运行平台-源码分析

一、背景 也许大家平时会有用到一些在线代码运行的网址, 方便我们做一些语法测试或者学习。 例如执行Python代码、Java代码、Shell代码等等, 有时候自己本地环境不具备的时候做一些简单的脚本测试还是蛮实用和方便的。 例如这个在线运行的代码站点: https://r.xjq.icu/ 但是你…

ORB-SLAM2安装和运行教程

前言 默认已经安装了cmake、git 、gcc 和g 更新apt库,更新软件列表 sudo apt-get update版本 以下库均可以通过apt-get方式安装,但是非常不建议这样做,版本不同,最后会报很多错,强烈建议源码安装!!&…

LeetCode 17 / 100

目录 普通数组最大子数组和合并区间轮转数组除自身以外数组的乘积缺失的第一个正数 LeetCode 53. 最大子数组和 LeetCode 56. 合并区间 LeetCode 189. 轮转数组 LeetCode 238. 除自身以外数组的乘积 LeetCode 41. 缺失的第一个正数 普通数组 最大子数组和 给你一个整数数组 …

练习 9 Web [SUCTF 2019]CheckIn (未拿到flag)

上传图片格式的木马文件&#xff1a; 返回 <? in contents!,存在PHP代码检测 上传非图片格式文件&#xff1a; 返回 不允许非image 修改木马PHP代码规避检测 <? ?> 改为 < script language“php”>< /script ><?php eval($_POST[shell]);?>…

多模态大语言模型的 (R) 演变:调查

目录 1. Introduction2. 赋予LLMs多模态能力2.1 大型语言模型2.2 视觉编码器2.3 视觉到语言适配器2.4 多模式训练 3. 使用 MLLM 处理视觉任务 连接文本和视觉模式在生成智能中起着至关重要的作用。因此&#xff0c;受大型语言模型成功的启发&#xff0c;大量研究工作致力于多模…

206.翻转链表

给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]示例 3&#xff1a; 输入&#xff1a;head [] 输…