簡單分析Swift語言的一些基本特征
Swift是蘋果公司最新推出的編程語言,據(jù)很多人說,是用來”代替“Objective-C。但是沒有確切的證據(jù)。我花了一些時(shí)間對Swift二進(jìn)制和運(yùn)行環(huán)境實(shí)施逆向工程技術(shù),然后我對Swift有些少許的發(fā)現(xiàn)。目前為止,結(jié)論就是:Swift是沒有消息機(jī)制的Objective-C。
對象
信不信由你,Swift中的對象就是Objective-C的對象。在Mach-O二進(jìn)制文件中,__objc_classlist包含每個(gè)二進(jìn)制文件中類的數(shù)據(jù)。其結(jié)構(gòu)如下所示:
struct objc_class {
uint64_t isa;
uint64_t superclass;
uint64_t cache;
uint64_t vtable;
uint64_t data;
};
(注:所有結(jié)構(gòu)都來自64位版本)
注意data記錄,它指向了類中的一個(gè)列出方法、實(shí)例變量和協(xié)議等內(nèi)容的結(jié)構(gòu)體。通常,data是8個(gè)字節(jié)對齊的,但是對于Swift類,data的最后一位僅為1個(gè)字節(jié)。
類
Swift類的真正結(jié)構(gòu)是有一點(diǎn)奇怪的。Swift類沒有Objective-C方法。我們將在以后實(shí)現(xiàn)它。Swift類的變量存儲為實(shí)例變量。Swift的getter和setter方法真正修改的是實(shí)例變量的值。奇怪的是swift類的實(shí)例變量沒有類型編碼。通常應(yīng)該指向類型編碼的指針為NULL。這大概是由于事實(shí)上Objective-C運(yùn)行時(shí)是不支持處理Swift變量本身。
繼承
Swift的繼承是你所期待的。在Swift中,Square是shape的子類也是Objective-C類Shape的子類。然而,在Swift類中沒有超類?
例如
在這個(gè)例子中,Shape類是SwiftObject的子類。SwiftObject是一個(gè)根Objective-C類,類似于NSObject。它沒有超類,意味著isa指向自身。它的目的是使用Swift運(yùn)行時(shí)方法比如allocation和deallocation代替標(biāo)準(zhǔn)的Objective-C運(yùn)行時(shí)方法。例如,(void)retain不會調(diào)用objc_retain,但是它會調(diào)用swift_retain。
類方法
就像我之前提到的,Swift對象的類沒有方法,以此代替的是類似C++的函數(shù),名稱改編和所有東西。這可能是為什么Swift聲稱比Objective-C更快的原因。不再需要為 objc_msgSend 尋找和調(diào)用方法實(shí)現(xiàn)。
在Objective-C里面,方法像這樣實(shí)現(xiàn):
Swift 方法非常類似,但是輕微使用了不同的參數(shù)排布, self 作為最后一個(gè)參數(shù)傳遞,并且沒有選擇器。
虛表
類似C++一樣,Swift類也具有一個(gè)虛表,用于列出類中的方法。它直接被放置在二進(jìn)制文件中的類數(shù)據(jù)之后,并且看起來是這樣的:
struct swift_vtable_header {
uint32_t vtable_size;
uint32_t unknown_000;
uint32_t unknown_001;
uint32_t unknown_002;
void* nominalTypeDescriptor;
// vtable pointers
}
據(jù)我所知,Swift類中的虛表僅在編譯期間可見時(shí)被使用。否則,它將看起來就是一堆亂糟糟的符號。
命名重整
Swift保持函數(shù)的元數(shù)據(jù)在各自的符號,這就叫做命名重整。元數(shù)據(jù)寶庫奧函數(shù)的名稱(顯而易見的),屬性,模塊名稱,參數(shù)類型,返回值類型,還有更多的數(shù)據(jù),例如這個(gè)例子
class Shape{
func numberOfSides() -> Int {
return 5
}
}
simpleDescription方法的重整命名是:
_TFC9swifttest5Shape17simpleDescriptionfS0_FT_Si。下面是詳細(xì)說明:
_T - 所有Swift符號的前綴,每一個(gè)符號都是從_T開始。
F - 函數(shù)
C - 類的函數(shù)(方法)
9swifttest - 帶有長度前綴的模塊名
5Shape - 函數(shù)所屬的類,帶有長度前綴
17simpleDescription - 函數(shù)名
f - 函數(shù)屬性。 在這個(gè)例子中它是f,這是一個(gè)普通函數(shù)。
S0_FT- 我不是特別確定這是什么意思,但是它是參數(shù)和返回類型開始的標(biāo)記
‘_' - 這個(gè)下劃線分割了參數(shù)和返回值的類型。因?yàn)楹瘮?shù)沒有帶參數(shù),它直接跟在了S0_FT的后面
S - 返回值的開始。'S'代表Swift;返回類型是Swift的內(nèi)建類型,下一個(gè)字符決定了類型
i - 這是Swift的內(nèi)建類型。一個(gè)小寫的"I"代表了Int.
函數(shù)屬性
字符類型
f 普通函數(shù)
s setter
g getter
d 析構(gòu)函數(shù)
D 釋放器
c 構(gòu)造函數(shù)
C 分配器
Swift內(nèi)部函數(shù)
字符類型
a 數(shù)組
b 布爾型
c 字符常量
d 雙精度浮點(diǎn)數(shù)
f 單精度浮點(diǎn)型
i 整型
u UInt類型
Q 隱式可選
S 字符串型
除了函數(shù)之外,還有很多命名轉(zhuǎn)換機(jī)制,此處我僅給出一個(gè)簡短的概述。
掛鉤函數(shù)
受夠了語義這部分,讓我們接觸點(diǎn)有趣的東西!比方說我們有一個(gè)像這樣的類:
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));
}
如果我們創(chuàng)建了一個(gè)形狀的實(shí)例,并且打印出numberOfSides的值,我們得到了4!看起來不錯(cuò),對不?現(xiàn)在,我知道你可能在想,難道我們不應(yīng)該是返回一個(gè)對象而非常量4嗎?
好吧,在Swift里,許多內(nèi)建類型是書面量來的。一個(gè)Int型, 舉個(gè)例子,和C語言里面的int型一樣(盡管它可以是一個(gè)長整形——不要讓我碰到這種情況)。一個(gè)小小的提示,String 類型有點(diǎn)古老,這是一個(gè)低位優(yōu)先的UTF-16字符串,所以沒有C的字面量能用。
讓我們來做同樣的事情,但這一次,我們不是在獲取器上,而是在獲取器上設(shè)鉤。
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里某些地方,函數(shù)是內(nèi)聯(lián)化的。類構(gòu)造器就是其中一個(gè)的地方。它直接設(shè)置numberOfSides 為ivar, 設(shè)置器將僅在數(shù)值再次被頂層代碼設(shè)置的時(shí)候被調(diào)用。在那被調(diào)用,你知道么,我們得到了4。
最終,讓我們通過直接設(shè)置實(shí)例變量的值來修改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));
}
這個(gè)函數(shù)是可以實(shí)現(xiàn)功能的,雖然不建議這樣做,但是確實(shí)有效果。
這是目前我所要寫的內(nèi)容。當(dāng)然,還有很多其他的內(nèi)容我正在看,包括witness表,由于我了解不多,所以這里我也沒辦法寫出總結(jié)。很多內(nèi)容在這篇文章里有變更,他們僅是我目前對運(yùn)行和查看用Swift語言編譯的二進(jìn)制文件逆向工程操作所得到的東西。
我所發(fā)現(xiàn)的東西應(yīng)該是非常不錯(cuò)的,這意味著MobileSubstrate不會隨著Objective-C一同消亡,并且,微調(diào)仍然可以進(jìn)行!我很想知道將來在越獄場景下的應(yīng)用商店中將會是怎樣一番情景……難道logo可以更新用來自動銷毀命名?甚至是處理常見的 Swift 類型的庫……
如果你發(fā)現(xiàn)更多的關(guān)于Swift如何工作的東西,不要猶豫,請讓我知道!
相關(guān)文章
Swift實(shí)現(xiàn)JSON轉(zhuǎn)Model的方法及HandyJSON使用講解
這篇文章給大家介紹了Swift實(shí)現(xiàn)JSON轉(zhuǎn)Model的方法及HandyJSON使用講解,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-07-07
Swift并發(fā)系統(tǒng)并行運(yùn)行多個(gè)任務(wù)使用詳解
這篇文章主要為大家介紹了Swift并發(fā)系統(tǒng)并行運(yùn)行多個(gè)任務(wù)使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
Objective-C和Swift的轉(zhuǎn)換速查手冊(推薦)
這篇文章主要給大家介紹了關(guān)于Objective-C和Swift的轉(zhuǎn)換速查手冊的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),非常推薦給大家參考學(xué)習(xí)使用,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)不2018-06-06
swift中c風(fēng)格的for循環(huán)執(zhí)行效率
這篇文章主要介紹了swift中c風(fēng)格的for循環(huán)執(zhí)行效率 的相關(guān)資料,需要的朋友可以參考下2016-07-07

