日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

iOS逆向之Protocol Witness Table的汇编实现原理

發布時間:2024/5/21 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 iOS逆向之Protocol Witness Table的汇编实现原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、什么是 Protocol Witness Table?

  • 我們都知道 C 函數調用是靜態派發,簡單來說可以理解為是用匯編命令 call $address 來實現,這種方式效率最高,但是靈活性不夠。
  • OC 的方法調用完全是基于動態派發,總是調用 objc_msgSend 實現,這種方式非常靈活,允許各種 Hook 黑科技,但是流程最長,效率最低。
  • 在 Swift 中,協議方法的調用,使用協議方法表的方式完成,也就是 Protocol Witness Table,下文簡稱 PWT。
  • 現有如下代碼:
protocol Drawable {func draw() -> Int }struct Point: Drawable {var x, y: Intfunc draw() -> Int {return x + y} }struct Line: Drawable {var length: Intfunc draw() -> Int {return length} }func foo() -> Int {let p: Drawable = xxxreturn p.draw() }
  • 在 foo 函數中,變量 p 并沒有明確的類型,只知道它遵守 Drawable 協議,實現了 draw 方法。但是編譯時并不能知道,調用的是結構體 Line 還是 Point 的 draw 方法。
  • 因此,PWT 的實現方式是:每個類都會有一個方法表(通過數組來實現),里面保存了它用于實現協議的函數的地址,只要知道一個類的信息和函數信息,就可以實現函數調用,這個方法表,就是 PWT。

二、PWT 的匯編實現

  • 除了從理論上了解 PWT 的概念,還可以從匯編角度來實際感受一下。現有如下代碼:
protocol Drawable {func draw() -> Int }struct Point: Drawable {var x, y: Intfunc draw() -> Int {return x + y} }func foo() -> Int {let p: Drawable = Point(x: 1, y: 2)return p.draw() }
  • Debug 模式下的匯編代碼:
