吾愛破解 - LCG - LSG |安卓破解|病毒分析|破解軟件|www.dypczhxn.cn

 找回密碼
 注冊[Register]

QQ登錄

只需一步,快速開始

搜索
查看: 3786|回復: 30
上一主題 下一主題

[調試逆向] Mac下 XX 及任意程序的內置瀏覽器調試的實現

  [復制鏈接]
跳轉到指定樓層
樓主
zwo 發表于 2019-12-5 22:24 回帖獎勵
本帖最后由 zwo 于 2019-12-5 22:41 編輯

0x0 前言
在iOS以及Mac上,Safari提供了功能強大的基于webkit的調試器功能,方便開發者調試APP的內置瀏覽器。在某聊天軟件盛行的今天,很多網頁都必須在該軟件的內置瀏覽器里才能運行,作為開發者的我們,如果想一窺這類網頁的實現細節該怎么辦呢?在浩瀚的網絡里搜了一下,安卓可以通過Chrome來調試,iOS系統越獄后,通過FrIDA也能做到,唯獨Mac系統甚少提及。這篇文章里,我嘗試通過逆向的手段,達到對任意APP的內置瀏覽器實現調試。

0x1 原理分析
從現有的資料,可以查到,Safari判斷是否可以進行調試依賴于守護進程 webinspectord ,而實際的邏輯判斷實現在動態庫WebInspector中,其路徑為
/System/Library/PrivateFrameworks/WebInspector.framework/Versions/A/WebInspector

而其中的關鍵函數為簽名如下的ObjC方法:
[Objective-C] 純文本查看 復制代碼
-[RWIRelayDelegateMac _allowApplication:bundleIdentifier:];

放進IDA分析這個方法的實現過程,整個流程,可以注釋如下:

分析可得,要使這個方法返回真,有以下幾個條件
  • 為內部程序,即isInternal為真,且debugEverything為真
  • 是代{過}{濾}理應用(包名包含com.apple.WebKit.WebContent),即isProxyApplication函數返回1.
  • 應用簽名包含com.apple.security.get-task-allow權限
  • 應用簽名包含com.apple.webinspector.allow權限
以上條件實現任一即可。對于普通開發者來說,最可操作的是第3點,只要用Mac開發證書重簽名應用即可達成。但是重簽也是有局限性的,會造成某些重要entitlement丟失從而導致運行不正常。根據以上的分析,我們來嘗試一下如何用技術的手段實現。
在開始之前,需要做的第一件事情是關閉系統的SIP以及taskgated。因為我們需要修改系統的實現,就需要獲得目標進程的task,獲得了task,也就得到了該進程的控制權,系統的SIP正是保護這一機制不被濫用,攔截不信任的應用調用task_for_pid()以獲得task。另一個安全機制taskgated對調用敏感內核函數的程序進行簽名校驗,也要關閉。關于關閉的方法網上有大量資料,不再累述。


0x2 嘗試
由于我們要修改的為一個ObjC方法,首先想到的就是最常用最方便的method swizzling技術,我們參考iOS的版本,直接用以下的Frida腳本驗證一下:
[JavaScript] 純文本查看 復制代碼
Interceptor.attach(ObjC.classes.RWIRelayDelegateMac['- _allowApplication:bundleIdentifier:'].implementation, {
  onEnter: function(args) {
    this.bundleId = new ObjC.Object(args[3]);
  },
  onLeave: function(retVal) {
    const allow = !retVal.equals(NULL)
    console.log(this.bundleId + (allow ? ' allows' : ' does not allow') + ' WebInspect')
    if (!allow) {
      console.log('now patch it');
      retVal.replace(ptr(1));
    }
  }
});


打開Safari后,在命令行輸入frida webinspectord進入frida界面提示,輸入以上的JavaScript腳本。然后在某聊天軟件打開任意文章以拉起webview,這時可以看到frida給出進程終止的提示。
frida不起作用,而我對frida的注入機制也不了解,只能靠自己來實現對webinspectord的注入了。對于在Mac上可以實現進程注入的技術手段,據我所知有以下三種:
  • 線程注入
  • 線程劫持
  • XPC助手服務
其中線程劫持這種遠程注入的難度太大,因為要從進程中取出某個線程,保存當前線程的狀態,運行劫持代碼,再恢復原來的狀態,非常容易造成線程出錯。我在嘗試了另外兩種方法后,都以webinspectord的crash而失敗告終。打開系統的日志,可以看到如下的輸出:



