作業
Windows提供了一個作業內核對象, 允許我們將進程組合在一起並創建一個“沙箱”來限制進程能做什麼.
// 驗證進程是否在一個作業控制下運行
BOOL IsProcessInJob(HANDLE hProcess, HANDLE hJob, PBOOL pbInJob);
- 默認下,用資源管理器啓動一個應用,進程自動與一個專用作業關聯。
- 如爲應用程序定義了一個清單,Windows資源管理器不會將我們的進程同專用作業關聯。調試應用時,應用會從調試器繼承專用作業。
- 如果用命令行啓動調試,調試器不會與專用作業關聯,調試的應用也不會。
// 創建作業內核對象
HANDLE CreateJobObject(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
PCTSTR pszName);
// 打開現有作業對象
HANDLE OpenJobObject(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
PCTSTR pszName
);
// 關閉作業對象,表示不再訪問此對象。
// 作業對象在作業中所有進程都已終止運行後,才自動銷燬
CloseHandle(HANDLE hWndJob);
// 把進程分配給作業
BOOL AssignProcessToJobObject(HANDLE hJob, HANDLE hProcess);
對作業中進程施加限制
- 基本限額和擴展基本限額
- 基本的UI限制
- 安全限額
BOOL SetInformationJobObject(
HANDLE hJob,
JOBOBJECTINFOCLASS JobObjectInformationClass,
PVOID pJobObjectInformation,
DWORD cbJobObjectInformationSize);
typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION
{
// 用戶模式時間限制--針對進程
LARGE_INTEGER PerProcessUserTimeLimit;
// 用戶模式時間限制--針對作業
LARGE_INTEGER PreJobUserTimeLimit;
// 標識有效字段
DWORD LimitFlags;
DWORD MinimumWorkingSetSize;
DWORD MaximumWorkingSetSize;
DWORD ActiveProcessLimit;
DWORD_PTR Affinity;
// 作業的優先級類
DWORD PriorityClass;
// 同一優先級類的作業的相對優先級
DWORD SchedulingClass;
};
typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
IO_COUNTERS IoInfo;
SIZE_T ProcessMemoryLimit;
SIZE_T JobMemoryLimit;
SIZE_T PeakProcessMemoryUsed;
SIZE_T PeakJobMemoryUsed;
};
typedef struct _JOBOBJECT_BASIC_UI_RESTRICTIONS
{
// JOB_OBJECT_UI_LIMIT_HANDLES 不可使用作業外進程的用戶對象句柄
// ...
DWORD UIRestrictionsClass;
};
BOOL UserHandleGrantAccess(
// 用戶對象
HANDLE hUserObj,
HANDLE hJob,
BOOL bGrant
);
typedef struct _JOBOBJECT_SECURITY_LIMIT_INFORMATION
{
DWORD SecurityLimitFlags;
// 作業令牌
HANDLE JobToken;
PTOKEN_GROUPS SidsToDisable;
PTOKEN_PRIVILEGES PrivilegesToDelete;
PTOKEN_GROUPS RestrictedSids;
};
將進程放入作業
// 一旦進程已屬作業的一部分,就不能再移動到另一個作業或從作業中移除
BOOL AssignProcessToJobObject(
HANDLE hJob,
HANDLE hProcess
);
// 作業中進程生成的進程默認也在作業中
// 作業基礎限額有標誌,JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK新進程不屬於作業
// 有標誌,JOB_OBJECT_LIMIT_BREAKAWAY_OK,CreateProcess時要指定CREATE_BREAKAWAY_FROM_JOB纔可
殺死作業內所有進程
BOOL TerminateJobObject(
HANDLE hJob,
UINT uExitCode
);
查詢作業信息
// 4類限額信息
// 統計信息
// 作業內進程列表
// JobObjectBasicAccountingInformation
// JOBOBJECT_BASIC_ACCOUNTING_INFORMATION
BOOL QueryInformationJobObject(
HANDLE hJob,
JOBOBJECTINFOCLASS JobObjectInformationClass,
PVOID pvJobObjectInformation,
DWORD cbJobObjectInformationSize,
PDWORD pdwReturnSize
);
typedef struct _JOBOBJECT_BASIC_ACCOUNTING_INFORMATION
{
LARGE_INTEGER TotalUserTime;
LARGE_INTEGER TotalKernelTime;
LARGE_INTEGER ThisPeriodTotalUserTime;
LARGE_INTEGER ThisPeriodTotalKernelTime;
DWORD TotalPageFaultCount;
DWORD TotalProcess;
DWORD TotalTerminatedProcesses;
};
typedef struct JOBOBJECT_BASIC_AND_IO_COUNTING_INFORMATION
{
JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo;
IO_COUNTERS IoInfo;
};
typedef struct _IO_COUNTERS
{
ULONGLONG ReadOperationCount;
ULONGLONG WriteOperationCount;
ULONGLONG OtherOperationCount;
ULONGLONG ReadTransferCount;
ULONGLONG WriteTransferCount;
ULONGLONG OtherTransferCount;
};
// 對不屬於作業的進程
BOOL GetProcessIoCounters(
HANDLE hProcess,
PIO_COUNTERS pIoCounters
);
// JobObjectBasicProcessIdList
// JOBOBJECT_BASIC_PROCESS_ID_LIST
typedef struct _JOBOBJECT_BASIC_PROCESS_ID_LIST(
// 傳入(要保證足夠大)
DWORD NumberOfAssignedProcesses;
// 傳出
DWORD NumberOfProcessIdsInList;
// 數組首地址
DWORD ProcessIdList[1];
);
作業通知
作業用完所有已分配的CPU時間,就會強行“殺死”作業中的所有進程並觸發作業對象。
之後,還可用SetInformationJobObject
把作業對象重置爲未觸發狀態。
1. 創建一個I/O完成端口。
2. 將我們的作業對象與完成端口關聯。
3. 須有一個或多個線程等待作業通知到達完成端口。
JOBOBJECT_ASSOCIATE_COMPLETION_PORT joacp;
joacp.CompletionKey = 1;
joacp.CompletionPort = hIOCP;
SetInformationJobObject(
hJob,
JobObjectAssociateCompletionPortInformation,
&joacp,
sizeof(joacp));
// 線程監視完成端口
BOOL GetQueuedCompletionStatus(
HANDLE hIOCP,
PDWORD pNumBytesTransferred,
// 區分作業
PULONG_PTR pCompletionKey,
POVERLAPPED *pOverlapped,
DWORD dwMilliseconds
);
默認下,分配給作業的CPU時間到期,它的所有進程都自動終止,且不投遞 JOB_OBJECT_MSG_END_OF_JOB_TIME
。
JOBOBJECT_END_OF_JOB_TIME_INFORMATION joeojti;
// JOB_OBJECT_TERMINATE_AT_END_OF_JOB 默認值
// JOB_OBJECT_POST_AT_END_OF_JOB
joeojti.EndOfJobTimeAction = xx;
SetInformationJobObject(hJob, JobObjectEndOfJobTimeInformation,
&joeojti,
sizeof(joeojti));