2013-12-18 145 views
0

我有一個使用共享庫的正在運行的進程。重新映射共享庫

有沒有辦法將共享庫重新映射到另一個虛擬地址,然後將舊映像重新映射,將進程地址更新爲新的共享對象地址並繼續運行?

+1

如果給mmap()提供了正確的選項,你也許可以映射這個庫的一個新副本,但它只是文件的映射,而不是解釋和分割成文本/數據等等。像加載器或'dlopen()'這樣的節會給。 'dlopen()'可能會讓你回到現有的副本。取消映射現有的副本很可能是不可能的,因爲如果允許的話,它可能會對進程造成致命的影響...... – twalberg

回答

1

肯定不是在進程運行時,如果它沒有準備好這樣做。請記住,共享庫代碼是一回事,共享庫內的數據結構是另一回事。指向庫中靜態定義的數據結構的指針可能只存在於您的進程中的任何位置,而您無法更改它們。

現在,如果你想寫一個新的程序,應該允許這個,它不應該太難。對共享庫沒有靜態依賴關係,使用dlopen()將其打開,並使用dlsym()獲取函數。讓你的進程捕捉到SIGUSR1這樣的信號,並在信號處理程序中(更好:在主循環中的某個安全點檢測到信號處理程序調用時設置的標誌)丟棄舊庫,加載新庫並調整相應的符號。

+0

我想要做以下操作,讓父母取消映射並重新映射庫,然後再分叉孩子,孩子將要使用重新映射的庫,我如何解決所有符號,以便孩子能夠正確運行?我應該爲每個符號調用dlsym嗎? –

0

如果您知道共享庫沒有被執行(即不在調用堆棧中),那麼執行該操作相當容易。只需dlclose()該庫,然後再次dlopen()。如果你需要一個圖書館的處理,你可以自己dlopen(),然後關閉它兩次。我相信這會起作用,因爲引用計數將達到零,並且庫將被取消映射(除非最初加載的庫以某種方式特殊裝入)。如果你可以避免共享庫的鏈接時依賴(只需在ELF構造函數中調用dlopen),這肯定會起作用。

如果您正在手動加載新庫(如果您希望能夠選擇其加載地址),則可以簡單地自行覆蓋PLT條目。我寫了一個工具,它做了一些非常相似的工作,如https://github.com/dwks/asyncsafe。如果您覆蓋每個PLT條目以指向解析函數,則懶惰符號加載將自動再次發生;或者,你可以自己解決它們。

我確定你知道Blind ROP學術攻擊(http://www.scs.stanford.edu/~abelay/pdf/bittau:brop.pdf)。這種攻擊有幾種防禦措施可以滿足你的要求,試着搜索文獻。