通過命令行輸入$security error -67050可以查看這個出錯的詳細說明,英文就不寫出來了,用人話來說,就是“不符合某些要求”,但是沒指名是什么要求。這個錯誤是amfid進程發出的,查閱相關資料,有點頭緒了,我們來分析一下。

我是首先生成一個動態庫dylib,內容很簡單,在初始化函數中利用method swizzling令-[RWIRelayDelegateMac _allowApplication:bundleIdentifier:]始終返回真。而注入程序首先是通過task_for_pid()獲取webinspectord的task,并在webinspectord的進程空間里通過mach_vm_allocate函數分配代碼空間和棧空間。然后將dlopen()加載動態庫所在路徑的相關匯編代碼通過mach_vm_write()函數寫入到剛才開辟的代碼空間中。最后通過結構體x86_thread_state64_t設置線程的棧指針RSP和棧基指針RBP指向棧空間底部,通過thread_create_running創建并運行線程。一切看起來如此正常,然而即使dylib和注入程序都用開發者證書簽名,依然過不了amfid的攔截。

amfid (Apple Mobile File Integrity daemon) 蘋果可移動文件完整性守護進程,對系統的保護簡單而高效。在Mac系統里,當一個程序被簽名的時候,簽名工具codesign會對該程序的二進制文件的每個頁(page)計算一個哈希值,以及所有哈希值一起計算出一個總的哈希值。對于Mac系統以及Linux系統,內核通過page fault的機制來分配內存, 當我們訪問一個內存地址時,如果該地址非法,或者我們對其沒有訪問權限,或者該地址對應的物理內存還未分配,內核都會生成一個page fault,進而執行操作系統的page fault handler。 在Mac上,還有一種情況會產生page fault,當某個文件(例如dylib)被內核以mmap函數映射進進程的虛擬內存中。這個時候amfid會校驗新進來的內存頁是否有簽名,簽名是否與當前執行的二進制程序一致,如果沒有簽名或者簽名的哈希值不一致,那么加載過程將中斷,對于某些蘋果簽名的二進制,系統為了安全起見會直接kill掉該二進制,webinspectord就是個例子。故事到了這里,如果要繼續發展下去,就需要patch amfid了,了解過iOS越獄的朋友會知道,越獄其中關鍵的一步就是patch amfid,可見這條路一定是荊棘叢叢,先暫不考慮。我想到的另一個辦法是內存補丁,既然系統不允許我們加載我們的代碼,那就直接改內部實現好了,也就是我接下來要說的內存補丁。

0x3 內存補丁

回顧圖1的流程圖,已知其中一個可以實現調試的條件是函數isProxyApplication返回1,觀察了一下判斷過程,驚喜的發現,非常容易扭轉狀態,見下圖:


首先是給bl寄存器賦值1,然后判斷存放isProxyApplication返回值的al寄存器是否不為零,如果不為零則跳轉到結束并把bl的值1返回。很容易想到把test al, al改為test bl, bl即可。用機器碼來表示就是84 C0改為84 DB


現在面臨的最大問題也是整個實現過程最大的挑戰,已知這段代碼在虛擬內存中的位置是0x6DAAF,如何確定在進程的虛擬內存中的位置?這段代碼是以系統共享動態庫的形式加載進webinspectord的內存空間。我首先想到的方法是通過mach_vm_region_recurse函數枚舉出所有進程中活躍的內存塊(region)并搜索mach-o的文件頭以找到動態庫的開始位置。然而實際的輸出內存區間卻沒有我想象中那樣可以對齊到動態庫的起始頭位置,對比一下vmmap的輸出如下:


嘗試了若干方法后,始終沒辦法獲得準確的偏移量,百般無奈下,我只好采取最沒技術含量的方法,直接調用命令行vmmap獲取偏移量。在這里我也問一下論壇里的大牛,如何通過代碼計算某個動態庫加載后的偏移量?

獲得vmmap的輸出后,字符串查找代碼所在的動態庫的名稱WebInspect從而定位到所在行,系統從dyld cache中映射共享動態庫到進程的虛擬內存空間中,起始位置的16位數字一定是以00007ff開頭(根據shared_region.h中的定義,起始偏移 SHARED_REGION_BASE_X86_64 = 0x00007FFF7000000),通過正則表達匹配出開始和結束位置,從而獲得偏移值。以上圖為例子,需要打補丁的位置就在0x7fff90432000 + 0x6daaf。

