StartRestrictedProcess 函数,我们利用该函数可以把一个进程放入一个作业中。
void StartRestrictedProcess() {
// 1.首先,我们会校验一个当前的进程判断它是否是已经在一个现有作业下控制运行了。
BOOL bInJob = FALSE;
IsProcessInJob(GetCurrentProcess(), NULL, &bInJob);
if (bInJob) {
MessageBox(NULL, TEXT("Process already in a job"),
TEXT(""), MB_ICONINFORMATION | MB_OK);
return;
}
/* ------ IsProcessInJob 函数声明------
BOOL IsProcessInJob(
HANDLE hProcess,
HANDLE hJob, // 默认初始化为NULL
PBOOL pbInJob);
------ IsProcessInJob 函数声明------ */
// 2.接下来,我们将创建一个新的内核作业对象:
HANDLE hjob = CreateJobObject(NULL,
TEXT("Wintellect_RestrictedProcessJob"));
/* ------ CreateJobObject 函数声明------
HANDLE CreateJobObject(
PSECURITY_ATTRIBUTES psa, // 安全信息与新作业对象关联
PCTSTR pszName // 对作业对象进行命名
);
------ CreateJobObject 函数声明------ */
/* ------ OpenJobObject 函数声明------
创建好一个作业内核对象后,我们可以使用OpenJobObject函数来访问
该作业对象。
HANDLE OpenJobObject(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
PCTSTR pszName
);
另外当访问结束后,还要记得调用CloseHandle来关闭它的句柄。
------ OpenJobObject 函数声明------ */
//3.对作业中的进程施加限制
/*
首先介绍,SetInformationJobObject函数,调用它可以向作业施加限制
BOOL SetInformationJobObject(
HANDLE hJob, // 指定要限制的作业
JOBOBJECTINFOCLASS JobObjectInformationClass, // 枚举类型,指定施加限制的类型
PVOID pJobObjectInformation, // 数据结构地址包含具体限制的设置
DWORD cbJobObjectInformationSize //数据结构大小(用于版本控制)
);
以下为几种限制类型:(参数值指:SetInformationJobObject第二参数和第三参数)
1.基本限额和扩展基本限额,主要用来防止作业中的进程独占系统的资源
☆基本限额:
使用参数值2:JobObjectBasicLimitInformation
使用参数值3:JOBOBJECT_BASIC_LIMIT_INFORMATION
☆扩展限额:
使用参数值2:JobObjectExtendedLimitInformation
使用参数值3:JOBOBJECT_EXTENDED_LIMIT_INFORMATION
2.基本的UI限制,用于防止作业内的进程更改用户的界面(参数值指:SetInformationJobObject第二参数和第三参数)
使用参数值2:JobObjectBasicUIRestrictions
使用参数值3:JOBOBJECT_BASIC_UI_RESTRICTIONS
3.安全限制,用于防止作业内的进程访问安全资源(包括文件、注册表子项等。)
(参数值指:SetInformationJobObject第二参数和第三参数)
使用参数值2:JobObjectSecurityLimitInformation
使用参数值3:JOBOBJECT_SECURITY_LIMIT_INFORMATION
*/
// 这是一个作业基本限制的结构
JOBOBJECT_BASIC_LIMIT_INFORMATION jobli = { 0 };
/* JOBOBJECT_BASIC_LIMIT_INFORMATION 结构声明
typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION {
LARGE_INTEGER PerProcessUserTimeLimit; // 设置运行的最时限
// ★使用此限额需在LimitFlags参数中指定 JOB_OBJECT_LIMIT_PROCESS_TIME 标志
LARGE_INTEGER PerJobUserTimeLimit; // 限制运行时的最大时限
// ★使用此限额需在LimitFlags参数中指定 JOB_OBJECT_LIMIT_JOB_TIME 标志
JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME 标志与它互斥 即,使用了这个标志后
我们改变标志条件同时,不扣除已终止运行的那些进程的CPU时间统计信息。
DWORD LimitFlags; // 设置将哪些限制用于作业
DWORD MinimumWorkingSetSize; // 进程的最小工作集
DWORD MaximumWorkingSetSize; // 进程的最大工作集
// ★使用此限额需在LimitFlags参数中指定 JOB_OBJECT_LIMIT_WORKINGSET 标志
DWORD ActiveProcessLimit; // 作业能并发运行进程数量
// ★使用此限额需在LimitFlags参数中指定 JOB_OBJECT_LIMIT_ACTIVE_PROCESS 标志
DWORD_PTR Affinity; // 能运行进程CPU子集
// ★使用此限额需在LimitFlags参数中指定 JOB_OBJECT_LIMIT_ AFFINITY 标志
DWORD PriorityClass; // 关联进程优先级
// ★使用此限额需在LimitFlags参数中指定 JOB_OBJECT_LIMIT_PRIORITY_CLASS 标志
DWORD SchedulingClass; // 作用中设定一个线程相对时间量差(0-9) 默认值为5
// 使用此限额需在LimitFlags参数中指定 JOB_OBJECT_LIMIT_SCHEDULING_CLASS 标志
★最后一个标志位JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION
它的作用是,该限额会导致系统关闭与作业关联的每一个进程的"未处理的异常"对话框。
} JOBOBJECT_BASIC_LIMIT_INFORMATION, *PJOBOBJECT_BASIC_LIMIT_INFORMATION;
*/
// 再介绍下,扩展限额 JOBOBJECT_EXTENDED_LIMIT_INFORMATION 结构
/*
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; // 作业中全部进程所需存储空间峰值(只读参数)
} JOBOBJECT_EXTENDED_LIMIT_INFORMATION, *PJOBOBJECT_EXTENDED_LIMIT_INFORMATION;
*/
jobli.PriorityClass = IDLE_PRIORITY_CLASS;
jobli.PerJobUserTimeLimit.QuadPart = 10000;
jobli.LimitFlags = JOB_OBJECT_LIMIT_PRIORITY_CLASS | JOB_OBJECT_LIMIT_JOB_TIME;
// 用于限制作业的函数
SetInformationJobObject(hjob, JobObjectBasicLimitInformation, &jobli,
sizeof(jobli));
// 这是对UI进行限制
JOBOBJECT_BASIC_UI_RESTRICTIONS jobuir;
/* JOBOBJECT_BASIC_UI_RESTRICTIONS的数据结构
typedef struct _JOBOBJECT_BASIC_UI_RESTRICTIONS {
DWORD UIRestrictionsClass; // 它只有一个数据成员 其中含有许多标志位..具体内容看底下详细描述
} JOBOBJECT_BASIC_UI_RESTRICTIONS, *PJOBOBJECT_BASIC_UI_RESTRICTIONS;
标志位 描述
JOB_OBJECT_UILIMIT_EXITWINDOWS 阻止进程通过ExitWindowsEx函数注销、关机、重启。
JOB_OBJECT_UILIMIT_READCLIPBOARD 阻止进程读取剪贴板内容
JOB_OBJECT_UILIMIT_WRITECLIPBOARD 阻止进程清除剪贴板内容
JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS 阻止进程通过SystemParametersInfo函数更改系统参数
JOB_OBJECT_UILIMIT_DISPLAYSETTINGS 阻止进程通过ChangeDisplaySettings函数更改显示设置
JOB_OBJECT_UILIMIT_GLOBALATOMS 阻止作业指定专有全局原于表,并限定作业中进程只能访问此作业表。
JOB_OBJECT_UILIMIT_DESKTOP 阻止进程使用CreateDesktop 或 SwitchDesktop 函数创建或切换桌面
JOB_OBJECT_UILIMIT_HANDLES 阻止作业中进程使用同一个作业外部进程创建用户对象(调用外部内容)
最后一个标记可以真正的创建一个安全的沙盘软件,限制HANDLES可以使作业内部进程无法与作业外的进程通信。
但如果需要也可以使用函数
BOOL UserHandleGrantAccess(
HANDLE hUserObj, // 指定一个用户对象
HANDLE hJob, // 授权哪个访问作业
BOOL bGrant // 拒接哪个作业访问
);
来与外面程序进行通信。
*/
jobuir.UIRestrictionsClass = JOB_OBJECT_UILIMIT_NONE;
jobuir.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS;
jobuir.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;
// 用于限制作业的函数
SetInformationJobObject(hjob, JobObjectBasicUIRestrictions, &jobuir,
sizeof(jobuir));
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
TCHAR szCmdLine[8];
_tcscpy_s(szCmdLine, _countof(szCmdLine), TEXT("CMD"));
// 接下来,外面调用 CreateProcess函数来生成一个打算放到进程中的进程。
// 需要注意的是,我们使用了CREATE_SUSPENDED标志,它可以新建一个进程,但不允许进程执行任何代码。
BOOL bResult =
CreateProcess(
NULL, szCmdLine, NULL, NULL, FALSE,
CREATE_SUSPENDED | CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
// 接着我们在调用AssignProcessToJobObjec函数,将进程显示地放入新建的作业中:
/*
BOOL AssignProcessToJobObject(
HANDLE hJob,
HANDLE hProcess);
此进程(由hProcess标识)当作现有作业(由hJob标识)的一部分。
*/
AssignProcessToJobObject(hjob, pi.hProcess);
ResumeThread(pi.hThread); // 调用它,使进程的线程可以再作业的限制下执行代码
CloseHandle(pi.hThread); // 关闭线程句柄。
// 终止作业中的所有进程 -- 可以通过以下代码来实现
/*
它可以"杀死"作业内部中的所有进程
BOOL TerminateJobObject(
HANDLE hJob,
UINT uExitCode);
这样做类似于将作业内的每一个进程调用TerminateJobObject,将所有退出代码设为uExitCode.
*/
// Wait for the process to terminate or
// for all the job's allotted CPU time to be used.
HANDLE h[2];
h[0] = pi.hProcess;
h[1] = hjob;
DWORD dw = WaitForMultipleObjects(2, h, FALSE, INFINITE);
switch (dw - WAIT_OBJECT_0) {
case 0:
// The process has terminated...
break;
case 1:
// All of the job's allotted CPU time was used...
break;
}
FILETIME CreationTime;
FILETIME ExitTime;
FILETIME KernelTime;
FILETIME UserTime;
TCHAR szInfo[MAX_PATH];
GetProcessTimes(pi.hProcess, &CreationTime, &ExitTime,
&KernelTime, &UserTime);
StringCchPrintf(szInfo, _countof(szInfo), TEXT("Kernel = %u | User = %u/n"),
KernelTime.dwLowDateTime / 10000, UserTime.dwLowDateTime / 10000);
MessageBox(GetActiveWindow(), szInfo, TEXT("Restricted Process times"),
MB_ICONINFORMATION | MB_OK);
// Clean up properly.
CloseHandle(pi.hProcess);
CloseHandle(hjob);
}
原文來自:http://262055400.p3l.cn/post/113.html