简单分析Swift语言的一些基本特征

Swift是苹果公司最新推出的编程语言,据很多人说,是用来”代替“Objective-C。但是没有确切的证据。我花了一些时间对Swift二进制和运行环境实施逆向工程技术,然后我对Swift有些少许的发现。目前为止,结论就是:Swift是没有消息机制的Objective-C。

对象

信不信由你,Swift中的对象就是Objective-C的对象。在Mach-O二进制文件中,__objc_classlist包含每个二进制文件中类的数据。其结构如下所示:
 

代码如下:

struct objc_class {
    uint64_t isa;
    uint64_t superclass;
    uint64_t cache;
    uint64_t vtable;
    uint64_t data;
};

(注:所有结构都来自64位版本)

注意data记录,它指向了类中的一个列出方法、实例变量和协议等内容的结构体。通常,data是8个字节对齐的,但是对于Swift类,data的最后一位仅为1个字节。

Swift类的真正结构是有一点奇怪的。Swift类没有Objective-C方法。我们将在以后实现它。Swift类的变量存储为实例变量。Swift的getter和setter方法真正修改的是实例变量的值。奇怪的是swift类的实例变量没有类型编码。通常应该指向类型编码的指针为NULL。这大概是由于事实上Objective-C运行时是不支持处理Swift变量本身。

继承

Swift的继承是你所期待的。在Swift中,Square是shape的子类也是Objective-C类Shape的子类。然而,在Swift类中没有超类?

例如

代码如下:

class Shape { }

在这个例子中,Shape类是SwiftObject的子类。SwiftObject是一个根Objective-C类,类似于NSObject。它没有超类,意味着isa指向自身。它的目的是使用Swift运行时方法比如allocation和deallocation代替标准的Objective-C运行时方法。例如,(void)retain不会调用objc_retain,但是它会调用swift_retain。

类方法

就像我之前提到的,Swift对象的类没有方法,以此代替的是类似C++的函数,名称改编和所有东西。这可能是为什么Swift声称比Objective-C更快的原因。不再需要为 objc_msgSend  寻找和调用方法实现。

在Objective-C里面,方法像这样实现:

代码如下:

type method(id self, SEL _cmd, id arg1, id arg2, ...)

Swift 方法非常类似,但是轻微使用了不同的参数排布, self 作为最后一个参数传递,并且没有选择器。

代码如下:

type method(id arg1, id arg2, ..., id self)

虚表

类似C++一样,Swift类也具有一个虚表,用于列出类中的方法。它直接被放置在二进制文件中的类数据之后,并且看起来是这样的:
 

代码如下:

struct swift_vtable_header {
    uint32_t vtable_size;
    uint32_t unknown_000;
    uint32_t unknown_001;
    uint32_t unknown_002;
    void* nominalTypeDescriptor;
    // vtable pointers
}

据我所知,Swift类中的虚表仅在编译期间可见时被使用。否则,它将看起来就是一堆乱糟糟的符号。

命名重整

Swift保持函数的元数据在各自的符号,这就叫做命名重整。元数据宝库奥函数的名称(显而易见的),属性,模块名称,参数类型,返回值类型,还有更多的数据,例如这个例子
 

代码如下:

class Shape{
    func numberOfSides() -> Int {
        return 5
    }
}

simpleDescription方法的重整命名是:

_TFC9swifttest5Shape17simpleDescriptionfS0_FT_Si。下面是详细说明:

_T - 所有Swift符号的前缀,每一个符号都是从_T开始。

F - 函数

C - 类的函数(方法)

9swifttest - 带有长度前缀的模块名

5Shape - 函数所属的类,带有长度前缀

17simpleDescription - 函数名

f - 函数属性。 在这个例子中它是f,这是一个普通函数。

S0_FT- 我不是特别确定这是什么意思,但是它是参数和返回类型开始的标记

‘_' - 这个下划线分割了参数和返回值的类型。因为函数没有带参数,它直接跟在了S0_FT的后面

S - 返回值的开始。'S'代表Swift;返回类型是Swift的内建类型,下一个字符决定了类型

i - 这是Swift的内建类型。一个小写的"I"代表了Int.

函数属性

字符类型

f        普通函数

s        setter

g        getter

d        析构函数

D        释放器

c        构造函数

C        分配器

Swift内部函数

字符类型

a        数组

b        布尔型

c        字符常量

d        双精度浮点数

f        单精度浮点型

i        整型

u        UInt类型

Q        隐式可选

S        字符串型

除了函数之外,还有很多命名转换机制,此处我仅给出一个简短的概述。

挂钩函数

受够了语义这部分,让我们接触点有趣的东西!比方说我们有一个像这样的类:
 

代码如下:

class Shape {
    var numberOfSides: Int;
 
    init(){
        numberOfSides = 5;
    }
}

比如我们想将numberOfSides的值改为4,很多种方法可以做到。我们可以使用MobileSubstrate挂到getter方法中,然后更改返回值,就像这样:

代码如下:

int (*numberOfSides)(id self);
 
MSHook(int, numberOfSides, id self){
    return 4;
}
 
