刘收获

导航

作业通知

一.作业(job)内核对象概念

1.为什么要有作业job
便于管理进程:进程的父子关系只存在于创建的子进程的那一刻,Windows并不一直维护着这种父子关系,这使得管理进程并不是件容易的事。
2.作业的功能
作业对象是用于将一组进程作为一个管理单元的内核对象,本质上可以理解为其实就是进程池对象,可将作业对象看作是进程的容器。
    作来对象可以用来限制一组进程的占用内存数量、占用CPU周期数、进程优先级等的一个“沙箱”。

   最终可以通过作业对象将该对象中的所有进程全部关闭(普通方法很难控制)

3.作业通知
通过结合一个完成端口对象并利用一个线程 实时动态的监控作业对象的执行(如得到一些消息,以便及时响应作业对象中的进程变化情况)
 

二.作业对象的基本用法

 

  

 


  CreateJobObject (创建作业对象)
  IsProcessInJob (进程是否己经与某个作业对象关联)
  SetInformationJobObject (设置作业对象或进程的限制)
  AssignProcessToJobObject (将进程添加到作业中)
  QueryInformationJobObject (查询作业对象中施加的限制)
  TerminateJobObject ("杀死"作业中所有的进程)
  CloseHandle (关闭作业对象句柄,导致所有进程不能访问作业对象,但作业仍存在!)
  OpenJobObject (打开一个指定名称的作业对象句柄)

 

三.作业通知实现

     

1.创建作业和完成端口:

//创建作业
HANDLE JobHandle = CreateJobObject(
NULL, //安全属性默认
NULL); //匿名作业
if (JobHandle == NULL)
{
goto Exit;
}
//创建一个完成端口
__CompletionPortHandle = CreateIoCompletionPort(
INVALID_HANDLE_VALUE, //关联的文件句柄
NULL, //已经存在的完成端口
0, //传送给处理函数的参数
0); //有多少个线程在访问这个消息队列
if (__CompletionPortHandle==NULL)
{
goto Exit;
}


2.作业与完成关联

//作业与完成关联
JOBOBJECT_ASSOCIATE_COMPLETION_PORT AssociateCompletePort;
AssociateCompletePort.CompletionKey = (PVOID)JOB_OBJECT_COMPLETE_KEY;
AssociateCompletePort.CompletionPort = __CompletionPortHandle;
if (SetInformationJobObject(
JobHandle, //作业句柄
JobObjectAssociateCompletionPortInformation,
&AssociateCompletePort,
sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT)
)==FALSE)
{
goto Exit;
}


3.设置限制:

//UI限制
JOBOBJECT_BASIC_UI_RESTRICTIONS Restrictions;

Restrictions.UIRestrictionsClass = JOB_OBJECT_UILIMIT_NONE; //初始化为0
Restrictions.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS; //进程不能访问用户对象(如窗口句柄)
Restrictions.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES; //进程不能关闭系统
//设置限制
SetInformationJobObject(
JobHandle, //作业对象句柄
JobObjectBasicUIRestrictions, //限制的类型,
&Restrictions, //指向初始化过的结构体,包含具体的限制
sizeof(JOBOBJECT_BASIC_UI_RESTRICTIONS)); //结构体的大小

4.创建一个守候在完成端口上的线程

//创建一个守候在完成端口上的线程,监视
HANDLE ThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProcedure, NULL, 0, NULL);
if (ThreadHandle == NULL)
{
goto Exit;
}

 

源代码:

// 作业通知.cpp : 定义控制台应用程序的入口点。


#include "stdafx.h"
#include <windows.h>
#include <iostream>
using namespace std;

