第1部分(必備知識)

1、錯誤處理

GetLastError,SetLastError,這兩個函數與線程相關的。參數DWORD有分段的含義,比如第29位爲0表示Microsoft定義的錯誤碼,爲1表示客戶端定義的錯誤碼

錯誤翻譯FormatMessage,參數裏面也可以指定語言版本


2、字符和字符串

2.1 字符編碼:Unicode,ANSI

實現Unicode的方式也有UTF8,UTF16,UTF32

比較常用的是UTF8和UTF16。比如同一個字"中",用utf8編碼,char szChinese[];每個char裏面存儲的值和用utf16編碼,存儲的值是不同的

string只是一個內存區,具體存儲一個漢字,使用何種編碼需要上層指定好,然會賦值給char或string

2.2 Unicode和ANSI轉換

MultiByteToWideChar // 多字節轉換爲寬字節,寬字節即Unicode,使用wchar

WideCharToMultiByte

2.3 判斷文本內容是Unicode

IsTextUnicode,該函數只是去猜測文本內容


3、內核對象

1. 每個內核對象都只是一個內存塊,它由操作系統內核分配,並只能由操作系統內核訪問。這個內存塊是一個數據結構,其成員維護着與對象相關的信息。
2.   內核對象,內核對象的所有者是操作系統內核,而非進程。內核對象的生命週期可能長於創建它的進程。操作系統使用計數來確定當前有多少個進程正在使用特定的內核對象。
2.1 創建內核對象:CreateThread,CreateFile,CreateFileMapping等。參數SECURITY_ATTRIBUTES 標記了安全性相關屬性。每個創建內核對象的函數都有該參數。
2.2 關閉內核對象:CloseHandle.
2.3 內核對象句柄表。當創建一個句柄時,會將其插入到內核對象句柄表中,用戶使用create**返回的句柄值時,系統會查找句柄表,如果查找爲空,則會返回無效句柄的錯誤。當調用closehandle時,會清除句柄表中的記錄項,但不一定會銷燬該內核對象,因爲有一個計數器存在,當計數器值未0(沒有任何進程擁有該內核對象了)的時候才銷燬,但記錄肯定會清除,因爲句柄表是和進程相關的。

每個進程都有自己的句柄表,即調用CloseHandle是與調用者的進程相關的,如果傳了一個其它進程的Handle過來,有可能關閉失敗,也有可能剛好關錯了。


進程間共享內核對象的方法:,共享後計數會+1的
句柄繼承:handel的值是相同的
進程名:handle的值是不同的,但是指向同一個內核對象
複製對象句柄:


2.4 使用對象句柄繼承。只有在進程間有一個父-子關係的時候,纔可以使用對象句柄繼承。
   A:父繼承必須向系統指定它希望這個對象的句柄是可繼承的
   B:子進程在創建的時候,向系統聲明繼承父進程中可繼承的句柄。
如果子進程在創建後,父進程再創建新的內核句柄,子進程是沒有繼承到的。只在創建子進程的時候,纔會遍歷父進程中可繼承的句柄並進行復制到自己的句柄表中。


2.5 改變句柄的標誌:SetHandleInfomation


2.6 爲對象命名:使用名稱實現進程共享內核對象,B共享A的並且B不一定是A的子進程。但是B和A的句柄值可能是不一樣的,只是它們使用了不同的值指向了同一塊內核對象。如進程A創建了一個mutex,進程B調用CreateMutex會返回一個新值,調用錯誤碼會得到already_exists。
打開句柄:Open*,可以使用打開句柄直接得到A創建的句柄,而不需要使用create。Open返回的句柄值和進程A中create的句柄值是一樣的。而create是不一樣的(Create會返回一個新值,該值也指向了B的Mutex)。

不同用戶登錄同一個pc,是在不同的session下的,此時使用進程名也是訪問不導的,他們在不通的內核對象的命名空間中
獲取進程ID:GetCurrentProcessId,根據進程ID獲得當前會話id--ProcessIdToSessionId。因爲一個進程可能在多個會話中運行,需要確認該進程在哪個會話中。有一些內核對象是在全局命名空間,有一些是在自己內部的命名空間,創建時通過Global\MyName或Local\MyName進行設置。
 複製對象句柄:DuplicateHandle,在不同進程之間複製句柄,複製句柄的目的主要是對句柄權限賦值和修改

BOOL WINAPI DuplicateHandle(
   __in    HANDLE hSourceProcessHandle,
   __in    HANDLE hSourceHandle,
   __in    HANDLE hTargetProcessHandle,
   __out   LPHANDLE lpTargetHandle,
   __in    DWORD dwDesiredAccess,
   __in    BOOL bInheritHandle,
   __in    DWORD dwOptions
);
將hSourceHandle複製給lpTargetHandle這個值,在源進程中不要關閉lpTargetHandle,因爲目標進程會使用該值的。
hSourceProcessHandle:源進程內核句柄(即負責傳遞內核對象句柄的進程句柄)
hSourceHandle:要傳遞的內核對象句柄
hTargetProcessHandle:目標進程內核句柄
lpTargetHandle:接收內核對象句柄的地址(先隨便聲明一個HANDLE)
dwDesiredAccess:TargetHandle句柄使用何種訪問掩碼(這個掩碼是在句柄表中的一項)
bInheritHandle:是否擁有繼承
dwOptions:當設DUPLICATE_SAME_ACCESS時,表示於源的內核對象所有標誌一樣,此時wDesiredAccess可標誌爲0
            當設DUPLICATE_CLOSE_SOURCE時,傳輸完後,關閉源中的內核對象句柄
此函數能否成功調用還要看你是否有足夠的權限去操作目標進程
通常目標進程的內核句柄是利用OpenProcess()得到的
HANDLE WINAPI OpenProcess(
   __in   DWORD dwDesiredAccess,
   __in   BOOL bInheritHandle,
   __in   DWORD dwProcessId
);
dwDesiredAccess:決定你擁有該進程的操作權限,如果要成功用到則要填PROCESS_ALL_ACCESS或PROCESS_DUP_HANDLE

bInheritHandle:是否可繼承

dwProcessId:這個ID可在資源管理器中找到,當然,我不提倡在哪裏得到,或者你可以通過進程間通信的方法把PID從目標進程傳給源進程

若DuplicateHandle()能成功執行,則利用進程通信把句柄值TargetHandle傳給目標進程,讓他知道利用該句柄使用內核對象,即目標進程能夠使用lpTargetHandle了

但很多菜鳥們都不知道爲何要用複製句柄函數,我利用進程間通信把句柄傳給目標進程不就行了嗎?

這樣的想法就大錯特錯了,我們表面上是在複製句柄值,實際上是把該句柄在源進程句柄表中的所有項複製到目標進程的句柄表中,而且使該內核對象的計數器+1了,如果只是簡單的只傳句柄值,目標進程的句柄表中是不會有所增加的(這樣系統不知道內核對象被多個進程使用,在關閉時會出問題的)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章