%ctor{
    numberOfSides = (int (*)(id self)) dlsym(RTLD_DEFAULT, "_TFC9swifttest5Shapeg13numberOfSidesSi");
    MSHookFunction(numberOfSides, MSHake(numberOfSides));
}

如果我们创建了一个形状的实例,并且打印出numberOfSides的值,我们得到了4!看起来不错,对不?现在,我知道你可能在想,难道我们不应该是返回一个对象而非常量4吗?

好吧,在Swift里,许多内建类型是书面量来的。一个Int型, 举个例子,和C语言里面的int型一样(尽管它可以是一个长整形——不要让我碰到这种情况)。一个小小的提示,String 类型有点古老,这是一个低位优先的UTF-16字符串,所以没有C的字面量能用。

让我们来做同样的事情,但这一次,我们不是在获取器上,而是在获取器上设钩。

代码如下:

void (*setNumberOfSides)(int newNumber, id self);
 
MSHook(void, setNumberOfSides, int newNumber, id self){
    _setNumberOfSides(4, self);
}
 
%ctor {
    setNumberOfSides = (void (*)(int newNumber, id self)) dlsym(RTLD_DEFAULT, "_TFC9swifttest5Shapes13numberOfSidesSi");
    MSHookFunction(setNumberOfSides, MSHake(setNumberOfSides));
}

再尝试一下,然后。。。。。。还是5。怎么回事,你问?好吧,在Swift里某些地方,函数是内联化的。类构造器就是其中一个的地方。它直接设置numberOfSides 为ivar, 设置器将仅在数值再次被顶层代码设置的时候被调用。在那被调用,你知道么,我们得到了4。

最终,让我们通过直接设置实例变量的值来修改numberOfSides。

代码如下:

void (*setNumberOfSides)(int newNumber, id self);
 
MSHook(void, setNumberOfSides, int newNumber, id self){
    MSHookIvar<int>(self, "numberOfSides") = 4;
}
 
%ctor {
    setNumberOfSides = (void (*)(int newNumber, id self)) dlsym(RTLD_DEFAULT, "_TFC9swifttest5Shapes13numberOfSidesSi");
    MSHookFunction(setNumberOfSides, MSHake(setNumberOfSides));
}

这个函数是可以实现功能的,虽然不建议这样做,但是确实有效果。

这是目前我所要写的内容。当然,还有很多其他的内容我正在看,包括witness表,由于我了解不多,所以这里我也没办法写出总结。很多内容在这篇文章里有变更,他们仅是我目前对运行和查看用Swift语言编译的二进制文件逆向工程操作所得到的东西。

我所发现的东西应该是非常不错的,这意味着MobileSubstrate不会随着Objective-C一同消亡,并且,微调仍然可以进行!我很想知道将来在越狱场景下的应用商店中将会是怎样一番情景……难道logo可以更新用来自动销毁命名?甚至是处理常见的 Swift 类型的库……

如果你发现更多的关于Swift如何工作的东西,不要犹豫,请让我知道!

(0)