swift-ui-test`foo():0x10518a860 <+0>: push rbp0x10518a861 <+1>: mov rbp, rsp0x10518a864 <+4>: push r130x10518a866 <+6>: sub rsp, 0x480x10518a86a <+10>: mov edi, 0x10x10518a86f <+15>: mov esi, 0x20x10518a874 <+20>: call 0x10518ae50 ; swift_ui_test.Point.init(x: Swift.Int, y: Swift.Int) -> swift_ui_test.Point at ContentView.swift:270x10518a879 <+25>: lea rcx, [rip + 0x1948] ; type metadata for swift_ui_test.Point0x10518a880 <+32>: mov qword ptr [rbp - 0x18], rcx0x10518a884 <+36>: lea rcx, [rip + 0x189d] ; protocol witness table for swift_ui_test.Point : swift_ui_test.Drawable in swift_ui_test0x10518a88b <+43>: mov qword ptr [rbp - 0x10], rcx0x10518a88f <+47>: mov qword ptr [rbp - 0x30], rax0x10518a893 <+51>: mov qword ptr [rbp - 0x28], rdx0x10518a897 <+55>: mov rax, qword ptr [rbp - 0x18]0x10518a89b <+59>: mov rcx, qword ptr [rbp - 0x10]0x10518a89f <+63>: lea rdx, [rbp - 0x30]0x10518a8a3 <+67>: mov rdi, rdx0x10518a8a6 <+70>: mov rsi, rax0x10518a8a9 <+73>: mov qword ptr [rbp - 0x38], rax0x10518a8ad <+77>: mov qword ptr [rbp - 0x40], rcx0x10518a8b1 <+81>: mov qword ptr [rbp - 0x48], rdx0x10518a8b5 <+85>: call 0x10518ae60 ; __swift_project_boxed_opaque_existential_1 at <compiler-generated>0x10518a8ba <+90>: mov rcx, qword ptr [rbp - 0x40]0x10518a8be <+94>: mov rdx, qword ptr [rcx + 0x8]0x10518a8c2 <+98>: mov r13, rax0x10518a8c5 <+101>: mov rdi, qword ptr [rbp - 0x38]0x10518a8c9 <+105>: mov rsi, rcx0x10518a8cc <+108>: call rdx -> 0x10518a8ce <+110>: mov rdi, qword ptr [rbp - 0x48]0x10518a8d2 <+114>: mov qword ptr [rbp - 0x50], rax0x10518a8d6 <+118>: call 0x10518aec0 ; __swift_destroy_boxed_opaque_existential_1 at <compiler-generated>0x10518a8db <+123>: mov rax, qword ptr [rbp - 0x50]0x10518a8df <+127>: add rsp, 0x480x10518a8e3 <+131>: pop r130x10518a8e5 <+133>: pop rbp0x10518a8e6 <+134>: ret
  • 首先按照函數調用來分割下,這里實現了結構體的初始化工作:
0x10518a86a <+10>: mov edi, 0x1 0x10518a86f <+15>: mov esi, 0x2 0x10518a874 <+20>: call 0x10518ae50 ; swift_ui_test.Point.init(x: Swift.Int, y: Swift.Int) -> swift_ui_test.Point at ContentView.swift:27
  • 根據結構體的調用慣例,可以知道返回值是通過 rax 和 rdx 兩個寄存器返回的,當然也可以看下這個函數的內部實現來驗證下,可以看出,Debug 模式下對于理解匯編代碼和進行反匯編都是非常友好的,非常耿直的用一個函數調用告訴我們這里實在創建結構體實例;如果是 Release 模式,大概率是直接對 rax 和 rdx 賦值。
  • 接下來分別把 metadata 和 Point 類的 PWT 表取出,存到棧上,注意到下一個 call 的函數是 __swift_project_boxed_opaque_existential_1 at ,它的存在是由于我們的這種寫法導致:
let p: Drawable = Point(x: 1, y: 2)
  • 這里的 p 就是一個 existential 對象,Drawble 協議是一個 existential type,簡單說結論,這個函數調用以后,入參寄存器 rdi 的內容會被賦值給 rax 寄存器來當做返回值。注意這個函數的入參 rdi 寄存器,是由下面幾個關鍵路徑構成的:
0x10518a89f <+63>: lea rdx, [rbp - 0x30] 0x10518a8a3 <+67>: mov rdi, rdx
  • 因此返回值 rax ,其實就是棧基址 rbp 減掉 0x30,這個地址內存貯的值,是結構體的第一個成員變量 x = 1,順便說一下,這個地址向上(高地址方向)偏移 8 字節,存儲的是第二個成員變量 y = 2。
  • 下一個關鍵操作是 call rdx,它的取值來源是:
0x1073be8be <+94>: mov rdx, qword ptr [rcx + 0x8]
  • 這里的 rcx 經過幾次存儲和取出,可以跟蹤到它最初的源頭,就是:
0x1073be884 <+36>: lea rcx, [rip + 0x189d] ; protocol witness table for swift_ui_test.Point : swift_ui_test.Drawable in swift_ui_test
  • 從邏輯上看,調用了 PWT 內存地址 + 0x8 位置的函數,具體如下:

  • 分析一下:
    • 首先看下 [rip + 0x189d] 的值是多少,在執行這行命令時,rip 的值是下一行命令的地址,即 0x1073be88b,相加后得到 0x000000010518c128;
    • 由于 Hopper、MachoView 等工具只能顯示相對便宜,因此要先減去當前程序在內存中的偏移,可以用 image list swift-ui-test 來查看;
    • 得到結果是 0x4128。
  • 因此 0x4128 就是 Point 結構體的 PWT 的位置,可以在 Hopper 中驗證下:

  • 這里其實是一個指針數組,第一個指針是 0x100003998,內容如下,暫時沒有深入研究其中存儲內容的含義,但是可以看出名字是:protocol conformance descriptor for swift_ui_test.Point : swift_ui_test.Drawable in swift_ui_test:

  • 第二個指針是 0x100002ff0,跳轉過去看下:

  • 從 demangle 后的結果也能看出來,這是一個遵守了協議的證明(Protocol Witness),遵守的協議函數是:Drawable.draw() -> Swift.Int,結構體是 Point,協議名是 Drawable,因此 call rdx 實際上就是調用 call 0x100002ff0。
  • 再來對比下入參和參數,rax 被作為 r13 傳入,函數內部分別把 r13 和 r13 + 8 的位置讀出來,放入 rdi 和 rsi 寄存器。正如前文所述,r13/rax 這個地址上,存儲的是 x 的值,+0x8 則存儲了 y 的值,因此可以理解為把結構體 p 傳入。
  • 最后調用 $s13swift_ui_test5PointV4drawSiyF 這個函數符號,內部邏輯有點啰嗦,猜測是 Debug 環境導致,但本質上就是一個加法運算。

三、結論

  • PWT 是為了解決協議方法調用在編譯時無法確定地址,而引入的中間層;
  • 每個遵守了協議的類,都會有自己的 PWT。遵守的協議中函數越多,PWT 中存儲的函數地址就越多;
  • 準確來說,PWT 是指針數組,但是第一個指針并不是函數指針,而是 protocol conformance descriptor,從第二個開始才是函數指針;
  • 對協議方法的調用,首先會調用一個 PWT address + offset 這個函數,這個函數被叫做 protocol witness,它的內部會做一些參數處理,最后再調用真實的函數;
  • 對于實際被調用的來說,只看它的內部實現,無法和其它函數做出區分,但是可以觀察它的 caller,如果是一個 protocol witness 就可以說明。

總結

以上是生活随笔為你收集整理的iOS逆向之Protocol Witness Table的汇编实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 人人爽人人澡 | 春色校园激情 | 性——交——性——乱免费的 | 九九色综合 | 天天操天天插 | 免费人成在线观看网站 | 香蕉人妻av久久久久天天 | 亚洲视频一区二区三区四区 | 91色视频在线 | 伊人亚洲综合 | 日韩一区在线播放 | 日日干天天爽 | 欧美亚洲黄色 | 久久亚洲热| 日日夜夜网 | 欧美日韩人妻精品一区二区三区 | 免费无毒av| 欧美xxxx黑人又粗又长密月 | 青青久操 | 欧美精品久久久久久久免费 | 高潮疯狂过瘾粗话对白 | 日韩亚洲欧美中文字幕 | 久久精品一区二区三区不卡牛牛 | 日韩视频一区二区三区四区 | 免费高清欧美大片在线观看 | 成片免费观看 | 老外一级片 | 免费大片黄在线观看 | 秋霞网一区 | 鲁一鲁在线视频 | 天堂а√在线中文在线鲁大师 | 欧美变态另类刺激 | 中文字幕在线播放不卡 | 欧美高清69hd | 老太婆av | 午夜青青草 | 妹子色综合 | 午夜激情视频在线 | 四虎视频国产精品免费入口 | 性色av浪潮av | 色综合免费 | 国产999精品久久久久久 | 蜜桃tv一区二区三区 | 五月天综合视频 | 日韩r级在线观看 | 日欧一级片 | 日本熟妇成熟毛茸茸 | 夜夜爽夜夜操 | 女女同性女同一区二区三区九色 | 黄色小说在线视频 | 欧美日本韩国在线 | 91直接看 | 在线手机av | 国产操 | 97人人爽人人| 国产精品国产三级国产aⅴ 欧美bbbbbbbbbbbb18av | av免费网站在线观看 | 精品国产青草久久久久96 | 国产1区在线观看 | 日韩欧美一区二 | 亚洲一区www | 一区二区三区四区亚洲 | 中文字幕人妻一区二区 | 日韩国产免费 | 午夜在线观看视频 | 比利时xxxx性hd极品 | 男人舔女人下部高潮全视频 | 久久涩视频 | 色中文字幕 | 91天天射| 天堂久久av | 国产精品一区二区白浆 | 成年人免费在线观看 | 尤物视频免费观看 | 在线视频污 | 人妻妺妺窝人体色www聚色窝 | 影音先锋中文字幕第一页 | 欧美r级在线观看 | 91福利免费视频 | av片久久 | 久久不卡av | 青青草91久久久久久久久 | a级片免费观看 | 国产一区二区三区四区五区在线 | 在线中文字幕第一页 | 性生交大片免费看狂欲 | 91挑色| 黄色中文字幕 | 欧美激情首页 | 欧美另类在线观看 | 亚洲精品成人a | 波多野结衣片子 | 亚洲第一av网站 | 韩国av在线免费观看 | 大奶一区 | 色婷婷视频网 | 国产精品熟女一区二区不卡 | 日韩精品成人无码专区免费 | 91在线视频免费 |