| 參數 | 建議值 | 說明 |
| lpApplicationName | 完整路徑或 NULL | NULL 時從 lpCommandLine 解析模組名 |
| lpCommandLine | "app.exe param1 param2" | 若 lpApplicationName 非 NULL,此參數僅作參數傳遞 |
| lpProcess/ThreadAttributes | NULL | 預設安全描述子,子進程/執行緒不可被其他使用者存取 |
| bInheritHandles | FALSE | 避免非預期控制代碼洩漏 |
| dwCreationFlags | NORMAL_PRIORITY_CLASS | 常用組合:DEBUG_PROCESS, CREATE_SUSPENDED, DETACHED_PROCESS, CREATE_NEW_CONSOLE |
| lpEnvironment | NULL | 繼承父進程環境變數 |
| lpCurrentDirectory | NULL | 繼承父進程當前目錄 |
| lpStartupInfo | GetStartupInfo 填充 | 指定主視窗顯示狀態 (SW_SHOWDEFAULT 等)、標準輸入/輸出/錯誤控制代碼 |
PROCESS_INFORMATION 結構
PROCESS_INFORMATION STRUCT
hProcess HANDLE ? ; 進程控制代碼 (需 CloseHandle)
hThread HANDLE ? ; 主執行緒控制代碼 (需 CloseHandle)
dwProcessId DWORD ? ; 進程 ID (系統全域唯一)
dwThreadId DWORD ? ; 主執行緒 ID
PROCESS_INFORMATION ENDS
控制代碼 ≠ ID:控制代碼是進程私有的間接引用,ID 是系統全域唯一數值。控制代碼需 CloseHandle 釋放核心物件引用計數。
進程生命週期管理
檢查進程是否結束
GetExitCodeProcess PROTO hProcess:DWORD, lpExitCode:DWORD
; 返回 STILL_ACTIVE (259) 表示仍在運行
強制終止進程
TerminateProcess PROTO hProcess:DWORD, uExitCode:DWORD
; ⚠ 粗暴終止:DLL 不會收到 DLL_PROCESS_DETACH,資源可能洩漏,僅作最後手段
完整範例:建立/終止子進程的 GUI 應用程式
資源定義
.const
IDM_CREATE_PROCESS equ 1
IDM_TERMINATE equ 2
IDM_EXIT equ 3
主視窗程序
WinMain proc ...
; 標準視窗類別註冊、建立、訊息迴路
invoke GetMenu, hwnd
mov hMenu, eax
.WHILE TRUE
invoke GetMessage, ADDR msg, NULL, 0, 0
.BREAK .IF !eax
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
ret
WinMain endp
訊息處理:動態選單啟用/禁用
WndProc proc hWnd, uMsg, wParam, lParam
LOCAL startInfo:STARTUPINFO
.IF uMsg == WM_DESTROY
invoke PostQuitMessage, NULL
.ELSEIF uMsg == WM_INITMENUPOPUP
; 選單彈出前動態更新狀態
invoke GetExitCodeProcess, procInfo.hProcess, ADDR ExitCode
.IF eax == TRUE
.IF ExitCode == STILL_ACTIVE
invoke EnableMenuItem, hMenu, IDM_CREATE_PROCESS, MF_GRAYED
invoke EnableMenuItem, hMenu, IDM_TERMINATE, MF_ENABLED
.ELSE
invoke EnableMenuItem, hMenu, IDM_CREATE_PROCESS, MF_ENABLED
invoke EnableMenuItem, hMenu, IDM_TERMINATE, MF_GRAYED
.ENDIF
.ELSE
invoke EnableMenuItem, hMenu, IDM_CREATE_PROCESS, MF_ENABLED
invoke EnableMenuItem, hMenu, IDM_TERMINATE, MF_GRAYED
.ENDIF
.ELSEIF uMsg == WM_COMMAND
mov eax, wParam
.IF lParam == 0 ; 選單項目
.IF ax == IDM_CREATE_PROCESS
; 清理舊控制代碼
.IF procInfo.hProcess != 0
invoke CloseHandle, procInfo.hProcess
mov procInfo.hProcess, 0
.ENDIF
invoke GetStartupInfo, ADDR startInfo
invoke CreateProcess, ADDR programName, NULL, NULL, NULL, FALSE, \
NORMAL_PRIORITY_CLASS, NULL, NULL, ADDR startInfo, ADDR procInfo
invoke CloseHandle, procInfo.hThread ; 不需主執行緒控制代碼,立即釋放
.ELSEIF ax == IDM_TERMINATE
invoke GetExitCodeProcess, procInfo.hProcess, ADDR ExitCode
.IF ExitCode == STILL_ACTIVE
invoke TerminateProcess, procInfo.hProcess, 0
.ENDIF
invoke CloseHandle, procInfo.hProcess
mov procInfo.hProcess, 0
.ELSE
invoke DestroyWindow, hWnd
.ENDIF
.ENDIF
.ELSE
invoke DefWindowProc, hWnd, uMsg, wParam, lParam
ret
.ENDIF
xor eax, eax
ret
WndProc endp
關鍵細節與常見錯誤
- 必須 CloseHandle:
CreateProcess 返回的 hProcess、hThread 都是核心物件控制代碼,不釋放會導致物件洩漏(進程結束後核心物件仍駐留)。
- 主執行緒控制代碼通常可立即關閉:除非需要
WaitForSingleObject(hThread) 等待執行緒結束或 GetThreadContext 操作暫存器。
- GetExitCodeProcess 失敗不代表進程不存在:可能是控制代碼無效、權限不足。結合
OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid) 更可靠。
- CREATE_SUSPENDED 技巧:建立暫停狀態進程 → 修改記憶體/暫存器/注入 DLL →
ResumeThread 繼續執行,是偵錯器、Hook 工具、加殼器核心技術。
- 命令列引號規則:路徑含空格需雙引號包圍:
"C:\Program Files\App.exe" arg1。
- Unicode 版本:
CreateProcessW 支援長路徑 (>260 字元,需 \\?\ 前綴) 與 Unicode 參數。
進階主題
- 工作物件:
CreateJobObject 管理進程群組,統一限制記憶體、CPU、執行時間、強制終止全群組。
- 受保護進程 (PPL):簽名等級高的進程,受保護免受非信任代碼注入/終止 (反惡意軟體、DRM)。
- 最小化進程 (Pico Process):WSL 1 使用,核心模式驅動模擬 Linux 系統呼叫。
- 進程遷移/注入:
OpenProcess + VirtualAllocEx + WriteProcessMemory + CreateRemoteThread,攻防核心戰場。
總結
進程是 Windows 資源管理的核心抽象,CreateProcess 是進程創建的唯一權威入口。掌握其參數語意、返回值管理、生命週期控制、錯誤處理模式,是開發啟動器、偵錯器、沙箱、服務管理器、自動化測試框架的必備基礎。本文範例展示了從選單驅動的建立/終止流程到控制代碼正確釋放的完整最佳實務,可直接作為生產代碼骨架。
- 上一篇文章: V86 模式記憶體管理實戰:V86MMGR API 傳輸緩衝區與 Ring 0/Real Mode 資料交換
- 下一篇文章: 虛擬機管理器 (VMM) 架構深度解析:記憶體、中斷、排程三大核心服務
Copyright ©
程式碼之家 All Rights Reserved