#define  JOB_OBJECT_COMPLETE_KEY  100
#define  EXIT_THREAD_COMPLETE_KEY 101
DWORD WINAPI ThreadProcedure(LPVOID ParameterData);
HANDLE __CompletionPortHandle = NULL;
BOOL __IsLoop = TRUE;
int main()
{
    //创建作业
    HANDLE JobHandle = CreateJobObject(
        NULL,    //安全属性默认
        NULL);   //匿名作业
    if (JobHandle == NULL)
    {
        goto Exit;
    }
    //创建一个完成端口
    __CompletionPortHandle =  CreateIoCompletionPort(
        INVALID_HANDLE_VALUE,   //关联的文件句柄
        NULL,                   //已经存在的完成端口
        0,                      //传送给处理函数的参数
        0);                     //有多少个线程在访问这个消息队列
    if (__CompletionPortHandle==NULL)
    {
        goto Exit;
    }
    //作业与完成关联
    JOBOBJECT_ASSOCIATE_COMPLETION_PORT AssociateCompletePort;
    AssociateCompletePort.CompletionKey = (PVOID)JOB_OBJECT_COMPLETE_KEY;
    AssociateCompletePort.CompletionPort = __CompletionPortHandle;
    if (SetInformationJobObject(
        JobHandle,                                    //作业句柄
        JobObjectAssociateCompletionPortInformation,  
        &AssociateCompletePort,                       
        sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT)   
        )==FALSE)
    {
        goto Exit;
    }


    //UI限制
    JOBOBJECT_BASIC_UI_RESTRICTIONS  Restrictions;

    Restrictions.UIRestrictionsClass = JOB_OBJECT_UILIMIT_NONE;         //初始化为0
    Restrictions.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS;    //进程不能访问用户对象(如窗口句柄)
    Restrictions.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;        //进程不能关闭系统
    //设置限制
    SetInformationJobObject(
        JobHandle,                                //作业对象句柄
        JobObjectBasicUIRestrictions,             //限制的类型,  
        &Restrictions,                            //指向初始化过的结构体,包含具体的限制    
        sizeof(JOBOBJECT_BASIC_UI_RESTRICTIONS)); //结构体的大小

    //创建一个守候在完成端口上的线程,监视
    HANDLE ThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProcedure, NULL, 0, NULL);
    if (ThreadHandle == NULL)
    {
        goto Exit;
    }

    WCHAR v1;
    do
    {
        wprintf(L"1..Create Process In Job\n");
        wprintf(L"2..Remove Process From Job\n");
        wprintf(L"3..Query Restrictions\n");
        wprintf(L"4..Exit\n");
    
        wscanf(L" %c", &v1);

        switch (v1)
        {
        case '1':
        {
            STARTUPINFO StartupInfo;
            memset(&StartupInfo, 0, sizeof(STARTUPINFO));
            StartupInfo.cb = sizeof(STARTUPINFO);

            PROCESS_INFORMATION ProcessInfo;
            memset(&ProcessInfo, 0, sizeof(PROCESS_INFORMATION));
        
            WCHAR CommandLine[] = L"Notepad.exe";
            //创建进程,且传入CREATE_SUSPENDED标志,暂时挂起进程,避免进程逃离“沙箱”
            BOOL IsOk = CreateProcess(NULL,CommandLine, NULL, NULL,
                FALSE, CREATE_SUSPENDED | CREATE_NEW_CONSOLE | CREATE_BREAKAWAY_FROM_JOB,
                NULL, NULL, &StartupInfo, &ProcessInfo);
            //将进程放入作业中
            AssignProcessToJobObject(JobHandle, ProcessInfo.hProcess);
            //再调用ResumeThread ,使进程的线程可以在作业的限制下执行代码
            ResumeThread(ProcessInfo.hThread);
            CloseHandle(ProcessInfo.hThread);
            CloseHandle(ProcessInfo.hProcess);
            break;
        }

        case '2':
        {
            TerminateJobObject(JobHandle, 0);   //终止作业中的所有进程 
            break;
        }
        case '4':
        {
            //发送自定义事件,触发GetQueuedCompletionStatus函数来取得数据包
            PostQueuedCompletionStatus(
                __CompletionPortHandle,            //完成端口对象
                0,
                EXIT_THREAD_COMPLETE_KEY,         //退出消息
                NULL);  
            goto Exit;
        }

        case '3':
        {
            QueryInformationJobObject(JobHandle, JobObjectBasicUIRestrictions,
                &Restrictions, sizeof(Restrictions), NULL);
            wprintf(L"%x\n", Restrictions.UIRestrictionsClass);

        }
        }

        wprintf(L"Do You Want To Continue?\n");

        wscanf(L" %c", &v1);


    } while (v1 == 'y' || v1 == 'Y');

Exit:
    
    if (__CompletionPortHandle!=NULL)
    {
        CloseHandle(__CompletionPortHandle);
        __CompletionPortHandle = NULL;
    }
    if (JobHandle!=NULL)
    {
        CloseHandle(JobHandle);
        JobHandle = NULL;
    }
    if (ThreadHandle!=NULL)
    {
        WaitForSingleObject(ThreadHandle, INFINITE);
        CloseHandle(ThreadHandle);
        ThreadHandle = NULL;
    }
    printf("Input AnyKey To Exit\r\n");
    getchar();
    return 0;
}
DWORD WINAPI ThreadProcedure(LPVOID ParameterData)
{
    DWORD  TransferredDataLength = 0;
    ULONG_PTR CompletionKey = 0;
    LPOVERLAPPED Overlapped;
    BOOL IsOk = FALSE;
    while (__IsLoop)
    {
        IsOk = GetQueuedCompletionStatus(
            __CompletionPortHandle, 
            &TransferredDataLength, //返回一个事件的ID
            &CompletionKey,         //返回触发这个事件的对象的句柄,即作业对象的句柄
            &Overlapped,            //事件对应的详细信息(NULL)
            INFINITE);
        
        if (IsOk==TRUE)
        {
            if (CompletionKey == JOB_OBJECT_COMPLETE_KEY)
            {
                switch (TransferredDataLength)
                {
                    /*
                    事件类型:
                    JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS    进程异常退出
                    JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT        同时活动的进程数达到设置的上限
                    JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO        作业对象中没有活动的进程了
                    JOB_OBJECT_MSG_END_OF_JOB_TIME            作业对象的CPU周期耗尽
                    JOB_OBJECT_MSG_END_OF_PROCESS_TIME        进程的CPU周期耗尽
                    JOB_OBJECT_MSG_EXIT_PROCESS                进程正常退出
                    JOB_OBJECT_MSG_JOB_MEMORY_LIMIT            作业对象消耗内存达到上限
                    JOB_OBJECT_MSG_NEW_PROCESS                有新进程加入到作业对象中
                    JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT        进程消耗内存数达到上限
                    */
                //作业通知
                case JOB_OBJECT_MSG_NEW_PROCESS:
                {
                    wprintf(L"New Process ID:%d In Job\n", Overlapped);

                    break;
                }
                case JOB_OBJECT_MSG_EXIT_PROCESS:
                {
                    wprintf(L"New Process ID:%d Out Job\n", Overlapped);   //进程已经消亡

                    break;
                }
                case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO:
                {
                    wprintf(L"Active Procss Is Zero\n");
                }

                default:
                {
                }
                }
            }
            else if (CompletionKey==EXIT_THREAD_COMPLETE_KEY)
            {

                printf("EXIT_THREAD_COMPLETE_KEY\r\n");
                break;
            }
        }
        else
        {
            printf("CloseHandle(__CompletionPortHandle)\r\n");
            break;
        }


    }

    printf("ThreadProcedure() Exit\r\n");
    return 0;
}

 

posted on 2017-08-09 14:34  沉疴  阅读(788)  评论(0编辑  收藏  举报