先打開Safari,然后運行程序,在聊天軟件中打開一篇公眾號文章,可以看到該文章的地址已經出現在Safari的開發調試列表中。


點擊文章的URL即可進入調試界面,開始愉快的調試了。



代碼在Mojave、High Sierra兩個版本的系統上測試過。由于是內存補丁,重啟Safari后就會失效。
完整代碼在這里 https://github.com/zwo/patch_webinspect

免費評分

參與人數 14吾愛幣 +13 熱心值 +12 收起 理由
RSu52 + 1 用心討論,共獲提升!
劣酒先生 + 1 + 1 已經處理,感謝您對吾愛破解論壇的支持!
小魚兒飛呀飛 + 1 + 1 [email protected]
poisonbcat + 1 + 1 [email protected]
Tairraos + 1 + 1 用心討論,共獲提升!
zgrm1000 + 1 + 1 熱心回復!
cheer1219 + 1 + 1 [email protected]
jason94 + 1 [email protected]
bricher9988 + 1 + 1 鼓勵轉貼優秀軟件安全工具和文檔!
fsrank + 1 + 1 [email protected]
52破解18118 + 1 + 1 我很贊同!
gaosld + 1 + 1 用心討論,共獲提升!
zhangkun910625 + 1 + 1 厲害,贊
shyocean + 1 用心討論,共獲提升!

查看全部評分

發帖前要善用論壇搜索功能,那里可能會有你要找的答案或者已經有人發布過相同內容了,請勿重復發帖。

推薦
 樓主| zwo 發表于 2019-12-25 23:04 <
RSu52 發表于 2019-12-25 12:30
這個可以自動增加一個hook, 每次啟動時自動內存補丁嗎? 小白求問這方面的文章或資料, 謝謝大神!

我的理解是啟動Safari的時候啟動補丁程序,對嗎?這樣的話,可以簡單改一下這個補丁程序,先kill了Safari,然后重啟一個,并且打補丁,以后就通過此程序來打開Safari。如果是要做成完全自動化,就需要寫腳本,不斷的pgrep Safari來檢測是否啟動,一旦啟動就打補丁。不太建議直接hook系統的東西,catalina的runtime hardening很強大,hook起來費勁。
推薦
 樓主| zwo 發表于 2019-12-12 15:02 <
A-new 發表于 2019-12-12 10:43
直接patch這個文件不行么

這個文件是蘋果簽名的,直接patch的話,簽名校驗是失敗的,需要繞過蘋果系統的簽名校驗,也就是要patch amfid這個玩意,不過系統也就相當于裸奔了。

點評

蘋果沒怎么玩過,還以為像win直接patch就好  詳情 回復 發表于 2019-12-12 15:06
沙發
shyocean 發表于 2019-12-5 22:48
學習了,分析邏輯清晰,實際操作步驟明確,方法非常好。值得研究學習討論。感謝分享
3#
泥泥的泥泥 發表于 2019-12-5 23:51
講解很詳細,謝謝分享
4#
2Burhero 發表于 2019-12-6 00:47
更加有意思
5#
最酷丶小方方 發表于 2019-12-6 00:49
有點看不懂啊
6#
kone153 發表于 2019-12-6 01:31
講解很詳細,分析邏輯清晰,實際操作步驟明確,方法非常好
7#
展小哥 發表于 2019-12-6 14:58
感謝樓主分享,十分需要這個!
8#
clm10 發表于 2019-12-6 20:17
感謝樓主分享,看看,不懂
9#
twsm321 發表于 2019-12-12 09:32
感謝大神分享啊
10#
阿甘阿Q 發表于 2019-12-12 09:43
感謝分享,試著嘗試了一下
您需要登錄后才可以回帖 登錄 | 注冊[Register]

本版積分規則 警告:禁止回復與主題無關內容,違者重罰!

快速回復 收藏帖子 返回列表 搜索

RSS訂閱|小黑屋|聯系我們|吾愛破解 - LCG - LSG ( 京ICP備16042023號 | 京公網安備 11010502030087號 )

GMT+8, 2020-1-4 19:31

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回復 返回頂部 返回列表
现在靠网络挣钱的方法