相关推荐

  • 浅谈在Swift中关于函数指针的实现

    Swift没有什么? 苹果工程师给我建的唯一一堵墙是:在Swift中没有任何办法获得一个函数的指针: 注意,C函数指针不会导入到Swift中(来自"Using Swift with Cocoa and Objective-C") 但是我们怎么知道这种情况下钩子的地址和跳到哪呢?让我们深入了解一下,并且看看Swift的func在字节码层面上的是什么. 当你给一个函数传递一个泛型参数时,Swift并没有直接传递它的地址,而是一个指向trampoline函数(见下文)并带有一些函数元数据信息

  • 在Mac OS的终端中运行Swift应用的方法

    在读完苹果开发者文档( Apple Developer Docs)后,我发现: "Xcode的调试器包括一个Swift语言的交互版本,叫做REPL(Read-Eval-Print-Loop)...可以通过Xcode的控制台或终端来访问" 不幸的是,它并没有告诉你怎样从终端访问.好在这也不是什么难事. 输入如下命令即可(无论你用哪个beta,换掉app的名字) 复制代码 代码如下: alias swift="/Applications/Xcode6-Beta2.app/Cont

  • 在Swift程序中实现手势识别的方法

    在这次IOS应用开发教程中,我们打算实现手势识别.正如你所知道的,IOS支持大量的手势操作,它们能提供了很好的应用控制和出色用户体验. 让我们开始吧! 首先需要在Xcode中创建一个新的Single View Application: 然后点击Next,弹出的窗口要求你填写项目设置.在第一栏 ("Product name") 中填入项目名称后,点击Next. 确保语言选择的是 "Swift". 设计界面 点击 "Main.storyboard"

  • 简单分析Swift语言的一些基本特征

    Swift是苹果公司最新推出的编程语言,据很多人说,是用来"代替"Objective-C.但是没有确切的证据.我花了一些时间对Swift二进制和运行环境实施逆向工程技术,然后我对Swift有些少许的发现.目前为止,结论就是:Swift是没有消息机制的Objective-C. 对象 信不信由你,Swift中的对象就是Objective-C的对象.在Mach-O二进制文件中,__objc_classlist包含每个二进制文件中类的数据.其结构如下所示:   复制代码 代码如下: struc

  • 简单分析C语言中指针数组与数组指针的区别

    首先来分别看一下,指针数组的一个小例子: #include <stdio.h> #include <string.h> int lookup_keyword(const char*key, const char* table[], const int size) { int ret = -1; int i = 0; for(i=0; i<size; i++) { if (strcmp(key, table[i]) == 0) { ret = i; break; } } ret

  • 详解Swift语言中的类与结构体

    类 在 Swift 中类是建立灵活的构建块.类似于常量,变量和函数,用户可以定义的类的属性和方法.Swift给我们提供了声明类,而无需用户创建接口和实现文件的功能.Swift 允许我们创建类作为单个文件和外部接口,将默认在类一次初始化来创建. 使用类的好处: 继承获得一个类的属性到其他类 类型转换使用户能够在运行时检查类的类型 初始化器需要处理释放内存资源 引用计数允许类实例有一个以上的参考 类和结构的共同特征: 属性被定义为存储值 下标被定义为提供访问值 方法被初始化来改善功能 初始状态是由初

  • 分析Swift性能高效的原因

    自从2014年Apple发布Swift语言以来,历时六年多,Swift已经发布到5.3版本,在5.0版本已经ABI stability,5.2版本也已经module stability,不管是语言还是基础库都日趋稳定,目前国内外大厂也都积极拥抱Swift阵营. 绝大多数公司选择Swift语言开发iOS应用,主要原因是因为Swift相比Objc有更快的运行效率,更加安全的类型检测,更多现代语言的特性提升开发效率:这一系列的优点使Swift语言的热度越来越高. 大多数人知道Swift语言相比于Obj

  • swift语言Codable 用法及原理详解

    目录 Codable Codable 的用法 JSON 和 模型的相互转换 解码(JSON Data -> Model): 编码(Model -> JSON Data): Codable 支持的数据类型 基础数据类型 Date 嵌套对象 枚举 自定义 CodingKeys Codable 的原理 Decodable 协议 Container 核心原理分析(Container <--> JSON) JSONDecoder 的解码过程 编译器帮我们做了什么? 默认值问题 属性包装器 @

  • swift语言AutoreleasePool原理及使用场景

    目录 使用场景 NSAutoreleasePool @autoreleasepool __autoreleasing 源码分析 __AtAutoreleasePool结构体 AutoreleasePoolPage POOL_BOUNDARY 多层嵌套 push autoreleaseFast autoreleaseFullPage autoreleaseNoPage add pop popPage releaseUntil autorelease hotPage coldPage 调试 _obj

  • Swift语言与Applescript的区别?AppleScript的发展状况?

    本人为非开发人员(科研工作者),使用Mac,最近了解到Applescript对提高工作效率有很多帮助,希望学一下Applescript.不过最近10.10系统将发布,新的swift语言据说也能实现AppleScript的功能.我希望能了解Applescript最近的发展状况(Apple是否会逐渐淘汰这门语言),以及学习了swift是不是就不用学AppleScript了.希望高人解答,感谢大家 1.什么是applescript AppleScript是用在MacOSX上的脚本语言,和操作系统结合的

  • 苹果公司编程语言Swift语言简介

    Swift 是一门新的编程语言,用于编写 iOS 和 OS X 应用程序.Swift 结合了 C 和 Objective-C 的优点并且不受C兼容性的限制.Swift 使用安全的编程模式并添加了很多新特性,这将使编程更简单,扩展性更强,也更有趣.Swift 支持 Cocoa 和 Cocoa Touch 框架. Swift 的开发从很久之前就开始了.为了给 Swift 打好基础,苹果公司改进了编译器,调试器和框架结构,让 Swift 使用自动引用计数(Automatic Reference Cou

  • 深入理解Swift语言中的闭包机制

    在 Swift 中的闭包类似于结构块,并可以在任何地方调用,它就像 C 和 Objective C 语言内置的函数. 函数内部定义的常数和变量引用可被捕获并存储在闭包.函数被视为封闭的特殊情况,它有 3 种形式. 在 Swift 语言闭合表达式,如下优化,重量轻语法风格,其中包括: 推导参数并从上下文菜单返回值的类型 从单封表达的隐性返回 简略参数名称 尾部闭包语法 语法 下面是一个通用的语法定义用于闭包,它接受参数并返回数据的类型: 复制代码 代码如下: {(parameters) -> re

  • Swift语言中的函数学习教程

    函数是一个组织在一起语句集合,以执行特定任务.Swift 函数类似于简单 C 函数以及复杂的 Objective C 语言函数. 它使我们能够通过函数调用内部的局部和全局参数值. 像其他任何语言一样 swift 函数也遵循相同的步骤. 函数声明:它告诉编译器有关的函数的名称,返回类型和参数. 函数定义:它提供函数的实际主体. Swift 函数包含参数类型和返回类型. 函数定义 在Swift 语言中函数是由 "func" 关键字来定义.当一个新定义函数时,它可能需要一个或几个值作为函数输

随机推荐