標籤:
6 進程執行個體控制代碼6.1 每一個EXE或者DLL被載入到記憶體中後,都會被賦予一個獨一無二的控制代碼(HINSTANCE),該控制代碼在WinMain函數調用時傳入。擷取應用程式相關資訊(資源、路徑)時,有的需要傳入HINSTANC有的需要傳入HMODULE,實際上HINSTANC與HMODULE完全是一回事,這是16位Windows系統上不同資料類型造成的。
WinMain函數的第一個參數:執行個體控制代碼是如何傳遞進來的呢?查看crtexe.c源碼,我們會看到如下代碼
#ifdef WPRFLAG mainret = wWinMain(#else /* WPRFLAG */ mainret = WinMain(#endif /* WPRFLAG */ (HINSTANCE)&__ImageBase, NULL, lpszCommandLine, StartupInfo.dwFlags & STARTF_USESHOWWINDOW ? StartupInfo.wShowWindow : SW_SHOWDEFAULT );#else /* _WINMAIN_ */
Crt在這裡調用我們的WinMain函數,傳入的執行個體控制代碼是:__ImageBase的地址,轉到其定義位置
extern "C" IMAGE_DOS_HEADER __ImageBase;
實際上執行個體控制代碼就是這個PE檔案載入到記憶體後的DOS頭的地址,CRT源碼都是可見的,在VS安裝路徑下VC\crt\src\大家可以看下。
6.2 GetModuleHandle(PCTSTR pszModule)的兩大注意點:
1、該API只檢查主調用進程的地址空間,如果pszModule沒有被主進程載入,即使其他進程載入了pszModule也會調用失敗,返回NULL;
2、在進程的DLL中調用該函數,返回的HMODULE是該EXE的記憶體基地址而非該DLL的記憶體基地址。
7 終止進程四種方式:
1、主進程入口函數返回(推薦方式、最佳方式);
2、進程中一個線程調用ExitProcess;
3、其他進程調用TerminateProcess;
4、進程中所有線程都自然死亡(幾乎不可能發生)。
7.1 主進程入口函數返回,進程終止過程
但主進程WinMain函數返回後,會回到C運行庫啟動代碼,然後正確清理進程使用的所有C運行時資源。釋放完這些資源後,C運行時啟動代碼將顯示調用ExitProcess,並將進程的WinMain函數返回值傳給它。於是,所有進程中啟動並執行其他進程都會終止。
任何時候都不應該顯示調用ExitProcess,否則很有可能導致自訂的C++對象得不到正確的釋放。
7.2 TerminateProcess終止進程
1、只有在無法通過其他方法終止進程時,才應使用該函數;
2、被終止的進程無法知道自己將要被終止,終止後雖然進程沒有機會自己執行清理工作,但是系統會在進程終止後進行徹底得清理;
3、TerminateProcess函數是非同步,函數返回後並不表示進程已經終止,可以通過WaitForSingleObject來等待判斷。
7.3 進程終止運行時,執行的步驟
1、終止進程中遺留的任何線程;
2、釋放進程分配的所有使用者物件和GDI對象,關閉所有的核心對象,若核心對象引用計數為0則銷毀;
3、進程的退出碼從STILL_ACTIVE變為傳給ExitProcess或者TerminateProcess的參數;
4、進程的核心對象狀態變為已觸發狀態;
5、進程的核心對象引用計數減一,引用計數為0,則銷毀核心對象。
8 進程提權8.1 Windows只允許在進程邊界上進行許可權提升,一旦進程啟動後,再要求更多的許可權已經太遲了。一個未提升許可權的進程可以產生另一個提升了許可權的進程,後者將包含一個COM伺服器,這個新進程將保持活躍狀態。這樣,未提升許可權的進程就可以向已提升許可權的進程發送IPC(Inter-Process Communication)調用,而不必為了提升許可權再開一個新執行個體然後終止自己。
8.2 手動提權方式
ShellExecuteEx函數,SHELLEXECUTEINFO 結構中lpVerb指定為"runas",同時在lpFile指定一個擁有許可權的可執行檔路徑。如果使用者拒絕提升許可權,返回FALSE,GetLastError()返回ERROR_CANCELLED。進程使用提升後的許可權運行時,其所建立的所有子進程都會具有相同許可權,無需再用ShellExecuteEx提權。
未完待續。
Windows核心編程筆記(2)