目錄
- • Windows CE跨進程記憶體注入之原理
- • 一、程式實現的先決條件
- • 二、程式實現的基本原理
編輯本段 回目錄Windows CE跨進程記憶體注入之原理
近日,由於程式設計需要,我對WincowsCE 的記憶體布局進行了研究,由於發現國內在這方面的文檔資料較少,於是在研究告一段落之際,形成這篇範例文件,以望拋磚引玉。
編輯本段 回目錄一、程式實現的先決條件
由於Windows系統的表單訊息總是投遞至一個特定進程的指定表單訊息函數中。於是在本地進程(自己的應用程式)中取得屬於其它進程的表單的訊息必須實現以下兩個部分:
1、將需要掛接表單的代碼放到目標進程的地址空間中去。
2、執行這一段代碼,並獲得目標進程表單的訊息。
這兩步看起來很簡單,但在實現過程中就比較困難。由於Windows CE作為嵌入式行動裝置作業系統,與Windows 98/2000/XP等案頭作業系統在核心的設計理念以及API的支援上有極大的區別。這就直接導致了常規的案頭系統利用全域滑鼠鉤子注入/遠程線程注入等方法在CE中完全得不通。不過可喜的是,微軟在開發工具中提供的remotexxx等遠端偵錯程式使我清楚這個目標並不是不可能的任務,微軟既然可以做到,那就是說在CE的內部一定有一套完整的跨進程記憶體訪問/代碼注入的機制。
編輯本段 回目錄二、程式實現的基本原理
經過兩天的google 搜尋,在網上我發現了一個沒有在微軟文檔中聲明的有趣的API函數:PerformCallBack4,傳說中這個函數可以在自己的應用程式中執行指定的進程中的一個函數,So Cool!這好象正是我所需要的東西。雖然網上也傳聞這個函數在wm5不受支援,其實經過實踐這個傳聞只是謠傳而已!
PerformCallBack4函數的定義:
[DllImport("coredll.dll")]
public static extern uint PerformCallBack4(ref CallBackInfo CallBackInfo,
IntPtr ni_pVoid1,IntPtr ni_pVoid2,IntPtr ni_pVoid3);
其中函數的參數CallBackInfo結構定義:
[StructLayout(LayoutKind.Sequential)]
public struct CallBackInfo
{
public IntPtr hProc; //遠端目標進程
public IntPtr pfn; //指向遠程目標進程的函數地址的指標
public IntPtr pvArg0; //函數的需要的第一個參數
}//end struct
而PerformCallback4的 ni_pVoid1、ni_pVoid2、ni_pVoid3為傳遞到遠程目標進程執行函數的其它三個參數。
至於將代碼放到目標進程的記憶體空間,我們可以利用CE設計上的一個特性:
1、為了節約記憶體使用量,CE將所有程式調用的動態連結程式庫(DLL)都映射到同一個記憶體位址中。
2、CE的記憶體布局中劃分有一個slot0的記憶體位置,這個記憶體位置是由正在執行的進程所佔有的,每一個特定的時間片,只能有一個進程可以佔有這個記憶體空間。在進程要求執行時,系統並不直接執行進程所處記憶體位置的代碼,而是將該進程的執行代碼複製到slot0的記憶體位置中產生一個副本執行。也就是說進程在執行時記憶體將會有進程執行代碼的兩個完全一樣的版本:存在於slot0中正在執行的進程代碼和進程本身所處的記憶體中的代碼。
在這個特性下,可以得到結論:如果進程A通過LoadLibrary函數裝載Test.dll,而進程B也通過LoadLibrary函數裝載同一個Test.dll,這個Test.dll的所有函數在進程A和進程B中執行時,相對於slot0中的進程執行代碼都會得到同一地址。
3、在CE中,系統在記憶體中劃分出33個slot,slot0保留給正在執行的進程,然後在進程啟動時將所有的代碼放到除slot0以外的一個slot中(這就是臭名昭著的CE系統中記憶體最多隻能有不多於32個程式執行的限制的來由)。在進程執行時,每個應用程式的記憶體訪問預設只能訪問slot0記憶體空間中的地址以及進程所處的slot記憶體空間的地址。 但為使裝置驅動程式可以訪問到它們所需的其它應用程式資料,CE提供了兩個函數以打破這個限制,SetKmode和SetProcPermission,SetKmode函數告訴系統,當前啟動並執行進程是否需要在核心模式中執行;SetProcPermission函數可以接受一個位元遮罩,每一位代碼一個slot的存取控制,1代表可以訪問該slot的記憶體內容。0表示不能訪問該slot的記憶體內容。這兩個函數在msdn中有協助文檔,可參閱msdn的文檔說明。