元始天尊 发表于 2015-9-20 11:20:40

TsSysKit深度分析

本帖最后由 元始天尊 于 2015-9-27 13:07 编辑

TsSysKit.sys分析报告
        该驱动为qq管家穿透驱动,提供文件、注册表穿透,和解锁文件、驱动加载、句柄、进程等操作,导出接口给其他驱动使用,设备名\\Device\\TSSysKit,符号名\\DosDevices\\TSSysKit。加密手段:Rabbit算法、MD5算法。
目录
TsSysKit.sys分析报告        1
一、        驱动入口DriverEntry        2
1.1 检测加载者是否为Ntos        2
1.2 执行删除任务 DoDeleteJob        3
二、        驱动接口Interface        5
2.1 DeviceExtension接口        5
2.2 与WRK代码异同点        6
2.3 重置/保存注册表对象ObjectInitialzer例程        6
NtCreateKey        7
NtOpenKey        9
NtQueryValueKey        10
NtSetValueKeyEx        11
NtDeleteValueKey        12
NtDeleteKey        13
IopCreateFile        13
三、        控制码        17
0x221C00解锁文件        21
0x222004普通结束进程        21
0x22242C穿透创建服务加载驱动        22
四、        默认派遣例程        26
3.1 根据进程id结束进程        26
3.2 获取当前进程进程名        26
3.3 由进程ID获取进程设备名        27
3.4 设备名转DOS路径        28
3.5 得到EPROCESS对应ImageDosPath        29
3.6 随机化程序名机制        30
3.7 根据进程文件名获取进程信息        31
3.8 两种方式调用内核函数        31
3.9 获取对象类型        32
3.10 基础库功能——检测腾讯程序合法性        32
3.11 解锁文件        34
五、        获取ObjectInitializer        40
4.1 获取注册表OBJECT_TYPE,匹配对象类型        40
4.2获取ParseProcedure        42
4.3 获取GetCellRoutine偏移,Hook GetCellRoutine        43
4.4 Hook和UnHook GetCellRoutine        44
4.5 创建系统线程获取 Cm*函数        45
4.6 匹配结构        49
4.7 获取DeviceObject对象类型        59


一、        驱动入口DriverEntry
        获取系统版本_1
        获取EPROCESS的ObjectTypeIndex(win7以前 0x1Cwin8 0x1FWin8.1 0x1E)
        创建\\Device\\TSSysKit设备和\\DosDevices\\TSSysKit符号链接
        设置DeviceExtension为通信接口(Interface函数指针)
        注册IRP_MJ_CREATE、IRP_MJ_CLOSE、IRP_MJ_DEVICE_CONTROL派遣例程为DefaultDispatch
        获取CmpKeyObject、DeviceObject的OBJECT_TYPE_INITIALIZER
GetCmpKeyObjectInitializerFunc        GetDeviceObjectInitializerFunc
        获取ZwQueryVirtualMemory、IoVolumeDeviceToDosName、PsGetProcessSectionBaseAddress地址和NtQueryVirtualMemory的index
        检测加载者是否为Ntos (CheckIopLoadDriver)
        执行开机删除操作(DoDeleteJob)删除ShutdownRecord.ini指定的文件


1.1 检测加载者是否为Ntos
顺带保存IopLoadDriver
int CheckIopLoadDriver()
{
        unsigned int IopLoadDriverNext; // esi@2
        PRTL_PROCESS_MODULES modules; // ebx@5
        int IopLoadDriver; // esi@8
        PVOID Base; // eax@9
        PVOID Callers; // @1
        BOOL ret; // @1
        ULONG SystemInformationLength; // @1

        Callers = 0;
        Callers = 0;
        Callers = 0;
        Callers = 0;
        ret = 0;
        SystemInformationLength = 0;
        ::IopLoadDriver = 0;
        if ( RtlWalkFrameChain(Callers, 4u, 0) == 4 )
                // =RtlWalkFrameChain next
                // =DriverEntry
                // =IopLoadDriver
                // =IopInitializeSystemDrivers
        {
                IopLoadDriverNext = Callers;
                if ( MmIsAddressValid(Callers) )
                {
                        if ( IopLoadDriverNext >= MmUserProbeAddress && *(IopLoadDriverNext - 5) == 0xE8u )// call ***
                        {
                                SystemInformationLength = sizeof(SYSTEM_MODULE_INFORMATION) + 3 * sizeof(RTL_PROCESS_MODULE_INFORMATION);
                                modules = ExAllocatePoolWithTag(0, SystemInformationLength, '!KIT');
                                if ( modules )
                                {
                                        memset(modules, 0, SystemInformationLength);
                                        if ( ZwQuerySystemInformation(SystemModuleInformation,modules,SystemInformationLength,&SystemInformationLength) >= 0 )
                                        {
                                                if ( modules->NumberOfModules )
                                                {
                                                        IopLoadDriver = *(IopLoadDriverNext - 4) + IopLoadDriverNext;
                                                        if ( MmIsAddressValid(IopLoadDriver) )
                                                        {
                                                                Base = modules->Modules.ImageBase;
                                                                if ( IopLoadDriver >= Base && IopLoadDriver <= (Base + modules->Modules.ImageSize) )
                                                                {                               // 检测IopLoadDriver是否在ntos中
                                                                        ::IopLoadDriver = IopLoadDriver;
                                                                        ret = 1;
                                                                }
                                                        }
                                                }
                                        }
                                        ExFreePool(modules);
                                }
                        }
                }
        }
        return ret;
}

1.2 执行删除任务 DoDeleteJob
如果腾讯安装目录存在ShutdownRecord.ini文件则删除该文件,解析文件列表中指定的文件并逐个删除,其中解析ini的api、文件操作都是自己实现的。删除方式采用NtSetInformationFile 置FileDispositionInformation。

ShutdownRecord.ini格式:

Count=3

0=0.txt
1=1.txt
2=2.txt

enum
{
        WIN2000=1,
        WINXP=2,
        WINXPSP3=3,
        WINVISTA=4,
        WIN7=5,
        WIN8=7,
        WIN8_1=8,
        WIN10=9,
        UNKNOWN=10,
};

二、        驱动接口Interface
2.1 DeviceExtension接口
DeviceObject->DeviceExtension(=Interface)通过制定序号返回对应函数指针,穿透函数内部在ObOpenObjectByName前后会保存和恢复注册表Objectinitializer:
FARPROC Interface(intindex)
{//注意下面的函数都是自己实现的穿透函数
    switch(index)
    {
    case 1:
      return NtOpenKey;
    case 2:
      return NtQueryValueKey;
    case 3:
      return NtSetValueKeyEx;
    case 4:
      return NtDeleteValueKey;
    case 5:
      return NtDeleteKey;
    case 20:
      return IopCreateFile;
    case 21:
      return NtReadFile;
    case 22:
      return NtWriteFile;
    case 23:
      return NtSetInformationFile;
    case 24:
      return NtQueryInformationFile;
    case 25:
      return NtQueryDirectoryFile;
    }
}

函数原型:
0:NTSTATUS __stdcall NtCreateKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG TitleIndex, PUNICODE_STRING Class, ULONG CreateOptions, PULONG Disposition)
1:NTSTATUS __stdcall NtOpenKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes)
2:NTSTATUS __stdcall NtQueryValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG Length, PULONG ResultLength)
3:NTSTATUS __stdcall NtSetValueKeyEx(HANDLE Handle, PUNICODE_STRING ValueName, ULONG Type, PVOID Data, ULONG DataSize)
和NtSetValueKey的用法类似,只是没有TitleIndex这个参数
4:NTSTATUS __stdcall NtDeleteValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName)
5:NTSTATUS __stdcall NtDeleteKey(HANDLE KeyHandle)
20:NTSTATUS __stdcall IopCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG Disposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength, CREATE_FILE_TYPE CreateFileType, PVOID ExtraCreateParameters, ULONG Options, ULONG InternalFlags, PVOID DeviceObject)
21:NTSTATUS __stdcall NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key)
22:NTSTATUS __stdcall NtWriteFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key)
23:NTSTATUS __stdcall NtSetInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOL DelCurrentFile)
24:NTSTATUS __stdcall NtQueryInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOL DelCurrentFile)
25:NTSTATUS __stdcall NtQueryDirectoryFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, PUNICODE_STRING FileName, BOOLEAN RestartScan)

2.2 与WRK代码异同点
注册表穿透操作是使用Cm*函数实现Nt*函数,而文件穿透操作则基本和WRK代码一致,Iop*函数最大程度的实现内联。
这些实现中和WRK主要区别在于:去掉了AccessMode=UserMode分支、和ObReferenceObjectByName调用前后重置ObjectInitializer
NtReadFile实现额外处理了IoCallDriver返回文件锁定(STATUS_FILE_LOCK_CONFLICT)的处理,此时通过创建文件映射实现读取

2.3 重置/保存注册表对象ObjectInitialzer例程

enum
{
        EClose,
        EDelete,
        EParse,
        ESecurtiy,
        EQueryName,
        EOpen,
};
BOOLEAN ReplaceObjectinitializer(int Type,FARPROC* OutFunc,BOOLEAN ResetOrRestore)
{
        FARPROC* Initailier = NULL;
        if(Type <0 || Type >= ECmMax)
        {
                if(!RegObjectInitialzer || !CmpKeyObjectType || !OutFunc)
                        return 0;
        }
        if(VersionIndex >= WIN2000 && VersionIndex <= WINXPSP3)
        {
                switch(Type)
                {
                        case EClose:
                                Initailier = &((POBJECT_TYPE_XP)CmpKeyObjectType)->TypeInfo.CloseProcedure;
                                break;
                        case EDelete:
                                Initailier = &((POBJECT_TYPE_XP)CmpKeyObjectType)->TypeInfo.DeleteProcedure;
                                break;
                        case EParse:
                                Initailier = &((POBJECT_TYPE_XP)CmpKeyObjectType)->TypeInfo.ParseProcedure;
                                break;
                        case ESecurity:
                                Initailier = &((POBJECT_TYPE_XP)CmpKeyObjectType)->TypeInfo.SecurityProcedure;
                                break;
                        case EQueryName:
                                Initailier = &((POBJECT_TYPE_XP)CmpKeyObjectType)->TypeInfo.QueryNameProcedure;
                                break;
                        case EOpen:
                                Initailier = &((POBJECT_TYPE_XP)CmpKeyObjectType)->TypeInfo.OpenProcedure;
                                break;
                }
        }
        else if(VersionIndex >= WINVISTA && VersionIndex <= WIN10)
        {
                switch(Type)
                {
                case EClose:
                        Initailier = &((POBJECT_TYPE_WIN7)CmpKeyObjectType)->TypeInfo.CloseProcedure;
                        break;
                case EDelete:
                        Initailier = &((POBJECT_TYPE_WIN7)CmpKeyObjectType)->TypeInfo.DeleteProcedure;
                        break;
                case EParse:
                        Initailier = &((POBJECT_TYPE_WIN7)CmpKeyObjectType)->TypeInfo.ParseProcedure;
                        break;
                case ESecurity:
                        Initailier = &((POBJECT_TYPE_WIN7)CmpKeyObjectType)->TypeInfo.SecurityProcedure;
                        break;
                case EQueryName:
                        Initailier = &((POBJECT_TYPE_WIN7)CmpKeyObjectType)->TypeInfo.QueryNameProcedure;
                        break;
                case EOpen:
                        Initailier = &((POBJECT_TYPE_WIN7)CmpKeyObjectType)->TypeInfo.OpenProcedure;
                        break;
                }
        }
        if(ResetOrRestore)
        {//Get
                if(*Initailier != RegObjectInitialzer)
                {
                        *OutFunc = *Initailier;
                        *Initailier = RegObjectInitialzer;
                        return TRUE;
                }
        }
        else
        {//Set
                if(*OutFunc != *Initailier)
                {
                        *Initailier = *OutFunc;
                        return TRUE;
                }
        }
        return FALSE;
}

NtCreateKey
NTSTATUS __stdcall NtCreateKey(PHANDLE KeyHandle,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes,
        ULONG TitleIndex,PUNICODE_STRING Class,ULONG CreateOptions,PULONG Disposition)
{
        NTSTATUS            status;
        KPROCESSOR_MODE   mode;
        CM_PARSE_CONTEXT    ParseContext;
        PCM_KEY_BODY      KeyBody = NULL;
        HANDLE            Handle = 0;
        UNICODE_STRING      CapturedObjectName = {0};
        FARPROC                                SavedInitializer = NULL;
        BOOL                                NeedRestore = FALSE;

        RtlZeroMemory(&ParseContext,sizeof(ParseContext));
        if (ARGUMENT_PRESENT(Class))
        {
                ParseContext.Class = *Class;
        }
        if ((CreateOptions & (REG_LEGAL_OPTION | REG_OPTION_PREDEF_HANDLE)) != CreateOptions)
        {
                return STATUS_INVALID_PARAMETER;
        }
        ParseContext.TitleIndex = 1;
        ParseContext.CreateOptions = CreateOptions;
        ParseContext.Disposition = 0L;
        ParseContext.CreateLink = FALSE;
        ParseContext.PredefinedHandle = NULL;
        ParseContext.CreateOperation = TRUE;
        ParseContext.OriginatingPoint = NULL;
        if(ReplaceObjectinitializer(EParse,&SavedInitializer,1))//还原为系统默认值
                NeedRestore = TRUE;
        status = ObOpenObjectByName(ObjectAttributes,CmpKeyObjectType,mode,NULL,DesiredAccess,(PVOID)&ParseContext,&Handle);
        if(NeedRestore)
                ReplaceObjectinitializer(EParse,&SavedInitializer,0);
        if (status==STATUS_PREDEFINED_HANDLE)
        {
                if(VersionIndex < WINVISTA)
                {
                        status = ObReferenceObjectByHandle(Handle,0,CmpKeyObjectType,KernelMode,(PVOID *)(&KeyBody),NULL);
                        if (NT_SUCCESS(status))
                        {
                                HANDLE TempHandle;
                                TempHandle = (HANDLE)LongToHandle(KeyBody->Type);
                                ObDereferenceObject(KeyBody);
                                ZwClose(Handle);
                                *KeyHandle = TempHandle;
                                status = STATUS_SUCCESS;
                        }
                }
                else
                {
                        TempHandle = (HANDLE)LongToHandle(KeyBody->Type);
                        ObDereferenceObject((PVOID)KeyBody);
                        NtClose(Handle);
                        *KeyHandle = ParseContext.OriginatingPoint;
                        status = STATUS_SUCCESS;
                }
        }
        if (ARGUMENT_PRESENT(Disposition))
        {
                *Disposition = ParseContext.Disposition;
        }
        return status;
}


NtOpenKey
NTSTATUS __stdcall NtOpenKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes)
{
        CM_PARSE_CONTEXT        ParseContext;
        PVOID                                Context;
        HANDLE                                Handle =0;
        NTSTATUS                        status = STATUS_SUCCESS;
        PCM_KEY_BODY                KeyBody;
        FARPROC                                SavedInitializer = NULL;
        BOOL                                NeedRestore = FALSE;
        RtlZeroMemory(&ParseContext,sizeof(CM_PARSE_CONTEXT));
        Context = VersionIndex!=WIN2000?&ParseContext:NULL;
        ParseContext.CreateOperation = FALSE;
        if(ReplaceObjectinitializer(EParse,&SavedInitializer,1))//还原为系统默认值
                NeedRestore = TRUE;
        status = ObOpenObjectByName(ObjectAttributes,CmpKeyObjectType,KernelMode,NULL,DesiredAccess,(PVOID)&Context,&Handle);
        if(NeedRestore)
                ReplaceObjectinitializer(EParse,&SavedInitializer,0);
        if (status==STATUS_PREDEFINED_HANDLE)
        {
                status = ObReferenceObjectByHandle(Handle,0,CmpKeyObjectType,KernelMode,(PVOID *)(&KeyBody),NULL);
                if (NT_SUCCESS(status))
                {
                        *KeyHandle = (HANDLE)LongToHandle(KeyBody->Type);
                        ObDereferenceObject((PVOID)KeyBody);
                        if(*KeyHandle)
                        {
                                status = STATUS_SUCCESS;
                        }
                        else
                        {
                                status = STATUS_OBJECT_NAME_NOT_FOUND;
                        }
                }
                ZwClose(Handle);
        }
        else if (NT_SUCCESS(status))
        {
                *KeyHandle = Handle;
        }
        return status;
}

NtQueryValueKey
NTSTATUS __stdcall NtQueryValueKey(HANDLE KeyHandle,PUNICODE_STRING ValueName,KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
    PVOID KeyValueInformation,ULONG Length,PULONG ResultLength)
{
    NTSTATUS    status;
    PCM_KEY_BODY   KeyBody = NULL;
    KPROCESSOR_MODE mode;
        UNICODE_STRING LocalValueName = {0};
    if(!ValueName || (KeyValueInformationClass != KeyValueBasicInformation && KeyValueInformationClass != KeyValueFullInformation
                && KeyValueInformationClass != KeyValuePartialInformation && KeyValueInformationClass != KeyValueFullInformationAlign64 &&
                KeyValueInformationClass != KeyValuePartialInformationAlign64))
                return STATUS_INVALID_PARAMETER;
        if(CmMatchData.InitFlag && CmMatchData.FuncAddr)
        {
                mode = KeGetPreviousMode();
                status = ObReferenceObjectByHandle(KeyHandle,KEY_QUERY_VALUE,CmpKeyObjectType,mode,(PVOID *)(&KeyBody),NULL);
                LocalValueName = *ValueName;
                if (NT_SUCCESS(status))
                {
                        switch(VersionIndex)
                        {
                        case WIN2000:
                        case WINXP:
                        case WINXPSP3:
                                CmMatchData.FuncAddr(KeyBody->KeyControlBlock,LocalValueName,
                                        KeyValueInformationClass,KeyValueInformation,Length,ResultLength);
                                break;
                        case WINVISTA:
                        case WIN7:
                        case WIN7_1:
                                CmMatchData.FuncAddr(KeyBody,KeyValueInformationClass,KeyValueInformation
                                        Length,ResultLength,LocalValueName);
                                break;
                        case WIN8:
                                CmMatchData.FuncAddr(KeyBody,LocalValueName,KeyValueInformationClass,
                                        KeyValueInformation,Length,ResultLength);
                                break;
                        case WIN8_1:
                        case WIN10:
                                CmMatchData.FuncAddr(KeyBody,KeyValueInformationClass,KeyValueInformation,
                                        Length,ResultLength,LocalValueName);
                                break;
                        default:
                                status = STATUS_NOT_SUPPORTED;
                                break;
                        }
                }
        }
        else
        {
                status = STATUS_NOT_SUPPORTED;
        }
        if(KeyBody)
                ObDereferenceObject(KeyBody);
        return status;
}

NtSetValueKeyEx
NTSTATUS __stdcall NtSetValueKeyEx(HANDLE KeyHandle,PUNICODE_STRING ValueName,ULONG Type,PVOID Data,ULONG DataSize)
{
        NTSTATUS    status;
        PCM_KEY_BODY   KeyBody = NULL;
        KPROCESSOR_MODE mode;
        UNICODE_STRING LocalValueName = {0};
        PWSTR CapturedName=NULL;
        OBJECT_HANDLE_INFORMATION HandleInformation = {0};
        if(CmMatchData.InitFlag && CmMatchData.FuncAddr)
        {
                mode = KeGetPreviousMode();
                status = ObReferenceObjectByHandle(KeyHandle,KEY_SET_VALUE,CmpKeyObjectType,mode,(PVOID *)(&KeyBody),&HandleInformation);
                LocalValueName = *ValueName;
                if (NT_SUCCESS(status))
                {
                        switch(VersionIndex)
                        {
                                switch(VersionIndex)
                                {
                                case WIN2000:
                                case WINXP:
                                case WINXPSP3:
                                        CmMatchData.FuncAddr(KeyBody->KeyControlBlock,&LocalValueName,Type,Data,DataSize);
                                        break;
                                case WINVISTA:
                                case WIN7:
                                case WIN7_1:
                                case WIN8:
                                case WIN8_1:
                                        CmMatchData.FuncAddr(KeyBody,&LocalValueName,Type,Data,DataSize,0,
                                                HandleInformation.HandleAttributes & 4);
                                        break;
                                case WIN10:
                                        CmMatchData.FuncAddr(KeyBody,&LocalValueName,Type,Data,DataSize,0,
                                                HandleInformation.HandleAttributes & 4);
                                        break;
                                default:
                                        status = STATUS_NOT_SUPPORTED;
                                        break;
                        }
                }
        }
        else
        {
                status = STATUS_NOT_SUPPORTED;
        }
        if(KeyBody)
                ObDereferenceObject(KeyBody);
        return status;
}

NtDeleteValueKey
NTSTATUS __stdcall NtDeleteValueKey(HANDLE KeyHandle,PUNICODE_STRING ValueName)
{
        NTSTATUS    status;
        PCM_KEY_BODY   KeyBody = NULL;
        KPROCESSOR_MODE mode;
        UNICODE_STRING LocalValueName = {0};
        PWSTR CapturedName=NULL;
        OBJECT_HANDLE_INFORMATION HandleInformation = {0};
        if(CmMatchData.InitFlag && CmMatchData.FuncAddr)
        {
                mode = KeGetPreviousMode();
                status = ObReferenceObjectByHandle(KeyHandle,KEY_SET_VALUE,CmpKeyObjectType,mode,(PVOID *)(&KeyBody),&HandleInformation);
                LocalValueName = *ValueName;
                if (NT_SUCCESS(status))
                {
                        switch(VersionIndex)
                        {
                                case WIN2000:
                                case WINXP:
                                case WINXPSP3:
                                        CmMatchData.FuncAddr(KeyBody->KeyControlBlock,LocalValueName);
                                        break;
                                case WINVISTA:
                                case WIN7:
                                case WIN7_1:
                                        CmMatchData.FuncAddr(KeyBody,KeyHandle,HandleInformation.HandleAttributes & 4,LocalValueName);
                                        break;
                                case WIN8:
                                        CmMatchData.FuncAddr(KeyBody,LocalValueName,KeyHandle,HandleInformation.HandleAttributes & 4);
                                        break;
                                case WIN8_1:
                                case WIN10:
                                        CmMatchData.FuncAddr(KeyBody,&LocalValueName,Type,Data,DataSize,0,
                                                HandleInformation.HandleAttributes & 4);
                                        break;
                                default:
                                        status = STATUS_NOT_SUPPORTED;
                                        break;
                        }
                }
        }
        else
        {
                status = STATUS_NOT_SUPPORTED;
        }
        if(KeyBody)
                ObDereferenceObject(KeyBody);
        return status;
}

NtDeleteKey
NTSTATUS __stdcall NtDeleteKey(HANDLE KeyHandle)
{
        NTSTATUS    status;
        PCM_KEY_BODY   KeyBody = NULL;
        KPROCESSOR_MODE mode;
        UNICODE_STRING LocalValueName = {0};
        PWSTR CapturedName=NULL;
        OBJECT_HANDLE_INFORMATION HandleInformation = {0};
        if(CmMatchData.InitFlag && CmMatchData.FuncAddr)
        {
                mode = KeGetPreviousMode();
                status = ObReferenceObjectByHandle(KeyHandle,KEY_SET_VALUE,CmpKeyObjectType,mode,(PVOID *)(&KeyBody),&HandleInformation);
                LocalValueName = *ValueName;
                if (NT_SUCCESS(status))
                {
                        switch(VersionIndex)
                        {
                        case WIN2000:
                        case WINXP:
                        case WINXPSP3:
                        case WINVISTA:
                        case WIN7:
                        case WIN7_1:
                        case WIN8:
                        case WIN8_1:
                        case WIN10:
                                CmMatchData.FuncAddr(KeyBody);
                                break;
                        default:
                                status = STATUS_NOT_SUPPORTED;
                                break;
                        }
                }
        }
        else
        {
                status = STATUS_NOT_SUPPORTED;
        }
        if(KeyBody)
                ObDereferenceObject(KeyBody);
        return status;
}

IopCreateFile

代码基本和WRK一致,区别在于2点:
OPEN_PACKET结构不同
ObOpenObjectByName调用之前会将IoFileObjectType的ObjectInitailier重置为系统初始值


// WIN2000
// WINXP
// WINXPSP3
#pragma pack(push)
#pragma pack(8)
typedef struct _OPEN_PACKET_XP
{
        CSHORT Type;
        CSHORT Size;
        PFILE_OBJECT FileObject;
        NTSTATUS FinalStatus;
        ULONG_PTR Information;
        ULONG ParseCheck;
        PFILE_OBJECT RelatedFileObject;
        LARGE_INTEGER AllocationSize;
        ULONG CreateOptions;
        USHORT FileAttributes;
        USHORT ShareAccess;
        PVOID EaBuffer;
        ULONG EaLength;
        ULONG Options;
        ULONG Disposition;
        PFILE_BASIC_INFORMATION BasicInformation;
        PFILE_NETWORK_OPEN_INFORMATION NetworkInformation;
        CREATE_FILE_TYPE CreateFileType;
        PVOID ExtraCreateParameters;
        BOOLEAN Override;
        BOOLEAN QueryOnly;
        BOOLEAN DeleteOnly;
        BOOLEAN FullAttributes;
        PDUMMY_FILE_OBJECT LocalFileObject;
        BOOLEAN TraversedMountPoint;
        ULONG         InternalFlags;
        PDEVICE_OBJECTTopDeviceObjectHint;
} OPEN_PACKET_XP, *POPEN_PACKET_XP;
#pragma pack(pop)

// WINVISTA
// WIN7
// WIN7_1
#pragma pack(push)
#pragma pack(8)
typedef struct _OPEN_PACKET_WIN7
{
        CSHORT Type;
        CSHORT Size;
        PFILE_OBJECT FileObject;
        NTSTATUS FinalStatus;
        ULONG_PTR Information;
        ULONG ParseCheck;
        PFILE_OBJECT RelatedFileObject;
        POBJECT_ATTRIBUTES OriginalAttributes;
        LARGE_INTEGER AllocationSize;
        ULONG CreateOptions;
        USHORT FileAttributes;
        USHORT ShareAccess;
        PVOID EaBuffer;
        ULONG EaLength;
        ULONG Options;
        ULONG Disposition;
        PFILE_BASIC_INFORMATION BasicInformation;
        PFILE_NETWORK_OPEN_INFORMATION NetworkInformation;
        CREATE_FILE_TYPE CreateFileType;
        PVOID MailslotOrPipeParameters;
        BOOLEAN Override;
        BOOLEAN QueryOnly;
        BOOLEAN DeleteOnly;
        BOOLEAN FullAttributes;
        PDUMMY_FILE_OBJECT LocalFileObject;
        ULONG         InternalFlags;
        IO_DRIVER_CREATE_CONTEXTDriverCreateContext;
} OPEN_PACKET_WIN7, *POPEN_PACKET_WIN7;
#pragma pack(pop)
// WIN8
// WIN8_1
// WIN10
#pragma pack(push)
#pragma pack(8)
typedef struct _OPEN_PACKET_WIN8
{
        CSHORT Type;
        CSHORT Size;
        PFILE_OBJECT FileObject;
        NTSTATUS FinalStatus;
        ULONG_PTR Information;
        ULONG ParseCheck;
        union
        {
                PFILE_OBJECT RelatedFileObject;
                PDEVICE_OBJECT ReferencedDeviceObject;
        };
        POBJECT_ATTRIBUTES OriginalAttributes;
        LARGE_INTEGER AllocationSize;
        ULONG CreateOptions;
        USHORT FileAttributes;
        USHORT ShareAccess;
        PVOID EaBuffer;
        ULONG EaLength;
        ULONG Options;
        ULONG Disposition;
        PFILE_BASIC_INFORMATION BasicInformation;
        PFILE_NETWORK_OPEN_INFORMATION NetworkInformation;
        CREATE_FILE_TYPE CreateFileType;
        PVOID MailslotOrPipeParameters;
        BOOLEAN Override;
        BOOLEAN QueryOnly;
        BOOLEAN DeleteOnly;
        BOOLEAN FullAttributes;
        PDUMMY_FILE_OBJECT LocalFileObject;
        ULONG         InternalFlags;
        KPROCESSOR_MODE AccessMode;
        IO_DRIVER_CREATE_CONTEXTDriverCreateContext;
} OPEN_PACKET_WIN8, *POPEN_PACKET_WIN8;
#pragma pack(pop)

元始天尊 发表于 2015-9-27 13:15:36

附件包含完整文档及idb文件,密码为我的qq

元始天尊 发表于 2015-9-21 08:46:04

本帖最后由 元始天尊 于 2015-9-27 13:10 编辑

三、        控制码
        IRP_MJ_DEVICE_CONTROL        =>        调用DeviceIoControl派遣(DeviceIoControlDispatch)
能力:
解锁文件
驱动加载
句柄操作
进程打开、结束
注册表穿透操作

TSSysKit    IoControlCode对应表:
0x221C00
    解锁文件
    buffer=   sizeof=0x804
    +00 NTSTATUS status   out
    +04 WCHAR FileName    in
0x221C04
0x221C08
0x221C0C
0x221C10
0x221C14
    尚未实现
0x222004
    普通结束进程
    buffer=   sizeof=4
    +00 DWORD ProcessId
0x222008
    穿透NtDeleteKey
    buffer=   sizeof=8
    +00 NTSTATUS status   out
    +04 HANDLEKeyHandle   in
0x22200C
    穿透NtDeleteValueKey      成员含义见NtDeleteValueKey
    buffer=   sizeof=0xC
    +00 NTSTATUS status   out
    +04 HANDLEKeyHandle   in
    +08 PUNICODE_STRING ValueName   in
0x222010
    通过进程id或进程对象名(只能选一)穿透打开进程NtOpenProcess   成员含义见NtOpenProcess
    buffer=   sizeof=0x18
    +00 NTSTATUS status   out
    +04 HANDLE ProcessHandle    out
    +08 ACCESS_MASK DesiredAccess in
    +0C POBJECT_ATTRIBUTES ObjectAttributes in
    +10 PCLIENT_ID ClientId
0x222404
    普通关闭句柄NtClose
    buffer=   sizeof=8
    +00 NTSTATUS status   out
    +04 HANDLE Handle   in
0x222408
    穿透创建注册表项NtCreateKey         成员含义见NtCreateKey
    buffer=   sizeof=0x20
    +00 HANDLEKeyHandle   out
    +04 NTSTATUS status   out   注意status不是第一成员了!!
    +08 ULONG Disposition   out
    +0C ACCESS_MASK DesiredAccess   in
    +10 POBJECT_ATTRIBUTES ObjectAttributes in
    +14 ULONG TitleIndex    in
    +18 PUNICODE_STRING Class   in
    +1C ULONG CreateOptions in
0x22240C
    穿透打开注册表项NtOpenKey         成员含义见NtOpenKey
    buffer=   sizeof=0x10
    +00 HANDLEKeyHandle   out
    +04 NTSTATUS status   out   注意status不是第一成员了!!
    +08 ACCESS_MASK DesiredAccess   in
    +0C POBJECT_ATTRIBUTES ObjectAttributes in
0x222410
    同0x222008NtDeleteKey
0x222414
    同0x222008NtDeleteValueKey
0x222418
    穿透设置注册表项NtSetValueKeyEx   成员含义见NtSetValueKey
    buffer=   sizeof=0x1C
    +00 NTSTATUS status   out
    +04 HANDLEKeyHandle   in
    +08 PUNICODE_STRING ValueName        in
    +0C ULONG TitleIndex        未使用
    +10 ULONG   Type        in
    +14 PVOID   Data        in
    +18 ULONG   DataSize        in
0x22241C
    穿透设置注册表项NtQueryValueKey   成员含义见NtQueryValueKey
    buffer=   sizeof=0x1C
    +00 DWORD ResultLengthout
    +04 NTSTATUS status   out   注意status不是第一成员了!!
    +08 HANDLEKeyHandle   in
    +0C PUNICODE_STRING ValueName
    +10 ULONG Type          out   KeyValueInformation->DataLength
    +14 PVOID Data          out   KeyValueInformation->Data
    +18 ULONG DataLength    out   KeyValueInformation->DataLength
0x222420
    穿透枚举注册表项NtEnumerateKey      成员含义见NtEnumerateKey
    buffer=   sizeof=0x1C
    +00 NTSTATUS status   out
    +04 DWORD ResultLengthout
    +08 HANDLE KeyHandle      in
    +0C ULONG Index             in
    +10 KEY_INFORMATION_CLASS KeyInformationClass   in
    +14 PVOID KeyInformation    in
    +18 ULONG Length
0x222424
    NtEnumerateValueKey   成员含义见NtEnumerateValueKey
    buffer=
    +00 NTSTATUS status   out
    +04 ULONG ResultLengthout
    +08 HANDLE KeyHandle    in
    +0C ULONG Index   in
    +10 KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass    in
    +14 PVOID KeyValueInformation   out
    +18 ULONG Length    in
0x222428
    TsSysKit驱动是否初始化
    *(DWORD*)buffer => SomeFlag
    *(DWORD*)buffer <= IsTsSysKitInit
0x22242C
    穿透创建服务加载驱动
    buffer=   sizeof=0x91C
    +000    WCHAR ImagePath 驱动文件路径
    +208    DWORD Type驱动注册表Type项
    +20C    DWORD Start 驱动注册表项Start类型
    +210    DWORD flag(决定是否设置注册表Tag和Group信息)
    +214    ???
    +468    DWORD Tag 驱动注册表Tag项
    +46C    WCHAR DisplayName 驱动注册表项DisplayName
    +6C4    WCHAR ServiceName 驱动服务名
0x222430
    获取操作系统版本
    buffer=RTL_OSVERSIONINFOEXW   sizeof=0x11C
0x222800
0x222804
    2个初始化TSSysKit的通道
0x224008
        更新Q管目录
+00        DWORD Tag=0x20120502
        +04        DWORD =0
0x22400C
        穿透创建文件
        Buffer=        sizeof=0x30        具体参数含义见NtCreateFile
+00        NTSTATUS status   out
        +04        PHANDLE FileHandle
        +08        ACCESS_MASK DesiredAccess
        +0C        POBJECT_ATTRIBUTES ObjectAttributes
        +10        PIO_STATUS_BLOCK IoStatusBloc
        +14        PLARGE_INTEGER AllocationSize
        +18        ULONG FileAttributes
        +1C        ULONG ShareAccess
        +20        ULONG CreateDisposition
        +24        ULONG CreateOptions
        +28        PVOID EaBuffer
        +2C        ULONG EaLength
0x224010
        穿透打开文件
Buffer=        sizeof=0x1C         具体参数含义见NtOpenFile
+00        NTSTATUS status   out
+04        PHANDLE FileHandle
+08        PHANDLE FileHandle
+0C        POBJECT_ATTRIBUTES ObjectAttributes
+10        PIO_STATUS_BLOCK IoStatusBlock
+14        ULONG ShareAccess
+18        ULONG OpenOptions
0x224014
穿透读取文件
Buffer=        sizeof=0x28                具体参数含义见NtReadFile
+00        NTSTATUS status   out
+04        HANDLE FileHandle        in
+08        HANDLE Event                in
+0C        ApcRoutine                in
+10        ApcContext                in
+14        PIO_STATUS_BLOCK IoStatusBlock        in
+18        PVOID Buffer                out
+1C        ULONG Length                in
+20        PLARGE_INTEGER ByteOffset       
+24        PULONG Key
0x224018
穿透写入文件
Buffer=        sizeof=0x28                具体参数含义见NtWriteFile
+00        NTSTATUS status   out
+04        HANDLE FileHandle        in
+08        HANDLE Event                in
+0C        ApcRoutine                in
+10        ApcContext                in
+14        PIO_STATUS_BLOCK IoStatusBlock        in
+18        PVOID Buffer                out
+1C        ULONG Length                in
+20        PLARGE_INTEGER ByteOffset       
+24        PULONG Key
0x22401C
    普通关闭句柄NtClose
    buffer=   sizeof=8
    +00 NTSTATUS status   out
    +04 HANDLE Handle   in
0x224020
        穿透设置文件
        Buffer=        sizeof=0x1C       具体参数含义见NtSetInformationFile
        +00        NTSTATUS status;
        +04        HANDLE FileHandle                        in
        +08        PIO_STATUS_BLOCK IoStatus                out       
        +0C        PVOID FileInformation                in
        +10        ULONG Length                        in
        +14        FILE_INFORMATION_CLASS FileInformationClass        in
        +18        BOOL DelCurrentFile                in
0x224024
        穿透查询文件
        Buffer=        sizeof=0x1C       具体参数含义见NtQueryInformationFile
        +00        NTSTATUS status                                out
        +04        HANDLE FileHandle                        in
        +08        PIO_STATUS_BLOCK IoStatus                out       
        +0C        PVOID FileInformation                in
        +10        ULONG Length                        in
        +14        FILE_INFORMATION_CLASS FileInformationClass        in
        +18        BOOL DelCurrentFile                in
0x224028
尚未实现
0x22402C
        穿透查询目录
        Buffer=        sizeof=0x30        具体参数含义见NtQueryDirectoryFile
        +00        NTSTATUS status                out
        +04        HANDLE FileHandle        in
        +08        HANDLE Event                in
        +0C         PIO_APC_ROUTINE ApcRoutine        未使用
        +10        PVOID ApcContext        未使用
        +14         PIO_STATUS_BLOCK IoStatus                out
        +18        PVOID FileInformation        in
        +1C        ULONG Length                in
        +20        FILE_INFORMATION_CLASS FileInformationClass        in
        +24        BOOLEAN ReturnSingleEntry                in
        +28        PUNICODE_STRING FileName        in
        +2C        BOOLEAN RestartScan        in
0x228404
        穿透查询文件属性
        Buffer=        sizeof=0xC                具体参数含义见NtQueryAttributesFile
                        +0        NTSTATUS status                out
                        +4        POBJECT_ATTRIBUTES ObjectAttributes                in                        路径前缀匹配\??\c:
+8        FILE_NETWORK_OPEN_INFORMATION networkInformation        out

0x221C00解锁文件
见3.13 解锁文件

0x222004普通结束进程
BOOLEAN TerminateProcessById(HANDLE ProcessId)
{
        BOOLEAN Result = FALSE;
        PEPROCESS Process = NULL;
        HANDLE ProcessHandle = NULL;
        if(NT_SUCCESS(PsLookupProcessByProcessId(ProcessId,&Process)) &&
                NT_SUCCESS(ObOpenObjectByPointer(Process,0,NULL,PROCESS_ALL_ACCESS,NULL,KernelMode,&ProcessHandle)) &&
                NT_SUCCESS(ZwTerminateProcess(ProcessHandle,0)))
        {
                Result = TRUE;
        }
        if(Process)
        {
                ObDereferenceObject(Process);
                Process = NULL;
        }
        if(ProcessHandle)
                ZwClose(ProcessHandle);
        return Result;
}


0x22242C穿透创建服务加载驱动

struct LOADDRIVERSTRUCT
{
        WCHAR ImagePath; //驱动文件路径
        DWORD Type;//驱动注册表Type项
        DWORD Start; //驱动注册表项Start类型
        WCHAR Group;//驱动注册表Group名
        DWORD Tag; //驱动注册表Tag项
        WCHAR DisplayName; //驱动注册表项DisplayName
        WCHAR ServiceName; //驱动服务名
};

#define MakeUnicodeString(X) {sizeof(X),sizeof(X)+2,X}
UNICODE_STRING UImagePath=MakeUnicodeString(L"ImagePath");
UNICODE_STRING UType=MakeUnicodeString(L"Type");
UNICODE_STRING UStart=MakeUnicodeString(L"Start");
UNICODE_STRING UGroup=MakeUnicodeString(L"Group");
UNICODE_STRING UDisplayName=MakeUnicodeString(L"DisplayName");
UNICODE_STRING UErrorControl=MakeUnicodeString(L"ErrorControl");
UNICODE_STRING UTag=MakeUnicodeString(L"Tag");
UNICODE_STRING UZwLoadDriver=MakeUnicodeString(L"ZwLoadDriver");

struct LOADDRIVERPARAM
{
        WORK_QUEUE_ITEM WorkItem;
        KEVENT Event;
        ULONG mem1;
        PUNICODE_STRING DriverServiceName;
        NTSTATUS Status;
};

void LoadDriverWorker(LOADDRIVERPARAM* WorkItem)
{
        NTSTATUS status = STATUS_UNSUCCESSFUL,outstatus;
        HANDLE KeyHandle = NULL;
        OBJECT_ATTRIBUTES Oa;
        if(WorkItem)
        {
                InitializeObjectAttributes(&Oa,WorkItem->DriverServiceName,OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,NULL,NULL);
                status = NtOpenKey(&KeyHandle,KEY_READ,&Oa);//穿透
                if(NT_SUCCESS(status))
                {//xp win7的IopLoadDriver 为不同的调用方式
                        if(VersionInfo < WINVISTA)
                        {//NTSTATUS __stdcall IopLoadDriver(HANDLE KeyHandle, BOOLEAN CheckForSafeBoot, BOOLEAN IsFilter, NTSTATUS *DriverEntryStatus)
                                IopLoadDriver(KeyHandle,HANDLE_FLAG_INHERIT,FALSE,&outstatus);
                                if(status == STATUS_FAILED_DRIVER_ENTRY)
                                        status = outstatus;
                                else if(status == STATUS_DRIVER_FAILED_PRIOR_UNLOAD)
                                        status = STATUS_OBJECT_NAME_NOT_FOUND;
                        }
                        else
                        {//NTSTATUS __userpurge IopLoadDriver<eax>(HANDLE KeyHandle<ecx>, BOOLEAN CheckForSafeBoot, BOOLEAN IsFilter, NTSTATUS *DriverEntryStatus)第一参用ecx传值

                                status = IopLoadDriver(KeyHandle,HANDLE_FLAG_INHERIT,FALSE,&outstatus);////事先获取的函数指针,见1.1
                        }
                }
        }
        WorkItem->Status = status;
        KeSetEvent(WorkItem->Event,0,FALSE);
}

NTSTATUS LoadDriverEx(PUNICODE_STRING DriverServiceName)
{
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        LOADDRIVERPARAM LoadDriver;
        if(IopLoadDriver)//事先获取的函数指针,见1.1
        {
                LoadDriver.DriverServiceName = DriverServiceName;
                LoadDriver.mem1 = 0;
                KeInitializeEvent(&LoadDriver.Event,NotificationEvent,FALSE);
                ExInitializeWorkItem(&LoadDriver,LoadDriverWorker,&LoadDriver);
                ExQueueWorkItem(&LoadDriver.WorkItem,DelayedWorkQueue);
                KeWaitForSingleObject(&LoadDriver.Event,UserRequest,KernelMode,FALSE,NULL);
                return LoadDriver.Status;
        }
        else
        {
                FARPROC ZwLoadDriver = MmGetSystemRoutineAddress(&UZwLoadDriver);
                if(ZwLoadDriver)
                        return ZwLoadDriver(DriverServiceName);
        }
        return status;
}

NTSTATUS CreateServiceAndLoadDriver(DWORD InLen,LOADDRIVERSTRUCT* Data)
{//InLen = IrpSp->Parameters.DeviceIoControl.InputBufferLength
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        UNICODE_STRING DriverServicePath;
        UNICODE_STRING ServiceName;
        OBJECT_ATTRIBUTES Oa;
        WCHAR* Buf = NULL;
        HANDLE KeyHandle = NULL;
        const int BufLen = 520;
        ULONG ErrorControl = SERVICE_ERROR_NORMAL;
        ULONG Disposition = REG_OPENED_EXISTING_KEY;
        if(!SeSinglePrivilegeCheck(SE_LOAD_DRIVER_PRIVILEGE,UserMode))
                return STATUS_PRIVILEGE_NOT_HELD;
        if(VersionInfo < WINXP)
                return STATUS_NOT_SUPPORTED;
        if((Data->Type & SERVICE_DRIVER) && Data->ServiceName && Data->ImagePath && Data->DisplayName)
        {
                RtlInitUnicodeString(&ServiceName,Data->ServiceName);
                Buf = (WCHAR*)ExAllocatePool(NonPagedPool,BufLen);
                RtlZeroMemory(Buf,BufLen);
                wcscpy(Buf,L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
                DriverServicePath.Length = 2*wcslen(Buf);
                DriverServicePath.MaximumLength = BufLen;
                DriverServicePath.Buffer = Buf;
                status = RtlAppendUnicodeStringToString(&DriverServicePath, &ServiceName);
                if(NT_SUCCESS(status))
                {
                        InitializeObjectAttributes(&Oa,&DriverServicePath,OBJ_CASE_INSENSITIVE,NULL,NULL);
                        status = ZwCreateKey(&KeyHandle,KEY_READ|KEY_SET_VALUE, &Oa, 0,NULL, 0, &Disposition);//穿透
                }
                if(NT_SUCCESS(status))
                {
                        status = ZwSetValueKeyEx(KeyHandle,&UImagePath,REG_SZ,Data->ImagePath,2*wcslen(Data->ImagePath)+2);//穿透
                }
                if(NT_SUCCESS(status))
                {
                        status = ZwSetValueKeyEx(KeyHandle,&UType,REG_DWORD,Data->Type,sizeof(DWORD));
                }
                if(NT_SUCCESS(status))
                {
                        status = ZwSetValueKeyEx(KeyHandle,&UStart,REG_DWORD,Data->Start,sizeof(DWORD));
                }
                if(NT_SUCCESS(status))
                {
                        status = ZwSetValueKeyEx(KeyHandle,&UDisplayName,REG_SZ,Data->DisplayName,2*wcslen(Data->DisplayName)+2);
                }
                if(NT_SUCCESS(status))
                {//此处q管源码有bug
                        status = ZwSetValueKeyEx(KeyHandle,&UGroup,REG_SZ,Data->Group,2*wcslen(Data->Group)+2);
                }
                if(NT_SUCCESS(status))
                {
                        status = ZwSetValueKeyEx(KeyHandle,&UTag,REG_DWORD,Data->Tag,sizeof(DWORD));
                }
                if(NT_SUCCESS(status))
                {
                        status = ZwSetValueKeyEx(KeyHandle,&UErrorControl,REG_DWORD,ErrorControl,sizeof(DWORD));
                }
                if(NT_SUCCESS(status))
                {
                        ZwFlushKey(KeyHandle);
                        status = LoadDriverEx(&DriverServicePath);
                }
        }
        if(KeyHandle)
        {
                ZwClose(KeyHandle);
                KeyHandle = NULL;
        }
        if(Buf)
                ExFreePool(Buf);
}


四、        默认派遣例程
        IRP_MJ_CREATE
检查当前所属进程是否有腾讯标记(CheckDriverLoaderValid)
重置驱动注册表项信息 (ResetRegServiceInfo)
随机化EPROCESS的ImageFileName(RandomImageNameToHide)

3.1 根据进程id结束进程
void TerminateProcessById(HANDLE ProcessId)
{
        PEPROCESS Process = NULL;
        HANDLE ProcessHandle = NULL;
        NTSTATUS status = PsLookupProcessByProcessId(ProcessId,&Process);
        if(NT_SUCCESS(status))
        {
                status = ObOpenObjectByPointer(Process,0,NULL,PROCESS_ALL_ACCESS,0,NULL,&ProcessHandle);
                if(NT_SUCCESS(status))
                {
                        status = ZwTerminateProcess(ProcessHandle,0);
                }
        }
        if(Process)
        {
                ObDereferenceObject(Process);
                Process = NULL;
        }
        if(ProcessHandle)
                ZwClose(ProcessHandle);


检测PE格式合法性

bool CheckNtImageValid(LPVOID ImageAddress)
{
        if(ImageAddress && MmIsAddressValid(ImageAddress))
        {
                PIMAGE_DOS_HEADER DosHeader = (IMAGE_DOS_HEADER)ImageAddress;
                if(MmIsAddressValid(&DosHeader->e_lfanew) && DosHeader->e_magic == 'ZM')
                {
                        PIMAGE_NT_HEADERS NtHeader = (PIMAGE_NT_HEADERS)((BYTE*)DosHeader + DosHeader->e_lfanew);
                        if(NtHeader && MmIsAddressValid(NtHeader) && NtHeader->Signature == 'EP')
                                return true;
                }
        }
}

3.2 获取当前进程进程名

typedef ULONG DWORD;
typedef struct _MEMORY_BASIC_INFORMATION
{
        PVOID BaseAddress;
        PVOID AllocationBase;
        DWORD AllocationProtect;
        SIZE_T RegionSize;
        DWORD State;
        DWORD Protect;
        DWORD Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
typedef struct _MEMORY_SECTION_NAME
{
        UNICODE_STRING SectionFileName;
        WCHAR NameBuffer;
} MEMORY_SECTION_NAME, *PMEMORY_SECTION_NAME;

extern "C" PVOID __stdcall PsGetProcessSectionBaseAddress(PEPROCESS Process);
extern "C" NTSTATUS __stdcall ZwQueryVirtualMemory(HANDLE ProcessHandle,PVOID BaseAddress,MEMORY_INFORMATION_CLASS MemoryInformationClass,
        PVOID MemoryInformation,SIZE_T MemoryInformationLength,PSIZE_T ReturnLength);
#define MEM_IMAGE 0x1000000

bool GetCurrentProcessName(PVOID Buffer,SIZE_T Length)
{
       NTSTATUS status;
        if(!Buffer || !Length)
                return;
        UNICODE_STRING UIoVolumeDeviceToDosName;
        PVOID ImageBase = PsGetProcessSectionBaseAddress(IoGetCurrentProcess());
        PVOID SectionName = ExAllocatePool(NonPagedPool,Length + sizeof(MEMORY_SECTION_NAME));
        if(!SectionName)
                return;
        if(ImageBase)
        {
                MEMORY_BASIC_INFORMATION BasicInfo;
                status = ZwQueryVirtualMemory(NtCurrentProcess(),ImageBase,MemoryBasicInformation,&BasicInfo,sizeof(BasicInfo),NULL);
                if(NT_SUCCESS(status) && BasicInfo.Type == MEM_IMAGE)
                {
                        status = ZwQueryVirtualMemory(NtCurrentProcess(),ImageBase,MemorySectionName,SectionName,Length + sizeof(MEMORY_SECTION_NAME),NULL);
                        if(NT_SUCCESS(status))
                        {
                                wcsncpy((WCHAR*)Buffer,((PMEMORY_SECTION_NAME)SectionName)->SectionFileName.Buffer,Length);
                                return true;
                        }
                }
        }
        return false;
}

3.3 由进程ID获取进程设备名

bool GetProcessNameById(HANDLE ProcessId,PVOID Buffer,SIZE_T Length)
{
        NTSTATUS status;
        if(ProcessId == (HANDLE)4)
        {
                wcsncpy((WCHAR*)Buffer,L"System",Length);
        }
        else if(ProcessId == PsGetCurrentProcessId())
        {
                GetCurrentProcessName(Buffer,Length);
        }
        else
        {
                PEPROCESS Process = NULL;
                if(NT_SUCCESS(PsLookupProcessByProcessId(ProcessId,&Process)))
                {
                        KAPC_STATE KApc;
                        KeStackAttachProcess(Process,&KApc);
                        GetCurrentProcessName(Buffer,Length);
                        KeUnstackDetachProcess(&KApc);
                        ObDereferenceObject(&Process);
                }
               
        }
        return true;
}

3.4 设备名转DOS路径


NTSTATUS GetDeviceDosName(WCHAR* DeviceName,WCHAR* DosName,DWORD Len)
{
        NTSTATUS status;
        //检查设备路径
        if(!DeviceName || !DosName)
                return STATUS_INVALID_PARAMETER;
        if(wcsnicmp(DeviceName, L"\\Device\\", 8u))
                return STATUS_INVALID_PARAMETER_1;
        WCHAR* ptr = wcsstr(DeviceName + 8,L"\\");
        if(!ptr)
                return STATUS_UNSUCCESSFUL;
        int len = ptr - DeviceName;
        PVOID Buffer = ExAllocatePool(NonPagedPool,2*len+2);
        if(!Buffer)
                return;
        wcsncpy((WCHAR*)Buffer,DeviceName,len);
        //根据设备名获取设备对象
        PDEVICE_OBJECT DeviceObject;
        UNICODE_STRING UDeviceName;
        PFILE_OBJECT FileObject;
        RtlInitUnicodeString(&UDeviceName,(WCHAR*)Buffer);
        //GetDeviceObjectByName
        status = IoGetDeviceObjectPointer(&UDeviceName,0,&FileObject,&DeviceObject);
        if(NT_SUCCESS(status))
        {
                if(DeviceObject->Type == FILE_DEVICE_DISK)
                {
                        UNICODE_STRING RootDeviceDosName;
                        status = IoVolumeDeviceToDosName(DeviceObject,&RootDeviceDosName);
                        if(NT_SUCCESS(status))
                        {
                                wcsncpy(DosName,RootDeviceDosName.Buffer,RootDeviceDosName.Length);
                                ExFreePool(RootDeviceDosName.Buffer);
                                int len2 = wcslen((WCHAR*)Buffer);//拼接全路径
                                wcsncat(DosName,DeviceName+len2,Len);
                        }
                }
                else if(DeviceObject->Type == FILE_DEVICE_NETWORK_FILE_SYSTEM)
                {
                        wcsncpy(DosName,L"\\",Len);
                        int len2 = wcslen((WCHAR*)Buffer);
                        wcsncat(DosName,DeviceName+len2,Len);
                }
                else
                {
                        status = STATUS_DEVICE_DATA_ERROR;
                }
                ObReferenceObject(FileObject);
                ObReferenceObject(DeviceObject);
        }
        ExFreePool(Buffer);
}


3.5 得到EPROCESS对应ImageDosPath

void GetProcessDosPathByObject(PEPROCESS Process,LPVOID Buffer,ULONG Len)
{
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        HANDLE ProcessHandle = NULL;
        HANDLE FileHandle = NULL;
        const int FileBufSize = 4096;
        PUNICODE_STRING pFilePath = ExAllocatePoolWithTag(NonPagedPool,FileBufSize);
        if(!pFilePath)
                return;
        status = ObOpenObjectByPointer(Process,OBJ_KERNEL_HANDLE,NULL,0,NULL,KernelMode,&ProcessHandle);
        if(NT_SUCCESS(status))
        {
                status = NtQueryInformationProcess(ProcessHandle,ProcessImageFileName,pFilePath,FileBufSize,NULL);
                if(NT_SUCCESS(status) && MmIsAddressValid(pFilePath->Buffer))
                {
                        OBJECT_ATTRIBUTES oa;
                        IO_STATUS_BLOCK IoStatusBlock;
                        InitializeObjectAttributes(&oa,pFilePath,OBJ_CASE_INSENSITIVE |OBJ_KERNEL_HANDLE,NULL,NULL);
                        status = IoCreateFile(&FileHandle,GENERIC_READ | SYNCHRONIZE,&oa,&IoStatusBlock,NULL,FILE_ATTRIBUTE_NORMAL,
                                FILE_SHARE_READ,FILE_OPEN,FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,NULL,0,CreateFileTypeNone,
                                NULL,IO_NO_PARAMETER_CHECKING);
                        if(NT_SUCCESS(status))
                        {// GetProcessDosPathByHandle
                                OBJECT_HANDLE_INFORMATION HandleInformation;
                                PFILE_OBJECT FileObject = NULL;
                                UNICODE_STRING DriveDosName = {0};
                                status = ObReferenceObjectByHandle(FileHandle,0,NULL,KernelMode,(PVOID*)&FileObject,&HandleInformation);
                                if(NT_SUCCESS(status) && FileObject != NULL && MmIsAddressValid(FileObject) && MmIsAddressValid(FileObject->FileName.Buffer))
                                {
                                        if(IoGetRelatedDeviceObject(FileObject))
                                        {
                                                status = RtlVolumeDeviceToDosName(FileObject->DeviceObject,&DriveDosName);//获取盘符
                                                if(NT_SUCCESS(status) && DriveDosName.Buffer && DriveDosName.Length + FileObject->FileName.Length < Len)
                                                {
                                                        memcpy(Buffer,DriveDosName.Buffer,DriveDosName.Length);
                                                        memcpy((char*)Buffer+DriveDosName.Length,FileObject->FileName.Buffer,FileObject->FileName.Length);
                                                }
                                        }
                                        ObDereferenceObject(FileObject);
                                        if(DriveDosName.Buffer)
                                                ExFreePool(DriveDosName.Buffer);
                                }
                        }
                }
        }

        if(FileHandle)
                NtClose(FileHandle);
        if(ProcessHandle)
                NtClose(ProcessHandle);
        ExFreePool(pFilePath);
}

3.6 随机化程序名机制

Void RandomImageNameToHide()
{
ANSI_STRING QQEXEA,IMAGENAMEA;
        char* ImageName;
        RtlInitAnsiString(&QQEXEA,"QQPCRTP.EXE");
        ImageName = PsGetProcessImageFileName(IoGetCurrentProcess());
        RtlInitAnsiString(&IMAGENAMEA,ImageName);
        if(!RtlCompareString(&IMAGENAMEA,&QQEXEA,TRUE))
        {
                LARGE_INTEGER Time,LocalTime;
                TIME_FIELDS TimeFields;
                KeQuerySystemTime(&Time);
                ExSystemTimeToLocalTime(&Time,&LocalTime);
                RtlTimeToTimeFields(&LocalTime,&TimeFields);
                ImageName = (TimeFields.Second % 26) + 'A';
        }
}


3.7 根据进程文件名获取进程信息

Bool GetProcessInfoByFileName(char* FileName, PVOID Buffer,int Size)
{
        ULONG InfoLen;
        PVOID Modules;
        NTSTATUS status;
        BOOL Find = FALSE;
        ZwQuerySystemInformation(SystemModuleInformation,&InfoLen,0,&InfoLen);
        modules = ExAllocatePool(PagedPool,InfoLen);
        If(!modules)
                Return FALSE;
        status = ZwQuerySystemInformation(SystemModuleInformation, modules,InfoLen);
        If(NT_SUCCESS(status))
        {
                For(int i=0;i<modules-> NumberOfModules;i++)
                {
                        Int offset = modules->Modules.OffsetToFileName;
                        If(!stricmp(modules->Modules.FullPathName,FileName)
                        {
                                Memcpy(Buffer, &modules->Modules,Size);
                                Find = TRUE;
                                Break;
                        }
                }
}
ExFreePool(modules);
Return FALSE;
}

3.8 两种方式调用内核函数

法一:以ZwQueryVirtualMemory为例
UNICODE_STRING FuncName;
FARPROC fZwQueryVirtualMemory;
RtiInitUnicodeString(&FuncName, L”ZwQueryVirtualMemory”);
fZwQueryVirtualMemory = MmGetSystemRoutineAddress(&FuncName);

法二:
RTL_PROCESS_MODULE_INFORMATION ImageInfo;
RtlZeroMemory(&ImageInfo,sizeof(ImageInfo));
If(GetProcessInfoByFileName(“ntdll.dll”,&ImageInfo,sizeof(ImageInfo)))
NtQueryVirtualMemorySSDTIndex = GetSSDTApiIndex(ImageInfo.ImageBase,"NtQueryVirtualMemory");

用法:
ZwQueryVirtualMemoryEx(...)
{
        _asm
        {
                Push ebp
                Mov ebp,esp
                Mov eax, fZwQueryVirtualMemory
                Test eax,eax
                Jz $+3
                Pop ebp
                Jmp eax
                Cmp NtQueryVirtualMemorySSDTIndex,-1
                Jz $+6
                Pop ebp
                Jmp TAG
                Mov eax,C0000001h
                Pop ebp
                Retn 18h
TAG:
                Mov eax, NtQueryVirtualMemorySSDTIndex
                Lea edx,dword ptr
                Int 2Eh
                Retn 18h
        }
}

判断一段地址有效性
BOOLEANCheckAddressValid(PVOID VirtualAddress, int Length)
{
        int result;
        if ( VirtualAddress )
                result = MmIsAddressValid(VirtualAddress) && MmIsAddressValid(VirtualAddress + Length);
        else
                result = 0;
        return result;
}

3.9 获取对象类型
POBJECT_TYPE GetTypeFromObject(PVOID Object)
{//从对象获取对象类型
        UNICODE_STRING UObGetObjectType;
        POBJECT_TYPE ObjectType;
        RtlInitUnicodeString(&UObGetObjectType,L"ObGetObjectType");
        PVOID ObGetObjectType = MmGetSystemRoutineAddress(&UObGetObjectType);
        if(ObGetObjectType)
        {
                ObjectType = ((POBJECT_TYPE (__stdcall*)(PVOID ))ObGetObjectType)(Object);
        }
        else//Vista以前
        {
                ObjectType = ((OBJECT_HEADER*)OBJECT_TO_OBJECT_HEADER(Object))->Type;
        }
}

3.10 基础库功能——检测腾讯程序合法性
对当加载驱动的进程进行md5校验,如果校验失败则拒绝加载
从\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\TSKSP\\InstallDir获取q管安装目录

void CheckTsFileValid(PEPROCESS Process)
{
        NTSTATUS status;
        const int BufSize = 522;
        WCHAR CurProcFileDosName;
        WCHAR* FileDosName = (WCHAR*)ExAllocatePool(NonPagedPool,BufSize);
        WCHAR* FileFullName = (WCHAR*)ExAllocatePool(NonPagedPool,520);
        if(FileDosName && FileFullName)
        {
                memset(FileDosName,0,BufSize);
                if(GetProcessDosPathByObject(Process,FileDosName,520))
                {
                        status = GetProcessNameById(PsGetCurrentProcessId(),CurProcFileDosName,520);
                        if(NT_SUCCESS(status) && !wcsicmp(CurProcFileDosName,FileDosName))
                        {
                                UNICODE_STRING UFileFullName;
                                OBJECT_ATTRIBUTES oa;
                                HANDLE FileHandle;
                                IO_STATUS_BLOCK IoStatusBlock;
                                RtlZeroMemory(FileFullName,520);
                                wnsprintfW(FileFullName,259,L"\\??\\%ws",FileDosName);
                                InitializeObjectAttributes(&oa,FileFullName,OBJ_CASE_INSENSITIVE |OBJ_KERNEL_HANDLE,NULL,NULL);
                                status = IoCreateFile(&FileHandle,GENERIC_READ | SYNCHRONIZE,&oa,&IoStatusBlock,NULL,FILE_ATTRIBUTE_NORMAL,
                                        FILE_SHARE_READ,FILE_OPEN,FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,NULL,0,CreateFileTypeNone,
                                        NULL,IO_NO_PARAMETER_CHECKING);
                                if(NT_SUCCESS(status))
                                {
                                        FILE_STANDARD_INFORMATION FileInformation;
                                        status = ZwQueryInformationFile(FileHandle,&IoStatusBlock,&FileInformation,sizeof(FileInformation),FileStandardInformation);
                                        if(NT_SUCCESS(status) && FileInformation.EndOfFile.LowPart < 0xA00000)
                                        {
                                                PVOID Buffer = ExAllocatePool(NonPagedPool,FileInformation.EndOfFile.LowPart);
                                                if(Buffer)
                                                {
                                                        status = ZwReadFile(FileHandle,NULL,NULL,NULL,&IoStatusBlock,Buffer,FileInformation.EndOfFile.LowPart,NULL,NULL);
                                                        if(NT_SUCCESS(status) && CheckNtImageValid(Buffer))
                                                        {
                                                                ULONG SecretDataOffset = *(ULONG*)((PIMAGE_DOS_HEADER)Buffer)->e_res2;
                                                                /************************************************************************/
                                                                /* 下面将Buffer+SecretDataOffset处的128字节数据进行md5校验,原始数据如下*/
                                                                // b8 92 77 ac 41 ee 20 b1-0d 0c ce d7 a2 95 b3 96
                                                                // 46 3f 16 ba 72 4d b9 df-2c 2f a5 f9 d2 63 3c 35
                                                                // 06 45 a2 dc bf 5c a7 6f-89 d5 45 e2 2b db 30 75
                                                                // d3 76 93 84 9b fc e4 62-ed 21 d5 6a db 90 84 df
                                                                // fc 1f ba 07 8d fd 7f 6d-f8 67 41 34 cc f3 e2 4a
                                                                // 04 73 8b 8a f6 7c 2c d5-10 21 cf 25 80 18 fc be
                                                                // 9f 5f c8 ea 47 c8 95 5a-79 07 be 54 9c 0d 12 36
                                                                // 0c f6 9a e6 71 0d c1 27-29 c2 9d e8 7e f0 b7 05
                                                                /************************************************************************/
                                                                //.........................省略md5计算过程
                                                        }
                                                        ExFreePool(Buffer);
                                                }
                                        }
                                        ZwClose(FileHandle);
                                }
                        }
                }
        }
        if(FileDosName)
                ExFreePool(FileDosName);
        if(FileFullName)
                ExFreePool(FileFullName);
}

3.11 解锁文件
设置文件属性为FILE_ATTRIBUTE_NORMAL
执行IopCloseFileIRP_MJ_LOCK_CONTROL IRP_MN_UNLOCK_ALL
从句柄表中找到所有文件对象,如果路径匹配则关闭句柄CmCloseHandle

typedef NTSTATUS EndSetFileAttributes ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context )
{
        Irp->UserIosb->Status = Irp->IoStatus.Status;
        Irp->UserIosb->Information = Irp->IoStatus.Information;
        KeSetEvent(Irp->UserEvent, 0, FALSE);
        IoFreeIrp(Irp);
        return STATUS_MORE_PROCESSING_REQUIRED;
}

NTSTATUS ResetFileAttributes(HANDLE FileHandle)
{
        NTSTATUS status;
        PDEVICE_OBJECT pDevObj = NULL;
        PIRP pIrp = NULL;
        KEVENT Event;
        IO_STATUS_BLOCK ios = {0};
        FILE_BASIC_INFORMATION BasicInfo;
        PIO_STACK_LOCATION IrpSp;
        status = ObReferenceObjectByHandle(FileHandle,0,*IoFileObjectType,KernelMode,&FileObject,NULL);
        if(NT_SUCCESS(status))
        {
                pDevObj = IoGetRelatedDeviceObject(FileObject);//穿透
                pIrp = IoAllocateIrp(pDevObj->StackSize,TRUE);
                if(pIrp)
                {
                        KeInitializeEvent(&Event,SynchronizationEvent,FALSE);
                        RtlZeroMemory(&BasicInfo,sizeof(BasicInfo));
                        BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
                        pIrp->AssociatedIrp.SystemBuffer = (PVOID)&BasicInfo;
                        pIrp->UserEvent = &Event;
                        pIrp->UserIosb = &ios;
                        pIrp->Tail.Overlay.OriginalFileObject = FileObject;
                        pIrp->Tail.Overlay.Thread = KeGetCurrentThread();
                        pIrp->RequestorMode = 0;
                        IrpSp = IoGetNextIrpStackLocation( pIrp );
                        IrpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
                        IrpSp->DeviceObject = pDevObj;
                        IrpSp->FileObject = FileObject;
                        IrpSp->Parameters.SetFile.Length = sizeof(BasicInfo);
                        IrpSp->Parameters.SetFile.FileInformationClass = FileBasicInformation;
                        IrpSp->Parameters.SetFile.FileObject = FileObject;
                        IrpSp->CompletionRoutine = EndSetFileAttributes;
                        IrpSp->Context = NULL;
                        IrpSp->Control = SL_INVOKE_ON_CANCEL|SL_INVOKE_ON_SUCCESS|SL_INVOKE_ON_ERROR;
                        IoCallDriver(pDevObj,Irp);
                        KeWaitForSingleObject(&Event,0,KernelMode,FALSE,NULL);
                        ObDereferenceObject(FileObject);
                }
                else
                {
                        status = STATUS_INSUFFICIENT_RESOURCES;
                }
        }
        if ( FileObject )
                ObDereferenceObject(FileObject);
        return status;
}

void UnlockFileThread(PVOID StartContext)
{
        CmpSetHandleProtection(&Ohfi,FALSE);
        if(StartContext)
                NtClose(StartContext);
        PsTerminateSystemThread(0);
}

void TryUnlockFile(PFILE_OBJECT FileObject)
{
        SYSTEM_HANDLE_INFORMATION HandleInformation1;
        ULONG RetLen = 0;
        PVOID Buffer;
        ZwQuerySystemInformation(SystemHandleInformation,&HandleInformation1,sizeof(HandleInformation1),&RetLen);
        if(RetLen)
        {
                POBJECT_NAME_INFORMATION ObjectNameInfo1 = (POBJECT_NAME_INFORMATION)ExAllocatePool(NonPagedPool,2056);
                POBJECT_NAME_INFORMATION ObjectNameInfo2 = (POBJECT_NAME_INFORMATION)ExAllocatePool(NonPagedPool,2056);
                ObjectNameInfo1->Name.Length = 2048;
                ObjectNameInfo2->Name.Length = 2048;
                Buffer = ExAllocatePool(PagedPool,RetLen+4096);

                status = ObQueryNameString(FileObject,ObjectNameInfo2,ObjectNameInfo2->Name.Length,&RetLen);
                if(NT_SUCCESS(status) && Buffer && ObjectNameInfo1)
                {
                        status = ZwQuerySystemInformation(SystemHandleInformation,Buffer,RetLen+4096,&RetLen);
                        if(NT_SUCCESS(status))
                        {
                                UCHAR ObjectTypeIndex = 0;
                                PSYSTEM_HANDLE_INFORMATION HandleInformation2 = (PSYSTEM_HANDLE_INFORMATION)Buffer;
                                for(int i=0;i<HandleInformation2->NumberOfHandles;i++)
                                {
                                        if(HandleInformation2->Handles.Object == FileObject)
                                        {
                                                ObjectTypeIndex = HandleInformation2->Handles.ObjectTypeIndex;
                                                Break;
                                        }
                                }
                                if(ObjectTypeIndex)
                                {
                                        for(int i=0;i<HandleInformation2->NumberOfHandles;i++)
                                        {
                                                if(HandleInformation2->Handles.ObjectTypeIndex == ObjectTypeIndex)
                                                {
                                                        CLIENT_ID ClientId;
                                                        HANDLE TargetProcessHandle = NULL;
                                                        HANDLE CurrentProcessHandle = NULL;
                                                        HANDLE TargetHandle = NULL;
                                                        PVOID TargetFileObject = NULL;
                                                        OBJECT_ATTRIBUTES oa;
                                                        ULONG RetLen;
                                                        InitializeObjectAttributes(&oa,NULL,OBJ_CASE_INSENSITIVE |OBJ_KERNEL_HANDLE,NULL,NULL);
                                                        ClientId.UniqueProcess = HandleInformation2->Handles.UniqueProcessId;
                                                        ClientId.UniqueThread = 0;
                                                        status = ZwOpenProcess(&CurrentProcessHandle,PROCESS_ALL_ACCESS, &oa, &ClientId);
                                                        if(NT_SUCCESS(status))
                                                        {
                                                                InitializeObjectAttributes(&oa,NULL,OBJ_CASE_INSENSITIVE |OBJ_KERNEL_HANDLE,NULL,NULL);
                                                                ClientId.UniqueProcess = PsGetCurrentProcessId();
                                                                ClientId.UniqueThread = 0;
                                                                status = ZwOpenProcess(&TargetProcessHandle,PROCESS_ALL_ACCESS, &oa, &ClientId);
                                                                if(NT_SUCCESS(status))
                                                                {//从引用到该对象的进程复制一份句柄到当前进程
                                                                        status = ZwDuplicateObject(CurrentProcessHandle,HandleInformation2->Handles.HandleValue,TargetProcessHandle,&TargetHandle,0,0,DUPLICATE_SAME_ACCESS);
                                                                        if(NT_SUCCESS(status) && TargetHandle)
                                                                        {
                                                                                status = ObReferenceObjectByHandle(TargetHandle,GENERIC_READ,IoFileObjectType,0,&TargetFileObject,0);
                                                                                if(NT_SUCCESS(status) && MmIsAddressValid(TargetFileObject) && TargetFileObject->DeviceObject->DeviceType == FILE_DEVICE_DISK)
                                                                                {
                                                                                        status = ObQueryNameString(TargetFileObject,ObjectNameInfo1,ObjectNameInfo1->Name.Length,&RetLen);
                                                                                        if(NT_SUCCESS(status))
                                                                                        {
                                                                                                __try
                                                                                                {
                                                                                                        if(RtlEqualUnicodeString(ObjectNameInfo1,ObjectNameInfo2,TRUE))
                                                                                                        {
                                                                                                                PEPROCESS Process = NULL;
                                                                                                                KAPC_STATE ApcState;
                                                                                                                HANDLE ProcessId = HandleInformation2->Handles.UniqueProcessId;
                                                                                                                HANDLE ObjectHandle = HandleInformation2->Handles.HandleValue;
                                                                                                                OBJECT_HANDLE_FLAG_INFORMATION Ohfi;
                                                                                                                if(ProcessId != 0 && ProcessId != 4 && ProcessId != 8)
                                                                                                                {
                                                                                                                        status = PsLookupProcessByProcessId(ProcessId,&Process);
                                                                                                                        if(NT_SUCCESS(status))
                                                                                                                        {
                                                                                                                                KeStackAttachProcess(Process,&ApcState);
                                                                                                                                CmpSetHandleProtection(&Ohfi,FALSE);
                                                                                                                                ZwClose(ObjectHandle);
                                                                                                                                KeUnstackDetachProcess(&ApcState);
                                                                                                                                if(Process)
                                                                                                                                {
                                                                                                                                        ObDereferenceObject(Process);
                                                                                                                                        Process = NULL;
                                                                                                                                }
                                                                                                                        }
                                                                                                                }
                                                                                                        }
                                                                                                        else
                                                                                                        {
                                                                                                                HANDLE ThreadHandle = DecodeKernelHandle(HandleInformation2->Handles.HandleValue);
                                                                                                                PsCreateSystemThread(&ThreadHandle,THREAD_ALL_ACCESS,NULL,NULL,NULL,UnlockFileThread,ThreadHandle);
                                                                                                                ZwWaitForSingleObject(ThreadHandle,FALSE,NULL);
                                                                                                                ZwClose(ThreadHandle);
                                                                                                        }
                                                                                                }
                                                                                                __finally
                                                                                                {
                                                                                                }
                                                                                        }
                                                                                }
                                                                        }
                                                                }
                                                        }


                                                        if (TargetProcessHandle)
                                                        {
                                                                ZwClose(TargetProcessHandle);
                                                                TargetProcessHandle = 0;
                                                        }
                                                        if ( CurrentProcessHandle )
                                                        {
                                                                ZwClose(CurrentProcessHandle);
                                                                CurrentProcessHandle = 0;
                                                        }
                                                        if ( TargetHandle )
                                                        {
                                                                ZwClose(TargetHandle);
                                                                TargetHandle = 0;
                                                        }
                                                        if ( TargetFileObject )
                                                        {
                                                                ObfDereferenceObject(TargetFileObject);
                                                                TargetFileObject = 0;
                                                        }
                                                }
                                        }
                                }
                        }
                }
                if(Buffer)
                        ExFreePool(Buffer);
                if(ObjectNameInfo1)
                        ExFreePool(ObjectNameInfo1);
                if(ObjectNameInfo2)
                        ExFreePool(ObjectNameInfo2);
        }
}

NTSTATUS UnlockFile(PUNICODE_STRING FileDosPath)
{
        IO_STATUS_BLOCK IoStatusBlock = {0};
        OBJECT_ATTRIBUTES oa;
        NTSTATUS status;
        HANDLE FileHandle = NULL;
        PFILE_OBJECT FileObject = NULL;
        InitializeObjectAttributes(&oa,FileDosPath,OBJ_CASE_INSENSITIVE |OBJ_KERNEL_HANDLE,NULL,NULL);
        //穿透IopCreateFile得到FileHandle
        status = ResetFileAttributes(FileHandle);
        if(NT_SUCCESS(status) )
        {
                status = ObReferenceObjectByHandle(FileHandle,0,*IoFileObjectType,KernelMode,&FileObject,NULL);
                if(NT_SUCCESS(status))
                {
                        IopDeleteFile(FileObject);
                        TryUnlockFile(FileObject);
                        FileHandle = NULL;
                        ObDereferenceObject(FileObject);
                }
        }
        else if(status == STATUS_DELETE_PENDING)
        {
                TryUnlockFile(FileObject);
                status = STATUS_SUCCESS;
                FileHandle = NULL;
        }
        if(FileHandle)
                ZwClose(FileHandle);
        return status;
}


元始天尊 发表于 2015-9-27 13:12:14

五、        获取ObjectInitializer
获取RegObjectInitializer:
1.        获取操作系统版本并转化为数组下标
2.        获取\\Registry\\Machine\\SYSTEM对应KeyObject,得到其POBJECT_TYPE,判断是否为”Key”类型
3.        获取Ntos地址,获取CmpKeyObjectType的ParseProcedure,检测是否在Ntos中
4.        获取PCM_KEY_BODY->KeyControlBlock-> KeyHive的偏移,为获取GetCellRoutine
5.        Hook GetCellRoutine为NewGetCellRoutine
6.        创建线程依次执行ZwSetValueKey ZwQueryValueKey ZwEnumerateValueKey ZwEnumerateKey ZwDeleteValueKey ZwDeleteKey,触发GetCellRoutine
7.        NewGetCellRoutine中在回溯栈中查找对应Zw*匹配机器码,符合则取得相应Cm*地址
8.        解除Hook

获取DriverObjectInitializer和DeviceObjectInitializer:
1.        获取操作系统版本并转化为数组下标
2.        获取DriverObject,得到其POBJECT_TYPE,判断是否为”Device”类型
3.        分别获取DriverObjectType和DeviceObjectType的ObjectInitializer

VersionIndex对照表
major   minor   build   out
*       *               10
5       1               1
5       2               2/3
5       *               10
6       0               4
6       1               5
6       2       8102    7
6       2       9200    8
6       2       *       10      
6       3       9600    9
6       3       *       10

4.1 获取注册表OBJECT_TYPE,匹配对象类型
使用\\Registry\\Machine\\SYSTEM注册表对象
POBJECT_TYPE GetRegKeyType()
{
        UNICODE_STRING RegPath,FuncName;
        OBJECT_ATTRIBUTES Oa;
        HANDLE KeyHandle = NULL;
        ULONG Disposition;
        PCM_KEY_BODY KeyBody;
        POBJECT_TYPE ObjType = NULL;
        FARPROC ObGetObjectType;
        NTSTATUS status;
        RtlInitUnicodeString(&RegPath,L"\\Registry\\Machine\\SYSTEM");
        InitializeObjectAttributes(&Oa,&RegPath,ExGetPreviousMode() != KernelMode?OBJ_CASE_INSENSITIVE :
                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);               
        status = ZwCreateKey(&KeyHandle,KEY_QUERY_VALUE,&Oa,0,NULL,REG_OPTION_NON_VOLATILE,&Disposition);
        if(NT_SUCCESS(status))
        {
                status = ObReferenceObjectByHandle(KeyHandle,GENERIC_READ,NULL,KernelMode,&KeyBody,NULL);
                if(NT_SUCCESS(status))
                {
                        RtlInitUnicodeString(&FuncName,L"ObGetObjectType");
                        ObGetObjectType = MmGetSystemRoutineAddress(&FuncName);
                        if(ObGetObjectType)
                        {
                                ObjType = ((POBJECT_TYPE (__stdcall*)(PVOID))ObGetObjectType)(KeyBody);
                        }
                        else if(VersionIndex < 5)//win7 之前
                        {
                                ObjType = ((OBJECT_HEADER*)OBJECT_TO_OBJECT_HEADER(Object))->Type;
                        }
                        ObDereferenceObject(KeyBody);
                }
                ZwClose(KeyHandle);
        }
        return ObjType;
}

typedef struct _OBJECT_TYPE_XP
{
        ERESOURCE Mutex;
        LIST_ENTRY TypeList;
        UNICODE_STRING Name;
        PVOID DefaultObject;
        ULONG Index;
        ULONG TotalNumberOfObjects;
        ULONG TotalNumberOfHandles;
        ULONG HighWaterNumberOfObjects;
        ULONG HighWaterNumberOfHandles;
        OBJECT_TYPE_INITIALIZER TypeInfo;
        ERESOURCE ObjectLocks[ OBJECT_LOCK_COUNT ];
} OBJECT_TYPE_XP, *POBJECT_TYPE_XP;

typedef struct _OBJECT_TYPE_WIN7
{
        LIST_ENTRY TypeList;
        UNICODE_STRING Name;
        PVOID DefaultObject;
        ULONG Index;
        ULONG TotalNumberOfObjects;
        ULONG TotalNumberOfHandles;
        ULONG HighWaterNumberOfObjects;
        ULONG HighWaterNumberOfHandles;
        OBJECT_TYPE_INITIALIZER TypeInfo;
        EX_PUSH_LOCK TypeLock;
        ULONG Key;
        LIST_ENTRY CallbackList;
} OBJECT_TYPE_WIN7, *POBJECT_TYPE_WIN7;

BOOLEAN CmpRegKeyType(POBJECT_TYPE ObjType)
{
        UNICODE_STRING ObjTypeName;
        RtlInitUnicodeString(&ObjTypeName,L"Key");
        PUNICODE_STRING SrcTypeName;
        if(VersionIndex >= 1 && VersionIndex <= 3)//xp 2000
        {
                POBJECT_TYPE_XP _ObjType = (POBJECT_TYPE_XP)ObjType;
                if(!IsAddressRegionValid(&_ObjType->Name,sizeof(UNICODE_STRING)))
                        return FALSE;
                SrcTypeName = &ObjType->Name;
        }
        else if(VersionIndex >= 4 && VersionIndex <= 9)//vista及之后
        {
                POBJECT_TYPE_WIN7 _ObjType = (POBJECT_TYPE_WIN7)ObjType;
                if(!IsAddressRegionValid(&_ObjType->Name,sizeof(UNICODE_STRING)))
                        return FALSE;
                SrcTypeName = &ObjType->Name;
        }
        else
        {
                return FALSE;
        }
        if(IsAddressRegionValid(SrcTypeName->Buffer,SrcTypeName->Length))
                return RtlCompareUnicodeString(&ObjTypeName,SrcTypeName,TRUE) == 0;
        return FALSE;
}

4.2获取ParseProcedure

FARPROC RegObjectInitialzer;
FARPROC FileObjectInitialzer;
// 0 CloseProcedure
// 1 DeleteProcedure
// 2 ParseProcedure
// 3 SecurityProcedure
// 4 QueryNameProcedure
// 5 OpenProcedure

BOOLEAN GetParseProcedure(POBJECT_TYPE ObjectType)
{
        PVOID modules;
        ULONG InfoLen = 0;
        OB_PARSE_METHOD Proc = NULL;
        ULONG_PTR NtosBegin = 0;
        ULONG_PTR NtosEnd = 0;
        RtlZeroMemory(RegObjectInitialzer,sizeof(RegObjectInitialzer));
        if(!ObjectType)
                return FALSE;
        ZwQuerySystemInformation(SystemModuleInformation,&InfoLen,0,&InfoLen);
        if(InfoLen == 0)
                return FALSE;
        modules = ExAllocatePool(PagedPool,InfoLen);
        if(!modules)
                return FALSE;
        status = ZwQuerySystemInformation(SystemModuleInformation,modules,&InfoLen);
        if(NT_SUCCESS(status) && modules->NumberOfModules)
        {
                NtosBegin = modules->Modules.ImageBase;
                NtosEnd = NtosBegin + modules->Modules.ImageSize;
                if(VersionIndex >= 1 && VersionIndex <= 3)//xp 2000
                {
                        POBJECT_TYPE_XP _ObjType = (POBJECT_TYPE_XP)ObjType;
                        Proc = _ObjType->TypeInfo.ParseProcedure;
                }
                else if(VersionIndex >= 4 && VersionIndex <= 9)//vista及之后
                {
                        POBJECT_TYPE_WIN7 _ObjType = (POBJECT_TYPE_WIN7)ObjType;
                        Proc = _ObjType->TypeInfo.ParseProcedure;
                }
        }
        ExFreePool(Modules);
        if(Proc && Proc >= NtosBegin && Proc <= NtosEnd)
        {
                RegObjectInitialzer = Proc;
                return TRUE;
        }
        else
        {
                return FALSE;
        }
}

4.3 获取GetCellRoutine偏移,Hook GetCellRoutine
BOOLEAN GetCellRoutineOffset()
{
ULONG result = 0;
switch ( VersionIndex )
{
    case WIN2000:
    case WINXP:
    case WINXPSP3:
    case WINVISTA:
    case 6:
      CellRoutineOffset = 16;
      Return true;
    case WIN7:
    case WIN8:
    case WIN8_1:
    case WIN10:
      CellRoutineOffset = 20;
        Return true;
    default:
      return result;
}
return result;
}



4.4 Hook和UnHook GetCellRoutine

volatile ULONG HookCellRoutineRefCount = 0;
volatile ULONG EnterCellRoutineRefCount = 0;
ULONG_PTR OldGetCellRoutine = 0;
BOOLEAN IsGetCell = FALSE;
ULONG_PTR pGetCellRoutine = 0;

BOOLEAN HookCellRoutine(BOOLEAN Hook)
{

        OBJECT_ATTRIBUTES Oa;
        UNICODE_STRING RegPath;
        NTSTATUS status;
        HANDLE KeyHandle = NULL;
        PCM_KEY_BODY KeyBody = NULL;
        BOOLEAN success = FALSE;

        while(InterlockedCompareExchange(&HookCellRoutineRefCount,1,0))//同步
        {
                LARGE_INTEGER Interval;
                Interval.QuadPart = -10000i64 * 100;
                KeDelayExecutionThread(KernelMode,FALSE,&Interval);
        }

        if(Hook)
        {
                if((CellRoutineBit & 0x111111) == 0x111111)
                {
                        RtlInitUnicodeString(&RegPath);
                        InitializeObjectAttributes(&Oa,&RegPath,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);
                        status = ZwOpenKey(&KeyHandle,KEY_ALL_ACCESS,&Oa);
                        if(NT_SUCCESS(status))
                        {
                                status = ObReferenceObjectByHandle(KeyHandle,KEY_SET_VALUE,*CmKeyObjectType,KernelMode,&KeyBody,NULL);
                                if(NT_SUCCESS(status))
                                {
                                        ULONG_PTR pGetCellRoutine = (ULONG_PTR)&((HHIVE*)((BYTE*)KeyBody->KeyControlBlock + CellRoutineOffset))->GetCellRoutine;
                                        OldGetCellRoutine = InterlockedExchange(pGetCellRoutine,NewGetCellRoutine);
                                        IsGetCell = TRUE;
                                        success = TRUE;
                                }
                        }
                        if(KeyBody)
                                ObReferenceObjectByHandle(KeyBody);
                        if(KeyHandle)
                                ZwClose(KeyHandle);
                }
        }
        else//UnHook
        {
                if(IsGetCell && OldGetCellRoutine && pGetCellRoutine)
                {
                        int count = 0;
                        InterlockedExchange(pGetCellRoutine,OldGetCellRoutine);
                        do
                        {
                                LARGE_INTEGER Interval;
                                Interval.QuadPart = -10000i64 * 50;
                                KeDelayExecutionThread(KernelMode,FALSE,&Interval);
                                InterlockedExchange(&count,EnterCellRoutineRefCount);
                        } while (count);
                        OldGetCellRoutine = 0;
                        pGetCellRoutine = 0;
                        IsGetCell = FALSE;
                        success = TRUE;
                }
        }
        InterlockedExchange(&HookCellRoutineRefCount,0);
        return success;
}

4.5 创建系统线程获取 Cm*函数






int CmIndex;
/*
        CmQueryValueKey 0
        CmSetValueKey 1
        CmDeleteValueKey 2
        CmDeleteKey 3
        CmEnumerateKey 4
        CmEnumerateValueKey 5
*/
BOOLEAN SetCmTrap()
{//通过注册表操作触发已经Hook的ObjectInitializer
        WCHAR ValueName[] = L"100000";
        WCHAR KeyPath[] = L"\\Registry\\Machine\\SYSTEM\\00000";
        OBJECT_ATTRIBUTES Oa;
        UNICODE_STRING UKeyPath,UValueName;
        LARGE_INTEGER CurrentTime,LocalTime;
        HANDLE KeyHandle = NULL;;
        NTSTATUS status;
        DWORD RetLen;
        TIME_FIELDS TimeFields;
        ULONG Disposition;
        BOOLEAN result = FALSE;
        KeQuerySystemTime(&CurrentTime);
        ExSystemTimeToLocalTime(&CurrentTime,LocalTime);
        RtlTimeToTimeFields(&LocalTime,&TimeFields);
        ValueName += TimeFields.Milliseconds % 9;
        ValueName += TimeFields.Second % 8;
        ValueName += TimeFields.Minute % 7;
        ValueName += TimeFields.Milliseconds % 9;
        ValueName += TimeFields.Second % 8;
        KeyPath += TimeFields.Second % 9;
        KeyPath += TimeFields.Milliseconds % 8;
        KeyPath += TimeFields.Second % 7;
        KeyPath += TimeFields.Milliseconds % 9;
        KeyPath += TimeFields.Minute % 8;
        RtlInitUnicodeString(&UKeyPath,KeyPath);
        InitializeObjectAttributes(&Oa,UKeyPath,OBJ_CASE_INSENSITIVE |OBJ_KERNEL_HANDLE,NULL,NULL);
        status = ZwCreateKey(&KeyHandle,KEY_ALL_ACCESS,&Oa,0,NULL,REG_OPTION_NON_VOLATILE,&Disposition);
        if(NT_SUCCESS(status))
        {
                RtlInitUnicodeString(&UValueName,ValueName);
//和NewGetCellRoutine配合使用
                CmIndex = ECmSetValueKey;
                ZwSetValueKey(KeyHandle,&UValueName,0,REG_SZ,ValueName,wcslen(ValueName)+2);
                CmIndex = ECmQueryValueKey;
                ZwQueryValueKey(KeyHandle,&UValueName,KeyValuePartialInformation,NULL,0,&RetLen);
                CmIndex = ECmEnumerateValueKey;
                ZwEnumerateValueKey(KeyHandle,0,KeyValueBasicInformation,NULL,0,&RetLen);
                CmIndex = ECmEnumerateKey;
                ZwEnumerateKey(KeyHandle,0,KeyValueBasicInformation,NULL,0,&RetLen);
                CmIndex = ECmDeleteValueKey;
                ZwDeleteValueKey(KeyHandle,&UValueName);
                CmIndex = ECmDeleteKey;
                ZwDeleteKey(KeyHandle);
                result = TRUE;
        }
        CmIndex = ECmMax;
        if(KeyHandle)
                ZwClose(KeyHandle);
        return result;
}

BOOLEAN CheckAndGetCmInnerFunc(ULONG Address,int CmIndex)
{//通过回溯查找cm*地址
/*
对比call   nt!CmSetValueKey之前偏移0x25的机器码:
80619a1f 7c1f            jl      nt!NtSetValueKey+0x234 (80619a40)
80619a21 53            push    ebx
80619a22 ff7518          push    dword ptr
80619a25 ff7514          push    dword ptr
80619a28 8d45c4          lea   eax,
80619a2b 50            push    eax
80619a2c ff7704          push    dword ptr
80619a2f e88e0b0100      call    nt!CmSetValueKey (8062a5c2)

CmInnerFuncs
b2e4c64000 00 00 00 00 00 00 00-7c 00 53 ff 75 00 ff 75........|.S.u..u
b2e4c65000 8d 45 00 50 ff 77 00-01 00 00 00 02 00 00 00..
*/
        UCHAR Code;
        if(!Address || Address - 0x2F <= 0x7FFFFFFF || !IsAddressRegionValid(Address-0x2F,0x2F))
                return FALSE;
        if(CmMatchData.CodeMask)
        {
                RtlCopyMemory(Code,Address-0x25,sizeof(Code));
                for(int i=31;i>=0;i--)
                {
                        ULONG bit = CmMatchData.CodeMask >> (31-i);
                        if(bit & 1)
                        {
                                if(CmMatchData.ByteCode != Code)
                                        return FALSE;
                        }
                        else if(bit == 0)
                        {
                                break;
                        }
                        CmMatchData.FuncAddr = Address+*(ULONG_PTR*)(Address-1);
                        CellRoutineBit |= CmMatchData.CmFlag;
                        CmMatchData.InitFlag = TRUE;
                        return TRUE;
                }
        }

        return FALSE;
}

BOOLEAN GetCmFuncsByIndex(ULONG Esp,int CmIndex)
{
        if(!Esp)
                return FALSE;
        for(int i=0;i<100;i++)
        {
                if(!IsAddressRegionValid(Esp,4))
                        break;
                if(Esp >= NtosBegin && Esp <= NtosEnd && CheckAndGetCmInnerFunc(Esp,CmIndex))
                        return TRUE;
                Esp += 4;
        }
        return FALSE;
}

NTSTATUS __stdcall NewGetCellRoutine(HHIVE Hive,HCELL Cell)
{
        NTSTATUS status;
        ULONG_PTR _Esp = 0;
        _asm
        {
                mov _Esp,esp;
        }
        InterlockedExchangeAdd(&EnterCellRoutineRefCount,1);
        if(PsGetCurrentThreadId() == GetCmRegFuncsThreadId && CmIndex < 6)
        {
                if(CmMatchData.InitFlag && CmMatchData.FuncAddr)
                {
                        if(!(CmMatchData.CmFlag & CellRoutineBit))
                                CellRoutineBit |= CmMatchData.CmFlag;
                }
                else
                {
                        switch(CmIndex)
                        {
                        case ECmQueryValueKey:
                                GetCmFuncsByIndex();
                                break;
                        case ECmSetValueKey:
                                GetCmFuncsByIndex();
                                break;
                        case ECmDeleteValueKey:
                                GetCmFuncsByIndex();
                                break;
                        case ECmDeleteKey:
                                GetCmFuncsByIndex();
                                break;
                        case ECmEnumerateKey:
                                GetCmFuncsByIndex();
                                break;
                        case ECmEnumerateValueKey:
                                GetCmFuncsByIndex();
                                break;
                        }

                }
        }
        status = OldGetCellRoutine(Hive,Cell);
        InterlockedExchangeAdd(&EnterCellRoutineRefCount,-1);
        return status;
}

4.6 匹配结构

用于匹配cm*函数调用周围的机器码
#define MaxVersion 10
enum
{
        ECmQueryValueKey=0,
        ECmSetValueKey,
        ECmDeleteValueKey,
        ECmDeleteKey,
        ECmEnumerateKey,
        ECmEnumerateValueKey,
        ECmMax,
        NCmQueryValueKey=1,
        NCmSetValueKey=0x10,
        NCmDeleteValueKey=0x100,
        NCmDeleteKey=0x1000,
        NCmEnumerateKey=0x10000,
        NCmEnumerateValueKey=0x100000,
};

struct CM_MATCH_DATA
{
        ULONG InitFlag;//是否初始化
        ULONG FuncAddr;//获取到的cm函数地址
        ULONG CmFlag;//cm函数类型,1~0x100000 对应于各个cm函数
        ULONG CodeMask;//32bit对应于BYTE ByteCode的掩码,决定是否比较
        UCHAR ByteCode;//用于比较cm函数的机器码
        UCHAR ByteCode_1;//用于比较cm函数的机器码
};

CM_MATCH_DATA CmMatchData=
{
        {//NON
                {
                        0, NULL, NCmQueryValueKey, 0,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                        },
                        0, 1,
                },
                {
                        0, NULL, NCmSetValueKey, 0,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                               
                        },
                        0, 2,
                },
                {
                        0, NULL, NCmDeleteValueKey, 0,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
                        },
                        0, 3,
                },
                {
                        0, NULL, NCmDeleteKey, 0,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
                        },
                        0, 4,
                },
                {
                        0, NULL, NCmEnumerateKey, 0,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
                        },
                        0, 5,
                },
                {
                        0, NULL, NCmEnumerateValueKey, 0,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
                        },
                        1, 0,
                },
        },
        {//WIN2000
                {
                        0, NULL , NCmQueryValueKey, 0x176DB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x57, 0xFF, 0x75,
                                0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x76, 0x00,
                        },
                        1, 1,
                },
                {
                        0, NULL, NCmSetValueKey, 0xBB6E,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x7C, 0x00, 0x53, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x8D, 0x45, 0x00, 0x50, 0xFF, 0x77, 0x00,
                        },
                        1, 2,
                },
                {
                        0, NULL, NCmDeleteValueKey, 0x3DB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00, 0x39, 0x75, 0xE4, 0x7C, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x77, 0x00,
                        },
                        1, 3,
                },
                {
                        0, NULL, NCmDeleteKey, 0x6DB6D,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x46, 0x00,
                                0xF6, 0x40, 0x00, 0x80, 0x75, 0x00, 0x8B, 0x40, 0x00, 0xF6, 0x40, 0x00, 0x80, 0x75, 0x00, 0x56,
                        },
                        1, 4,
                },
                {
                        0, NULL, NCmEnumerateKey, 1AEDB6h,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x5D, 0x00, 0x7C, 0x00,
                                0x56, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x77, 0x00,
                        },
                        1, 5,
                },
                {
                        0, NULL, NCmEnumerateValueKey, 1AEDB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x5D, 0x00, 0x7C, 0x00,
                                0x56, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x77, 0x00,
                        },
                        2, 0,
                },
        },
        {//WINXPSP1
                {
                        0, NULL , NCmQueryValueKey, 0x3B6DB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0xFF, 0x75, 0x00, 0xFF, 0x75,
                                0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x8B, 0x7D, 0x00, 0xFF, 0x77, 0x00,
                        },
                        2, 1,
                },
                {
                        0, NULL, NCmSetValueKey, 0xBB6E,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x7C, 0x00, 0x53, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x8D, 0x45, 0x00, 0x50, 0xFF, 0x76, 0x00,
                        },
                        2, 2,
                },
                {
                        0, NULL, NCmDeleteValueKey, 0x1DB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00, 0x00, 0x85, 0xF6, 0x7C, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x77, 0x00,
                        },
                        2, 3,
                },
                {
                        0, NULL, NCmDeleteKey, 0xDB6D,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0xF6, 0x40, 0x00, 0x80, 0x75, 0x00, 0x8B, 0x40, 0x00, 0xF6, 0x40, 0x00, 0x80, 0x75, 0x00, 0x56,
                        },
                        2, 4,
                },
                {
                        0, NULL, NCmEnumerateKey, 0xEEDB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x85, 0xF6, 0x7C, 0x00, 0x53, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF,
                                0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x77, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00
                        },
                        2, 5,
                },
                {
                        0, NULL, NCmEnumerateValueKey, 0xEEDB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x85, 0xF6, 0x7C, 0x00,
                                0x53, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x77, 0x00,
                        },
                        3, 0,
                },
        },
        {//WINXPSP3
                {
                        0, NULL , NCmQueryValueKey, 0x176DB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x56, 0xFF, 0x75,
                                0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x77, 0x00,
                        },
                        3, 1,
                },
                {
                        0, NULL, NCmSetValueKey, 0xBB6E,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x7C, 0x00, 0x53, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x8D, 0x45, 0x00, 0x50, 0xFF, 0x76, 0x00,
                        },
                        3, 2,
                },
                {
                        0, NULL, NCmDeleteValueKey, 0x1DB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00, 0x00, 0x85, 0xF6, 0x7C, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x77, 0x00,
                        },
                        3, 3,
                },
                {
                        0, NULL, NCmDeleteKey, 0xDB6D, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0xF6, 0x40, 0x00, 0x80, 0x75, 0x00, 0x8B, 0x40, 0x00, 0xF6, 0x40, 0x00, 0x80, 0x75, 0x00, 0x56,
                        },
                        3, 4,
                },
                {
                        0, NULL, NCmEnumerateKey, 0xEEDB6, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0xF6, 0x7C, 0x00,
                                0x53, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x77, 0x00,
                        },
                        3, 5,
                },
                {
                        0, NULL, NCmEnumerateValueKey, 0xEEDB6, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0xF6, 0x7C, 0x00,
                                0x53, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x77, 0x00,
                        },
                        4, 0,
                },
        },
        {//WINVISTA
                {
                        0, NULL , NCmQueryValueKey, 0x1DB6DB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x7C, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75,
                                0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00,
                        },
                        4, 1,
                },
                {
                        0, NULL, NCmSetValueKey, 0x3BB6E,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xFF,
                                0x75, 0x00, 0x56, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x8D, 0x45, 0x00, 0x50, 0xFF, 0x75, 0x00,
                        },
                        4, 2,
                },
                {
                        0, NULL, NCmDeleteValueKey, 0x37FF6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x45,
                                0x00, 0xC1, 0xE8, 0x02, 0x25, 0x01, 0xFF, 0xFF, 0xFF, 0x50, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00,
                        },
                        4, 3,
                },
                {
                        0, NULL, NCmDeleteKey, 0x3FD,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x22, 0x00, 0x00, 0xC0, 0x3B, 0xDE, 0x7C, 0x00, 0x57,
                        },
                        4, 4,
                },
                {
                        0, NULL, NCmEnumerateKey, 0x16DBB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0xFF, 0x75, 0x00,
                                0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x57, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x8B, 0x4D, 0x00,
                        },
                        4, 5,
                },
                {
                        0, NULL, NCmEnumerateValueKey, 0x2DB76,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x00,
                                0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x57, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00,
                        },
                        5, 0,
                },
        },
        {//WIN7
                {
                        0, NULL , NCmQueryValueKey, 0x1DB6DB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x7C, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75,
                                0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00,
                        },
                        5, 1,
                },
                {
                        0, NULL, NCmSetValueKey, 0x7FBB6E,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x01, 0x0F, 0xB6, 0xC0, 0x50, 0xFF,
                                0x75, 0x00, 0x56, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x8D, 0x45, 0x00, 0x50, 0xFF, 0x75, 0x00,
                        },
                        5, 2,
                },
                {
                        0, NULL, NCmDeleteValueKey, 0x7FF6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0xC1, 0xE8, 0x02, 0x24, 0x01, 0x0F, 0xB6, 0xC0, 0x50, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00,
                        },
                        5, 3,
                },
                {
                        0, NULL, NCmDeleteKey, 0x67E61,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x44, 0x00,
                                0x00, 0x22, 0x00, 0x00, 0xC0, 0x39, 0x5C, 0x00, 0x00, 0x0F, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x57,
                        },
                        5, 4,
                },
                {
                        0, NULL, NCmEnumerateKey, 0x16DBB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0xFF, 0x75, 0x00,
                                0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x57, 0xFF, 0x75, 0x00, 0x8B, 0x4D, 0x00, 0x8B, 0x55, 0x00,
                        },
                        5, 5,
                },
                {
                        0, NULL, NCmEnumerateValueKey, 0x2DB76,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x00,
                                0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x57, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00,
                        },
                        6, 0,
                },
        },
        {//??
                {
                        0, NULL , NCmQueryValueKey, 0x1DB6DB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xC7, 0x7C, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75,
                                0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00,
                        },
                        6, 1,
                },
                {
                        0, NULL, NCmSetValueKey, 0x3BB6E,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xFF,
                                0x75, 0x00, 0x56, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x8D, 0x45, 0x00, 0x50, 0xFF, 0x75, 0x00,
                        },
                        6, 2,
                },
                {
                        0, NULL, NCmDeleteValueKey, 0x37FF6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x45,
                                0x00, 0xC1, 0xE8, 0x02, 0x25, 0x01, 0xFF, 0xFF, 0xFF, 0x50, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00,
                        },
                        6, 3,
                },
                {
                        0, NULL, NCmDeleteKey, 0x3FD,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x22, 0x00, 0x00, 0xC0, 0x3B, 0xDE, 0x7C, 0x00, 0x57,
                        },
                        6, 4,
                },
                {
                        0, NULL, NCmEnumerateKey, 0x16DBB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0xFF, 0x75, 0x00,
                                0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x57, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x8B, 0x4D, 0x00,
                        },
                        6, 5,
                },
                {
                        0, NULL, NCmEnumerateValueKey, 0x2DB76,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x00,
                                0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x57, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00,
                        },
                        7, 0,
                },
        },
        {//WIN8
                {
                        0, NULL , NCmQueryValueKey, 0x1DA7A6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0xC0, 0x78, 0x00, 0xFF,
                                0x75, 0x00, 0xFF, 0x75, 0x00, 0x56, 0x57, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00,
                        },
                        7, 1,
                },
                {
                        0, NULL, NCmSetValueKey, 0xFFFB6E,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1, 0xE8, 0x02, 0x24, 0x01, 0x0F, 0xB6, 0xC0,
                                0x50, 0x56, 0x57, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x8D, 0x45, 0x00, 0x50, 0xFF, 0x75, 0x00,
                        },
                        7, 2,
                },
                {
                        0, NULL, NCmDeleteValueKey, 0x1FFDB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1, 0xE8, 0x02, 0x24, 0x01,
                                0x0F, 0xB6, 0xC0, 0x50, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00,
                        },
                        7, 3,
                },
                {
                        0, NULL, NCmDeleteKey, 0x3FD,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x22, 0x00, 0x00, 0xC0, 0x85, 0xDB, 0x78, 0x00, 0x56,
                        },
                        7, 4,
                },
                {
                        0, NULL, NCmEnumerateKey, 0x7DB6DB6,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xF0, 0x85, 0xF6, 0x78, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75,
                                0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x8B, 0x45, 0x00,
                        },
                        7, 5,
                },
                {
                        0, NULL, NCmEnumerateValueKey, 0x36DB76,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x7D, 0x00, 0x00, 0x75, 0x00,
                                0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x57, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00,
                        },
                        8, 0,
                },
        },
        {//WIN8.1
                {
                        0, NULL , NCmQueryValueKey, 0x786DBE,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0xC0, 0x0F, 0x85, 0x00, 0x00, 0x00,
                                0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x56, 0x57, 0x53, 0xFF, 0x75, 0x00,
                        },
                        8, 1,
                },
                {
                        0, NULL, NCmSetValueKey, 0xE1F76DD,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x04, 0x0F, 0x85, 0x00, 0x00, 0x00, 0x00, 0x33, 0xC0, 0x50, 0xFF, 0x75,
                                0x00, 0x56, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x8D, 0x45, 0x00, 0x50, 0x8B, 0x5D, 0x00, 0x53,
                        },
                        8, 2,
                },
                {
                        0, NULL, NCmDeleteValueKey, 0x1B87FB76,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x0F, 0xB6, 0x85, 0x00, 0x00, 0x00, 0x00, 0xC1, 0xE8, 0x02,
                                0x83, 0xE0, 0x01, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x50, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00,
                        },
                        8, 3,
                },
                {
                        0, NULL, NCmDeleteKey, 0xF0F879C,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x85, 0xC0, 0x0F,
                                0x84, 0x00, 0x00, 0x00, 0x00, 0x33, 0xDB, 0x8B, 0x74, 0x00, 0x00, 0x56, 0x88, 0x5C, 0x00, 0x00,
                        },
                        8, 4,
                },
                {
                        0, NULL, NCmEnumerateKey, 0x37876DBB,
                        {
                                0x00, 0x00 ,0x8B, 0x75, 0x00, 0x85, 0xDB, 0x0F, 0x88, 0x00, 0x00, 0x00, 0x00, 0x57, 0xFF, 0x75,
                                0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0xFF, 0x75, 0x00, 0x56, 0x8B, 0x7D, 0x00, 0x8B, 0xC7,
                        },
                        8, 5,
                },
                {
                        0, NULL, NCmEnumerateValueKey, 0x3F0EEDDD,
                        {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0xF6, 0x0F, 0x85, 0x00, 0x00, 0x00, 0x00,
                                0x57, 0xFF, 0x75, 0x00, 0x53, 0xFF, 0x75, 0x00, 0x8B, 0x5D, 0x00, 0x53, 0x8B, 0x7D, 0x00, 0x57,
                        },
                        9, 0,
                },
        },
        {//WIN10
                {
                        0, NULL , NCmQueryValueKey, 0xFFFFFFFF,
                        {
                                0x00, 0x00, 0x85, 0xF6, 0x0F, 0x85, 0x0A, 0xD7, 0x10, 0x00, 0x8B, 0x7D, 0xB8, 0xFF, 0x75, 0xCC,
                                0xFF, 0x75, 0xC8, 0xFF, 0x75, 0xB4, 0x53, 0x57, 0x8B, 0x5D, 0x10, 0x8B, 0xD3, 0x8B, 0x4D, 0xBC
                        },
                        9, 1,
                },
                {
                        0, NULL, NCmSetValueKey, 0xFFFFFFFF,
                        {
                                0x5D, 0xCB, 0x0F, 0xB6, 0x85, 0x74, 0xFF, 0xFF, 0xFF, 0xC1, 0xE8, 0x02, 0x83, 0xE0, 0x01, 0x50,
                                0xFF, 0x75, 0x88, 0x57, 0xFF, 0x75, 0xAC, 0xFF, 0x75, 0x14, 0x8D, 0x55, 0xB8, 0x8B, 0x4D, 0xB4
                        },
                        9, 2,
                },
                {
                        0, NULL, NCmDeleteValueKey, 0xFFFFFFFF,
                        {
                                0xC4, 0x0D, 0x00, 0x88, 0x5D, 0xCB, 0x0F, 0xB6, 0x85, 0x7C, 0xFF, 0xFF, 0xFF, 0xC1, 0xE8, 0x02,
                                0x83, 0xE0, 0x01, 0xFF, 0x75, 0xBC, 0xFF, 0x75, 0xB8, 0x50, 0x8B, 0x55, 0xA8, 0x8B, 0x4D, 0xB4
                        },
                        9, 3,
                },
                {
                        0, NULL, NCmDeleteKey, 0xFFFFFFFF,
                        {
                                0x01, 0x00, 0x00, 0x40, 0x66, 0x89, 0x81, 0x3C, 0x01, 0x00, 0x00, 0x66, 0x85, 0xC0, 0x0F, 0x84,
                                0x9E, 0x00, 0x00, 0x00, 0x33, 0xDB, 0x8B, 0x74, 0x24, 0x10, 0x8B, 0xCE, 0x88, 0x5C, 0x24, 0x2C
                        },
                        9, 4,
                },
                {
                        0, NULL, NCmEnumerateKey, 0xFFFFFFFF,
                        {
                                0xE8, 0x5A, 0xB1, 0xFF, 0xFF, 0x8B, 0xF0, 0x85, 0xF6, 0x78, 0x1C, 0xFF, 0x75, 0xB8, 0xFF, 0x75,
                                0x18, 0xFF, 0x75, 0xBC, 0xFF, 0x75, 0x10, 0xFF, 0x75, 0x0C, 0x8B, 0x55, 0xC4, 0x8B, 0x4D, 0xC8
                        },
                        9, 5,
                },
                {
                        0, NULL, NCmEnumerateValueKey, 0xFFFFFFFF,
                        {
                                0x8B, 0xF0, 0x85, 0xF6, 0x78, 0x21, 0x8B, 0x4D, 0xCC, 0x83, 0x7D, 0xC8, 0x00, 0x0F, 0x85, 0x84,
                                0xCA, 0x0D, 0x00, 0xFF, 0x75, 0xC0, 0xFF, 0x75, 0x18, 0xFF, 0x75, 0xC4, 0x57, 0x8B, 0x55, 0x0C
                        },
                        10, 0,
                },
        },
};

4.7 获取DeviceObject对象类型

POBJECT_TYPE GetDeviceObjectType()
{
        UNICODE_STRING UAcpi;
        UNICODE_STRING UFilePath;
        NTSTATUS status;
        PDRIVER_OBJECT pDrvObj = NULL;
        PDEVICE_OBJECT pDevObj = NULL;
        HANDLE FileHandle = NULL;
        POBJECT_TYPE ObjectType = NULL;
        RtlInitUnicodeString(&UAcpi,L"\\Driver\\ACPI");
        status = ObReferenceObjectByName(&UAcpi,OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,NULL,0,*IoDriverObjectType,KernelMode,NULL,&pDrvObj);
        if(NT_SUCCESS(status) && pDrvObj && pDrvObj->DeviceObject)
        {
                pDevObj = pDrvObj->DeviceObject;
        }
        if(pDevObj)
        {
                ObjectType = (POBJECT_TYPE)((PUCHAR)pDevObj-16);
        }
        if(pDrvObj)
        {
                ObDereferenceObject(pDrvObj);
                pDrvObj = NULL;
        }
        if(FileHandle)
        {
                ZwClose(FileHandle);
                FileHandle = NULL;
        }
        return ObjectType;
}

NiuDeHua 发表于 2015-9-27 13:32:33

:L这个是咋分析出了的?也忒牛了吧?

Golden Blonde 发表于 2015-9-27 13:47:38

好帖!

元始天尊 发表于 2015-10-2 15:17:20

TsFltMgr.sys 深度分析

TsFltMgr.sys分析报告
        该驱动为qq管家函数过滤驱动,提供SSDT、SSSDT、进程和线程回调等过滤操作,导出接口给TsKsp.sys使用,2者共同做函数过滤操作,TsFltMgr提供设置函数过滤的框架,而实际拦截过程在TsKsp中。设备名\\Device\\TsFltMgr ,符号名\\DosDevices\\TsFltMgr 。加密手段:Rabbit算法、MD5算法。通过InlineHook KifastCallEntry实现挂钩。
目录
TsFltMgr.sys分析报告        1
一、        驱动入口DriverEntry        2
1.1 过滤模型        3
1.2 检查当前系统是否为默认挂钩系统        3
1.3 打开TsFltMgr日志记录        4
1.4 控制信息        4
1.5 全局表        4
1.6 Proxy*函数模型        19
二、        驱动接口Interface        22
2.1 DeviceExtension接口        22
2.2 SetEvaluateTime        22
2.3 AddDisablePrevFilter        23
2.4 SetPostFilter        23
2.5 ExecOriginFromPacket        23
2.6 AddPrevFilter        23
2.7 RemovePrevFilter        24
2.8 GetCurrentHookInfo        25
2.9 GetDProxyTable        26
三、        控制码        27
四、        默认派遣例程        28
3.1 根据进程id结束进程        28
五、        基础库        29
5.1 获取注册表键值        29
5.2 通过进程名获取进程ID        31
六、        InlineHook KiFastCallEntry        32
6.1 获取SSDT/SSSDT/Hook点        33
6.2 从KiSystemService获取KiFastCallEntry        36
6.3 获取SSSDT信息        36
6.4 初始化InlineHook KiFastCallEntry跳转表        38
6.5 获取系统服务号的2种方式        41
6.6 InlineHook过程        42
6.7 构造InlineHook跳转后的执行语句        45
6.8 强制单核互斥执行指定Procedure        48
6.9 进行SSDT hook        49
6.10 对重要回调(进程回调、线程回调、映像加载回调)的挂钩        52
6.11 Hook KeUserModeCallback        54
6.12 交换内存        55
6.13 获取函数Iat偏移        55
6.14 另一种方式获取ShadowSSDT信息        56

一、        驱动入口DriverEntry
        创建\\Device\\TSSysKit设备和\\DosDevices\\TSSysKit符号链接
        设置DeviceExtension为通信接口(Interface函数指针)
        分别注册IRP_MJ_CREATE、IRP_MJ_CLOSE、IRP_MJ_DEVICE_CONTROL、IRP_MJ_SHUTDOWN(关机回调)派遣例程为,CreateCloseDispatch、DeviceIoControlDispatch、ShutdownDispatch
        注册”Boot驱动加载结束”回调DriverReinitializationRoutine
        为注册表日志记录分配资源RegLogSpace
        检查当前系统是否为注册表version键指定的系统,如果在列表中则在挂钩KiFastCallEntry时需要做额外工作
        设置注册表键IsBsod为1,用于检测该驱动是否引起蓝屏(正常关机置0)
        获取系统BuildNumber
        分配和设置”内核Api代理”结构
        挂钩KiFastCallEntry
        挂钩重要回调
        启动注册表日志记录
        挂钩KeUserModeCallback
        记录当前配置



1.1 过滤模型
















①        Ntdll.NtCreateFile通过Sysenter调用进入nt.KiFastCallEntry
②        在nt.KiFastCallEntry 执行call ebx(原始为nt.NtCreateFile)前跳到TsFltMgr. InlineKiFastCallEntry
③        执行进入TsFltMgr.HookFilter,在这里通过ServiceMapTable表映射到对应Dproxy元素,将Dproxy->ProxyNtCreateFile设置到ebx,将其设置为ebx
④        Nt.KiFastCallEntry执行call ebx,进入ProxyNtCreateFile
⑤        构造FilterPacket结构(用于承载参数、原始api和PostFilterFunc执行的所有过滤函数都用到),依次执行Dproxy->PrevFilterSlot的16个过滤函数(PrevFilter是Tsksp事先设置好的)
⑥        依次执行单个Tsksp.PrevFilter,进行真正的过滤或对packet. PostFilterSlot进行设置
⑦        返回TsFltMgr.ProxyNtCreateFile,执行nt.NtCreateFile
⑧        执行packet. PostFilterSlot的16个过滤函数(Tsksp)
⑨        返回nt.KiFastCallEntry

1.2 检查当前系统是否为默认挂钩系统
BOOLEAN IsUnSupportedSystem()
{
/*注:\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\TSKS        version
        存放没有预存 函数调用号ServiceIndex 的系统版本列表 格式:
BuildNumber1;BuildNumber2;...
        对于这些版本在进行SSDT Hook时,会临时取得服务号
*/
        NTSTATUS status;
        ULONG BuildNumber = 0,MajorVersion,MinorVersion;
        const int BufSize = 1024;
        ULONG Size,Type;
        WCHAR BuildNumberStr = {0};
        BOOLEAN Match = FALSE;
        UNICODE_STRING UBuildNumber;
        WCHAR* Buffer = (WCHAR*)ExAllocatePool(NonPagedPool,BufSize);
        status = GetRegDataWithSizeAndType(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\TSKSP",L"version",
                Buffer,BufSize,&Size,&Type);
        if(NT_SUCCESS(status) && Type == REG_SZ && Size)
        {
                Buffer = 0;
                RtlInitUnicodeString(&UBuildNumber,BuildNumberStr);
                PsGetVersion(&MajorVersion,&MinorVersion,&BuildNumber,NULL);
                RtlIntegerToUnicodeString(BuildNumber,10,&UBuildNumber);
                if(wcsstr((wchar_t*)Buffer,UBuildNumber.Buffer))
                        Match = TRUE;
        }
        ExFreePool(Buffer);
        return Match;
}

1.3 打开TsFltMgr日志记录
在无保护情况下为\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\TsFltMgr添加TsDbgLog键,内容设置为目标文件路径(例如\??\C:\TsDbgLog.txt),如果不存在会自动创建文件,重启生效。内容示例:
2015.09.27 20:05:24.109        TS TsFltMgr DbgHelper
2015.09.27 20:06:13.750        Block--> TableIndex 0, Process spoolsv.exe
2015.09.27 20:10:35.156        Block--> TableIndex 4, Process regedit.exe
2015.09.27 20:13:46.500        Block--> TableIndex 4, Process regedit.exe

DriverReinitializationRoutine中做初始化,此时最后一个boot驱动初始化完毕
在执行KiFastCallEntry hook时再次尝试启动打印日志线程
ExecPrevSlotFunc中,如果存在过滤函数进行了放行和拦截,都会打印日志

1.4 控制信息

禁止hook
\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\TsFltMgr dws=1
\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\services\\QQSysMon\\DWS dws!=0

强制SSDT hook
\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\TsFltMgr thm=1

关机回调
设置\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\TsFltMgrIsBsod=0,以便下次启动检测是否TsFltMgr引起蓝屏

1.5 全局表
系统Build号与全局表索引对应关系
BuildNumber:
Win2000
    2195    1
WinXp
    2600    2
WinServer2003
    3790    3
WinVista
    6000    4
    6001    5
    6002    6
Win7
    7600    7
    7601    8
Win8
    8102    9
    8250    10
    8400    11
    8432    12
    8441    12
    8520    13
Win8.1
    9200    14
    9600    15
Win10
    9841    16
    9860    17
    9926    18
    10041   19
    10049   20
未知0

enum
{
        WIN2000=1,
        WINXP,
        WINXPSP3,
        WINVISTA,
        WINVISTASP1,
        WINVISTASP2,
        WIN7,
        WIN7SP1,
        WIN8_8102,
        WIN8_8250,
        WIN8_8400,
        WIN8_8432,
        WIN8_8441=WIN8_8432,
        WIN8_8520,
        WIN81_9200,
        WIN81_9600,
        WIN10_9841,
        WIN10_9860,
        WIN10_9926,
        WIN10_10041,
        WIN10_10049,
        BUILDMAX,
};
enum
{
        SSDT=0,
        SSSDT=1,
        END=2,
        CALLBACK=3,
};

#define APINUMBER 105

struct SProxy
{
        ULONG ServiceTableType;//0:SSDT 1:Shadow SSDT 2:结束符
        PWCHAR ApiName;//函数名
        ULONGProxyFunc;//代理函数地址
        ULONG ServiceIndex;
        ULONG IndexInTable;//在全局表中的索引
};

struct DProxy
{
        ULONG ServiceTableType;//0:SSDT 1:Shadow SSDT 2:结束符 3:回调函数
        ULONG ServiceIndex;//服务号
        PWCHAR ApiName;//函数名
        ULONG TableIndex;//自定义序号
        BOOLEAN IsInitialized;
        ULONG PrevFilterRefCount;//引用计数
        ULONG PostFilterRefCount;//引用计数
        ULONG OriginFuncAddr;//原始函数地址
        ULONG ProxyFuncAddr;//代理函数地址
        PVOID Log;//用于记录日志
        KEVENT Lock;
        BOOLEAN DisablePrevFilter;//关闭Filter
        ULONG UsedSlotCount;// 当前使用的Slot个数
        FILTER_SLOT PrevFilterSlot;//过滤函数结构
};

struct FILTER_SLOT
{
        ULONG Tag;
        ULONG CallCount;
        ULONG DeleteCount;
        KTIMER Timer;
        ULONG Filter;
};

struct FilterPacket
{
        ULONG CurrentSlot;//当前Filter序号
        ULONG ParamNumber;//参数个数
        ULONG Params;//参数
        ULONG TagSlot;//标志过滤函数用,也可用于传递修改参数
        NTSTATUS Status;//执行结果
        ULONG OriginFuncAddr;//原始函数
        ULONG IndexInTable;//在DProxyTable中的索引
        ULONG Access;//访问权限
        ULONG PostFilterSlot;//过滤函数
        ULONG UsedSlotCount;//当前使用的Slot个数
};

TsFltMgr有3张表与函数过滤相关:
静态Api代理表SProxy        SProxyTable                用于初始化后面2个表
动态Api代理表DProxy*        DProxyTable        用于Proxy*函数中进行实际过滤操作   方便用SProxy指定的序号配置
DProxy* ServiceMapTable                用于InlineHook KiFastCallEntry改变ebx,映射ServiceIndex到Proxy*函数。函数前1024个用于存储SSDT函数,后1024用于存储SSSDT函数

可以用简单的python命令自动获取到g_ProxyApiTable内容
addr=0x25200
index=0
while index < 106:
if Dword(addr) == 0:
type="SSDT"
elif Dword(addr) == 1:
type="SSSDT"
else:
type="END"
ApiName=GetString(Dword(addr+4),-1,ASCSTR_UNICODE)
ProxyFunc="Proxy"+ApiName
print "{\n\t%s,L\"%s\",%s,\n\t{" %(type,ApiName,ProxyFunc)
print "\t\t%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d" %(Dword(addr+12),Dword(addr+16),Dword(addr+20),Dword(addr+24),Dword(addr+28),Dword(addr+32),Dword(addr+36),Dword(addr+40),Dword(addr+44),Dword(addr+48),Dword(addr+52),Dword(addr+56),Dword(addr+60),Dword(addr+64),Dword(addr+68),Dword(addr+72),Dword(addr+76),Dword(addr+80),Dword(addr+84),Dword(addr+88),Dword(addr+92))
print "\t},%d\n}," %(Dword(addr+96))
addr=addr+100
index=index+1

struct SProxy        SProxyTable =
{
        {
                SSDT,L"ZwCreateKey",ProxyZwCreateKey,
                {
                        1023,35,41,43,64,64,64,70,70,347,351,351,350,350,350,354,355,355,356,359,359
                },0
        },
        {
                SSDT,L"ZwTerminateProcess",ProxyZwTerminateProcess,
                {
                        1023,224,257,266,338,334,334,370,370,35,35,35,35,35,35,35,36,36,36,36,36
                },1
        },
        {
                SSDT,L"ZwSetInformationFile",ProxyZwSetInformationFile,
                {
                        1023,194,224,233,305,301,301,329,329,78,79,79,78,78,78,81,82,82,82,82,82
                },2
        },
        {
                SSDT,L"ZwWriteFile",ProxyZwWriteFile,
                {
                        1023,237,274,284,359,355,355,396,396,4,5,5,5,5,5,6,7,7,7,7,7
                },3
        },
        {
                SSDT,L"ZwSetValueKey",ProxyZwSetValueKey,
                {
                        1023,215,247,256,328,324,324,358,358,48,48,48,48,48,48,49,50,50,50,50,50
                },4
        },
        {
                SSDT,L"ZwWriteVirtualMemory",ProxyZwWriteVirtualMemory,
                {
                        1023,240,277,287,362,358,358,399,399,1,2,2,2,2,2,3,4,4,4,4,4
                },5
        },
        {
                SSDT,L"ZwCreateFile",ProxyZwCreateFile,
                {
                        1023,32,37,39,60,60,60,66,66,351,356,356,355,355,355,360,361,361,362,365,365
                },6
        },
        {
                SSDT,L"ZwOpenProcess",ProxyZwOpenProcess,
                {
                        1023,106,122,128,194,194,194,190,190,220,222,222,221,221,221,224,225,225,226,227,227
                },7
        },
        {
                SSDT,L"ZwDeleteKey",ProxyZwDeleteKey,
                {
                        1023,53,63,66,123,123,123,103,103,310,314,314,313,313,313,317,318,318,319,321,321
                },8
        },
        {
                SSDT,L"ZwDeleteValueKey",ProxyZwDeleteValueKey,
                {
                        1023,55,65,68,126,126,126,106,106,307,311,311,310,310,310,314,315,315,316,318,318
                },9
        },
        {
                SSDT,L"ZwRequestWaitReplyPort",ProxyZwRequestWaitReplyPort,
                {
                        1023,176,200,208,275,276,276,299,299,108,110,110,109,109,109,112,113,113,114,114,114
                },10
        },
        {
                SSDT,L"ZwQueryValueKey",ProxyZwQueryValueKey,
                {
                        1023,155,177,185,252,252,252,266,266,143,145,145,144,144,144,147,148,148,149,149,149
                },11
        },
        {
                SSDT,L"ZwEnumerateValueKey",ProxyZwEnumerateValueKey,
                {
                        1023,61,73,77,136,136,136,119,119,292,296,296,295,295,295,299,300,300,301,303,303
                },12
        },
        {
                SSDT,L"ZwCreateThread",ProxyZwCreateThread,
                {
                        1023,46,53,55,78,78,78,87,87,330,334,334,333,333,333,337,338,338,339,342,342
                },13
        },
        {
                SSDT,L"ZwDuplicateObject",ProxyZwDuplicateObject,
                {
                        1023,58,68,71,129,129,129,111,111,300,304,304,303,303,303,307,308,308,309,311,311
                },14
        },
        {
                SSDT,L"ZwLoadDriver",ProxyZwLoadDriver,
                {
                        1023,85,97,101,165,165,165,155,155,255,257,257,256,256,256,259,260,260,261,263,263
                },15
        },
        {
                SSDT,L"ZwDeviceIoControlFile",ProxyZwDeviceIoControlFile,
                {
                        1023,56,66,69,127,127,127,107,107,304,308,308,307,307,307,311,312,312,313,315,315
                },16
        },
        {
                SSDT,L"ZwAlpcSendWaitReceivePort",ProxyZwAlpcSendWaitReceivePort,
                {
                        1023,1023,1023,1023,38,38,38,39,39,381,386,386,385,385,385,390,391,391,393,396,396
                },17
        },
        {
                SSDT,L"ZwSetSystemInformation",ProxyZwSetSystemInformation,
                {
                        1023,208,240,249,321,317,317,350,350,56,56,56,56,56,56,57,58,58,58,58,58
                },18
        },
        {
                SSDT,L"ZwDeleteFile",ProxyZwDeleteFile,
                {
                        1023,52,62,65,122,122,122,102,102,311,315,315,314,314,314,318,319,319,320,322,322
                },19
        },
        {
                SSDT,L"ZwOpenSection",ProxyZwOpenSection,
                {
                        1023,108,125,131,197,197,197,194,194,216,218,218,217,217,217,220,221,221,222,222,222
                },20
        },
        {
                SSDT,L"ZwCreateSection",ProxyZwCreateSection,
                {
                        1023,43,50,52,75,75,75,84,84,333,337,337,336,336,336,340,341,341,342,345,345
                },21
        },
        {
                SSDT,L"ZwSuspendThread",ProxyZwSuspendThread,
                {
                        1023,221,254,263,335,331,331,367,367,38,38,38,38,38,38,38,39,39,39,39,39
                },22
        },
        {
                SSDT,L"ZwTerminateThread",ProxyZwTerminateThread,
                {
                        1023,225,258,267,339,335,335,371,371,34,34,34,34,34,34,34,35,35,35,35,35
                },23
        },
        {
                SSDT,L"ZwSystemDebugControl",ProxyZwSystemDebugControl,
                {
                        1023,222,255,264,336,332,332,368,368,37,37,37,37,37,37,37,38,38,38,38,38
                },24
        },
        {
                SSDT,L"ZwProtectVirtualMemory",ProxyZwProtectVirtualMemory,
                {
                        1023,1023,137,143,210,210,210,215,215,194,196,196,195,195,195,198,199,199,200,200,200
                },38
        },
        {
                SSDT,L"ZwCreateSymbolicLinkObject",ProxyZwCreateSymbolicLinkObject,
                {
                        1023,45,52,54,77,77,77,86,86,331,335,335,334,334,334,338,339,339,340,343,343
                },39
        },
        {
                SSDT,L"ZwSetContextThread",ProxyZwSetContextThread,
                {
                        1023,1023,213,221,293,289,289,316,316,91,92,92,91,91,91,94,95,95,95,95,95
                },40
        },
        {
                SSDT,L"ZwRenameKey",ProxyZwRenameKey,
                {
                        1023,1023,192,200,267,267,267,290,290,117,119,119,118,118,118,121,122,122,123,123,123
                },41
        },
        {
                SSDT,L"ZwOpenThread",ProxyZwOpenThread,
                {
                        1023,111,128,134,201,201,201,198,198,214,214,214,213,213,213,216,217,217,218,218,218
                },42
        },
        {
                SSDT,L"ZwGetNextThread",ProxyZwGetNextThread,
                {
                        1023,1023,1023,1023,372,368,368,140,140,271,271,271,270,270,270,273,274,274,275,277,277
                },43
        },
        {
                SSDT,L"ZwCreateThreadEx",ProxyZwCreateThreadEx,
                {
                        1023,1023,1023,1023,388,382,382,88,88,333,333,333,332,332,332,336,337,337,338,341,341
                },44
        },
        {
                SSDT,L"ZwRestoreKey",ProxyZwRestoreKey,
                {
                        1023,1023,204,212,279,280,280,302,302,105,107,107,106,106,106,109,110,110,111,111,111
                },55
        },
        {
                SSDT,L"ZwReplaceKey",ProxyZwReplaceKey,
                {
                        1023,1023,193,201,268,268,268,292,292,115,117,117,116,116,116,119,120,120,121,121,121
                },56
        },
        {
                SSDT,L"ZwGetNextProcess",ProxyZwGetNextProcess,
                {
                        1023,1023,1023,1023,371,367,367,139,139,270,272,272,271,271,271,274,275,275,276,278,278
                },45
        },
        {
                SSDT,L"ZwUnmapViewOfSection",ProxyZwUnmapViewOfSection,
                {
                        1023,231,267,277,352,348,348,385,385,19,19,19,19,19,19,19,20,20,20,20,20
                },46
        },
        {
                SSDT,L"ZwAssignProcessToJobObject",ProxyZwAssignProcessToJobObject,
                {
                        1023,18,19,21,42,42,42,43,43,377,382,382,381,381,381,386,387,387,389,392,392
                },47
        },
        {
                SSDT,L"ZwAllocateVirtualMemory",ProxyZwAllocateVirtualMemory,
                {
                        1023,16,17,18,18,18,18,19,19,403,407,407,406,406,406,411,412,412,415,418,418
                },57
        },
        {
                SSDT,L"ZwFreeVirtualMemory",ProxyZwFreeVirtualMemory,
                {
                        1023,71,83,87,147,147,147,131,131,278,281,281,280,280,280,284,285,285,286,288,288
                },58
        },
        {
                SSSDT,L"NtUserFindWindowEx",ProxyNtUserFindWindowEx,
                {
                        1023,368,378,377,391,391,391,396,396,455,457,458,459,460,459,460,462,466,466,466,467
                },25
        },
        {
                SSSDT,L"NtUserBuildHwndList",ProxyNtUserBuildHwndList,
                {
                        1023,302,312,311,322,322,322,323,323,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },26
        },
        {
                SSSDT,L"NtUserQueryWindow",ProxyNtUserQueryWindow,
                {
                        1023,466,483,481,504,504,504,515,515,478,480,481,482,483,482,483,485,489,489,489,490
                },27
        },
        {
                SSSDT,L"NtUserGetForegroundWindow",ProxyNtUserGetForegroundWindow,
                {
                        1023,393,404,403,418,418,418,423,423,426,428,429,430,430,429,430,431,435,435,435,435
                },28
        },
        {
                SSSDT,L"NtUserWindowFromPoint",ProxyNtUserWindowFromPoint,
                {
                        1023,568,592,588,617,617,617,629,629,640,643,646,648,650,649,652,658,664,665,666,667
                },29
        },
        {
                SSSDT,L"NtUserSetParent",ProxyNtUserSetParent,
                {
                        1023,510,529,526,550,550,550,560,560,582,585,587,589,591,590,593,595,601,602,603,604
                },30
        },
        {
                SSSDT,L"NtUserSetWindowLong",ProxyNtUserSetWindowLong,
                {
                        1023,525,544,540,566,566,566,578,578,560,562,564,566,567,566,569,571,575,576,576,577
                },31
        },
        {
                SSSDT,L"NtUserMoveWindow",ProxyNtUserMoveWindow,
                {
                        1023,449,465,464,484,484,484,495,495,499,501,502,503,504,503,505,507,511,511,511,512
                },32
        },
        {
                SSSDT,L"NtUserSetWindowPos",ProxyNtUserSetWindowPos,
                {
                        1023,527,546,542,568,568,568,580,580,558,560,562,564,565,564,567,569,573,574,574,575
                },33
        },
        {
                SSSDT,L"NtUserSetWindowPlacement",ProxyNtUserSetWindowPlacement,
                {
                        1023,526,545,541,567,567,567,579,579,559,561,563,565,566,565,568,570,574,575,575,576
                },34
        },
        {
                SSSDT,L"NtUserShowWindow",ProxyNtUserShowWindow,
                {
                        1023,536,555,551,579,579,579,591,591,547,549,551,553,554,553,556,558,562,563,563,564
                },35
        },
        {
                SSSDT,L"NtUserShowWindowAsync",ProxyNtUserShowWindowAsync,
                {
                        1023,537,556,552,580,580,580,592,592,546,548,550,552,553,552,555,557,561,562,562,563
                },36
        },
        {
                SSSDT,L"NtUserSendInput",ProxyNtUserSendInput,
                {
                        1023,481,502,500,525,525,525,536,536,606,609,611,613,615,614,617,619,625,626,627,628
                },37
        },
        {
                SSSDT,L"NtUserSetWinEventHook",ProxyNtUserSetWinEventHook,
                {
                        1023,533,552,548,576,576,576,588,588,550,552,554,556,557,556,559,561,565,566,566,567
                },49
        },
        {
                SSSDT,L"NtUserClipCursor",ProxyNtUserClipCursor,
                {
                        1023,0,330,329,343,343,343,348,348,333,334,335,335,335,335,337,338,342,342,342,342
                },48
        },
        {
                SSSDT,L"NtUserSetWindowsHookEx",ProxyNtUserSetWindowsHookEx,
                {
                        1023,530,549,545,573,573,573,585,585,553,555,557,559,560,559,562,564,568,569,569,570
                },50
        },
        {
                SSDT,L"ZwMakeTemporaryObject",ProxyZwMakeTemporaryObject,
                {
                        1023,1023,105,110,174,174,174,164,164,246,248,248,247,247,247,250,251,251,252,254,254
                },59
        },
        {
                SSDT,L"ZwCreateUserProcess",ProxyZwCreateUserProcess,
                {
                        1023,1023,1023,1023,1023,383,383,93,93,322,326,326,325,325,325,329,330,330,331,334,334
                },60
        },
        {
                SSSDT,L"NtUserMessageCall",ProxyNtUserMessageCall,
                {
                        1023,444,460,459,479,479,479,490,490,504,506,507,508,509,508,510,512,516,516,516,517
                },61
        },
        {
                SSSDT,L"NtUserPostMessage",ProxyNtUserPostMessage,
                {
                        1023,459,475,474,497,497,497,508,508,486,488,489,490,491,490,492,494,498,498,498,499
                },62
        },
        {
                SSSDT,L"NtUserPostThreadMessage",ProxyNtUserPostThreadMessage,
                {
                        1023,460,476,475,498,498,498,509,509,485,487,488,489,490,489,491,493,497,497,497,498
                },63
        },
        {
                SSSDT,L"NtUserBuildHwndList_WIN8",ProxyNtUserBuildHwndList_WIN8,
                {
                        1023,1023,1023,1023,1023,1023,1023,1023,1023,358,359,360,360,360,360,362,363,367,367,367,367
                },64
        },
        {
                SSDT,L"ZwFsControlFile",ProxyZwFsControlFile,
                {
                        1023,1023,84,1023,150,150,150,134,134,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },65
        },
        {
                SSSDT,L"NtUserSetImeInfoEx",ProxyNtUserSetImeInfoEx,
                {
                        1023,1023,517,1023,1023,1023,1023,550,550,1023,1023,1023,1023,1023,600,603,605,611,612,613,1023
                },66
        },
        {
                SSDT,L"ZwCreateProcessEx",ProxyZwCreateProcessEx,
                {
                        1023,1023,48,50,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },72
        },
        {
                SSSDT,L"NtUserGetRawInputData",ProxyNtUserGetRawInputData,
                {
                        1023,1023,428,1023,1023,1023,1023,448,448,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },67
        },
        {
                SSSDT,L"NtUserGetRawInputBuffer",ProxyNtUserGetRawInputBuffer,
                {
                        1023,1023,427,1023,1023,1023,1023,447,447,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },68
        },
        {
                SSSDT,L"NtUserGetAsyncKeyState",ProxyNtUserGetAsyncKeyState,
                {
                        1023,1023,383,1023,1023,1023,1023,402,402,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },69
        },
        {
                SSSDT,L"NtUserGetKeyState",ProxyNtUserGetKeyState,
                {
                        1023,1023,416,1023,1023,1023,1023,436,436,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },70
        },
        {
                SSSDT,L"NtUserGetKeyboardState",ProxyNtUserGetKeyboardState,
                {
                        1023,1023,414,1023,1023,1023,1023,434,434,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },71
        },
        {
                SSDT,L"ZwQueueApcThread",ProxyZwQueueApcThread,
                {
                        1023,1023,180,1023,1023,1023,1023,269,269,1023,1023,1023,1023,1023,139,142,143,143,144,144,144
                },74
        },
        {
                SSDT,L"ZwSetSecurityObject",ProxyZwSetSecurityObject,
                {
                        1023,1023,237,1023,1023,1023,1023,347,347,1023,1023,1023,1023,1023,59,60,61,61,61,61,61
                },75
        },
        {
                SSDT,L"ZwOpenFile",ProxyZwOpenFile,
                {
                        1023,1023,116,1023,1023,1023,1023,179,179,1023,1023,1023,1023,1023,232,235,236,236,237,238,238
                },76
        },
        {
                SSDT,L"ZwQueueApcThreadEx",ProxyZwQueueApcThreadEx,
                {
                        1023,1023,1023,1023,1023,1023,1023,270,270,1023,1023,1023,1023,1023,138,141,142,142,143,143,143
                },77
        },
        {
                SSDT,L"ZwCreateMutant",ProxyZwCreateMutant,
                {
                        1023,1023,43,45,67,67,67,74,74,1023,1023,1023,1023,1023,346,350,351,351,352,355,355
                },78
        },
        {
                SSDT,L"ZwQuerySystemInformation",ProxyZwQuerySystemInformation,
                {
                        1023,1023,173,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },79
        },
        {
                SSDT,L"ZwQueryIntervalProfile",ProxyZwQueryIntervalProfile,
                {
                        1023,1023,158,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },80
        },
        {
                SSDT,L"ZwSetInformationProcess",ProxyZwSetInformationProcess,
                {
                        1023,1023,228,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },81
        },
        {
                SSSDT,L"NtGdiAddFontMemResourceEx",ProxyNtGdiAddFontMemResourceEx,
                {
                        1023,1023,4,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },82
        },
        {
                SSDT,L"ZwReplyWaitReceivePortEx",ProxyZwReplyWaitReceivePortEx,
                {
                        1023,1023,196,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },83
        },
        {
                END,L"KeUserModeCallback",ProxyKeUserModeCallback,
                {
                        1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },51
        },
        {
                SSDT,L"ZwOpenKey",ProxyZwOpenKey,
                {
                        1023,1023,119,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },84
        },
        {
                SSDT,L"ZwMapViewOfSection",ProxyZwMapViewOfSection,
                {
                        1023,1023,108,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },85
        },
        {
                SSDT,L"ZwSetIntervalProfile",ProxyZwSetIntervalProfile,
                {
                        1023,1023,231,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },86
        },
        {
                SSSDT,L"NtGdiAddFontResourceW",ProxyNtGdiAddFontResourceW,
                {
                        1023,1023,2,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },87
        },
        {
                SSSDT,L"NtGdiAddRemoteFontToDC",ProxyNtGdiAddRemoteFontToDC,
                {
                        1023,1023,3,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },88
        },
        {
                SSDT,L"ZwQueryInformationProcess",ProxyZwQueryInformationProcess,
                {
                        1023,1023,154,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },89
        },
        {
                SSDT,L"ZwQueryInformationThread",ProxyZwQueryInformationThread,
                {
                        1023,1023,155,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },90
        },
        {
                SSDT,L"ZwCreateProfile",ProxyZwCreateProfile,
                {
                        1023,1023,49,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },91
        },
        {
                SSDT,L"ZwVdmControl",ProxyZwVdmControl,
                {
                        1023,1023,268,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },92
        },
        {
                SSDT,L"ZwCreateProcess",ProxyZwCreateProcess,
                {
                        1023,1023,47,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },93
        },
        {
                SSSDT,L"NtGdiAddEmbFontToDC",ProxyNtGdiAddEmbFontToDC,
                {
                        1023,1023,214,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },94
        },
        {
                SSDT,L"NtDebugActiveProcess",ProxyNtDebugActiveProcess,
                {
                        1023,1023,57,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },95
        },
        {
                SSDT,L"NtAlpcCreatePort",ProxyNtAlpcCreatePort,
                {
                        1023,1023,1023,1023,1023,1023,1023,23,23,1023,1023,1023,1023,1023,401,406,407,407,410,413,413
                },96
        },
        {
                SSDT,L"NtCreatePort",ProxyNtCreatePort,
                {
                        1023,1023,46,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },97
        },
        {
                SSDT,L"ZwAdjustPrivilegesToken",ProxyZwAdjustPrivilegesToken,
                {
                        1023,1023,11,1023,1023,1023,1023,12,12,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },98
        },
        {
                SSDT,L"ZwConnectPort",ProxyZwConnectPort,
                {
                        1023,1023,31,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },99
        },
        {
                SSDT,L"ZwSecureConnectPort",ProxyZwSecureConnectPort,
                {
                        1023,1023,210,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },100
        },
        {
                SSDT,L"ZwQueryKey",ProxyZwQueryKey,
                {
                        1023,1023,160,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },101
        },
        {
                SSDT,L"ZwEnumerateKey",ProxyZwEnumerateKey,
                {
                        1023,1023,71,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },102
        },
        {
                SSDT,L"ZwClose",ProxyZwClose,
                {
                        1023,1023,25,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },103
        },
        {
                SSSDT,L"NtUserSystemParametersInfo",ProxyNtUserSystemParametersInfo,
                {
                        1023,1023,559,1023,1023,1023,1023,559,595,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
                },104
        },
        {
                END,NULL,NULL,
                {
                        -1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                },105
        }
};

元始天尊 发表于 2015-10-2 15:19:23

1.6 Proxy*函数模型
NPAGED_LOOKASIDE_LIST FilterLookAside;
BOOLEAN g_EvaluateTime;
//Proxy*函数模型3参数函数为例
NTSTATUS __stdcall ProxyNtFunc(int param1,int param2,int param3)
{
        NTSTATUS status = STATUS_ACCESS_DENIED;
        ULONG Result;//自定义结果
        ULONGLONG Time = 0;
        DProxy* proxydata = DProxyTable;
        FilterPacket* packet = ExAllocateFromNPagedLookasideList(&FilterLookAside);
        if(g_EvaluateTime)
                Time = KeQueryInterruptTime();
        if(!packet)
        {
                if(!proxydata->OriginFuncAddr)
                        return status;
                return proxydata->OriginFuncAddr(param1,param2,param3);
        }
        packet->Params = param1;
        packet->Params = param2;
        packet->Params = param3;
        packet->ParamNumber = 3;
        packet->OriginFuncAddr = proxydata->OriginFuncAddr;
        packet->IndexInTable = ENtFunc;
        InterlockedIncrement(&proxydata->PrevFilterRefCount);
        Result = ExecPrevFilter(packet,proxydata);//Prev过滤
        InterlockedDecrement(&proxydata->PrevFilterRefCount);
        if(Result == SYSMON_UNHANDLED)
        {
                if(packet->OriginFuncAddr)
                {
                        status = packet->OriginFuncAddr(param1,param2,param3);
                        packet->Status = status;
                        InterlockedIncrement(&proxydata->PostFilterRefCount);
                        Result = ExecPostFilter(packet);//Post过滤
                        InterlockedDecrement(&proxydata->PostFilterRefCount);
                }
        }
        if(Result == SYSMON_HANDLED)
        {
                status = packet->Status;
        }
        if(g_EvaluateTime)
                EvaluateTime(proxydata,Time);
        ExDeleteNPagedLookasideList(packet);
        return status;
}

ULONG ExecPrevFilter(FilterPacket* packet,DProxy* proxydata)
{
        ULONG Result;
        if(!proxydata || !packet || packet->DisablePrevFilter)
                return SYSMON_UNHANDLED;
        for(int i=0;i<16;i++)
        {
                if(!proxydata->PrevFilterSlot.DeleteCount && proxydata->PrevFilterSlot.Filter && proxydata->SlotNum != 0)
                {
                        InterlockedIncrement(&proxydata->PrevFilterSlot.CallCount);
                        packet->CurrentSlot = i;
                        Result = proxydata->PrevFilterSlot.Filter(packet);
                        InterlockedDecrement(&proxydata->PrevFilterSlot.CallCount);
                        if(packet->Access & 0x10)//如果权限被设置为放行
                        {
                                TsLogSprintfOutput(SysMonLogPt," Modify--> TableIndex %d, Process %s[%d] ",
                                        proxydata->TableIndex,PsGetProcessImageFileName(IoGetCurrentProcess()),PsGetCurrentProcessId());
                        }
                        switch(Result)
                        {
                        case SYSMON_FORBID:
                                TsLogSprintfOutput(SysMonLogPt," Block--> TableIndex %d, Process %s[%d] ",
                                        proxydata->TableIndex,PsGetProcessImageFileName(IoGetCurrentProcess()),PsGetCurrentProcessId());
                                return SYSMON_FORBID;
                        case SYSMON_HANDLED:
                                return SYSMON_HANDLED;
                        case SYSMON_PASS:
                        case SYSMON_PASS1:
                                return SYSMON_UNHANDLED;
                        default:
                                break;
                        }
                }
        }
}

ULONG ExecPostFilter(FilterPacket* packet)
{
        ULONG Result;
        if(!packet)
                return SYSMON_UNHANDLED;
        FILTER_SLOT* CurrentSlot = DProxyTable->PrevFilterSlot;
        for(int i=0;i<16;i++)
        {
                if(!CurrentSlot .DeleteCount)
                {
                        InterlockedIncrement(&CurrentSlot .CallCount);
                        packet->CurrentSlot = i;
                        Result = packet->PostFilterSlot(packet);
                        InterlockedDecrement(&CurrentSlot .CallCount);
                }
                switch(Result)
                {
                case SYSMON_HANDLED:
                        return SYSMON_HANDLED;
                case SYSMON_PASS:
                case SYSMON_PASS1:
                case SYSMON_FORBID:
                        return SYSMON_UNHANDLED;
                default:
                        break;
                }
        }
}

二、        驱动接口Interface
2.1 DeviceExtension接口
DeviceObject->DeviceExtension结构:
+00h        TAG=’TSFL’
+14h        FARPROC Interface
FARPROC Interface(intindex)

NTSTATUS Interface(int index,FARPROC* outfunc)
{//注意下面的函数都是自己实现的穿透函数
        If(!outfunc)
                Return STATUS_UNSUCCESSFUL;
    switch(index)
    {
    case 0:
*outfunc = SetEvaluateTime;
                Break;
    case 1:
*outfunc = AddDisablePrevFilter;
                Break;
    case 2:
*outfunc = SetPostFilter;
                Break;
    case 3:
*outfunc = ExecOriginFromPacket;
                Break;
    case 4:
*outfunc = AddPrevFilter;
                Break;
    case 5:
*outfunc = RemovePrevFilter;
                Break;
    case 6:
*outfunc = GetCurrentHookInfo;
                Break;
    case 7:
*outfunc = GetDProxyTable;
                Break;
default:
                *outfunc = NULL;
                Break;
}
Return STATUS_SUCESS;
}

2.2 SetEvaluateTime
Void __stdcall SetEvaluateTime(bool EvaluateTime)
{//设置计算过滤函数执行耗时
        g_EvaluateTime = EvaluateTime;
}

2.3 AddDisablePrevFilter
Void __stdcall AddDisablePrevFilter(ULONG Index,BOOLEAN Disable)
{//设置是否执行PrevFilter(同时也是PostFilter)
        If(Index < APINUMBER)
{
        If(DProxyTable)
                DProxyTable-> DisablePrevFilter = Disable;
}
}

2.4 SetPostFilter
Void __stdcall SetPostFilter(FilterPacket* Packet,FARPROC Filter,ULONG Tag)
{//设置PostFilter函数
        If(Packet)
{
        Packet->TagSlot = Tag;//用于修改参数或区分Filter
        Packet->PostFilterSlot = Filter;
        Packet->SlotCount++;
}
}

2.5 ExecOriginFromPacket
NTSTATUS __stdcall ExecOriginFromPacket(FilterPacket* Packet)
{//执行Nt*原始函数
        If(!Packet || !Packet->OriginFuncAddr)
                Return STATUS_UNSUCCESSFUL;
        _asm
        {
                Mov eax, Packet->ParamNumber
                Test eax,eax
                Jbe tag1
                Lea ecx,
                Test ecx,ecx
                Jl tag1
                Lea edx,Packet->Params//参数逐个压栈
Tag1:
                Mov eax,
                Push eax
                Sub ecx,1
                Sub edx,4
                Test ecx,ecx
                Jge tag2
Tag2:
                Call Packet->OriginFuncAddr
        }
}

2.6 AddPrevFilter
NTSTATUS __stdcall AddPrevFilter(ULONG Index,FARPROC Filter,ULONG Tag,ULONG PreferSlot,PULONG OutSlot)
{
        /*
                Index :Nt函数在全局表DProxyTable中的索引
                Filter:要设置的过滤函数
                Tag:标志过滤函数(可用于保存参数)
                PreferSlot:优先选用的函数槽
                OutSlot:实际选用的函数槽
*/
        if(!Filter || Index >= APINUMBER || PreferSlot >= 16)
                return STATUS_UNSUCCESSFUL;
        if(!DProxyTable || !DProxyTable->IsInitialized)
                return STATUS_UNSUCCESSFUL;
        if(DProxyTable->PrevFilterSlot.Filter)
        {//若函数槽已被占用
                for(int i=0;i<16;i++)
                {
                        if(!DProxyTable->PrevFilterSlot.Filter)
                        {
                                DProxyTable->PrevFilterSlot.Tag = Tag;
                                InterlockedExchange(&DProxyTable->PrevFilterSlot.Filter,Filter);
                                InterlockedIncrement(&DProxyTable->UsedSlotCount);
                                if(OutSlot)
                                        *OutSlot = i;
                                return STATUS_SUCCESS;
                        }
                }
        }
        else
        {
                DProxyTable->PrevFilterSlot.Tag = Tag;
                InterlockedExchange(&DProxyTable->PrevFilterSlot.Filter,Filter);
                InterlockedIncrement(&DProxyTable->UsedSlotCount);
                if(OutSlot)
                        *OutSlot = i;
                return STATUS_SUCCESS;
        }
        return STATUS_UNSUCCESSFUL;
}

2.7 RemovePrevFilter
void WaitStop(FILTER_SLOT* CurrentSlot)
{
        KeInitializeTimer(&CurrentSlot->Timer);
        Li.QuadPart = 1000000;
        while(CurrentSlot->CallCount)
        {
                KeSetTimer(&CurrentSlot->Timer,&Li,NULL);
                KeWaitForSingleObject(&CurrentSlot->Timer,Executive,KernelMode,FALSE,NULL);
        }
        KeCancelTimer(&CurrentSlot->Timer);
}

NTSTATUS __fastcall RemovePrevFilter(ULONG Index,FARPROC Filter)
{//从Index对应的函数过滤中查找删除Filter
        if(!Filter || Index >= APINUMBER)
                return STATUS_UNSUCCESSFUL;
        if(!DProxyTable || !DProxyTable->IsInitialized)
                return STATUS_UNSUCCESSFUL;
        for(int i=0;i<16;i++)
        {
                if(DProxyTable->PrevFilterSlot.Filter == Filter)
                {
                        LARGE_INTEGER Li;
                        FILTER_SLOT* CurrentSlot = &DProxyTable->PrevFilterSlot;
                        CurrentSlot->DeleteCount = FALSE;
                        InterlockedIncrement(&CurrentSlot->DeleteCount);
                        WaitStop(CurrentSlot);
                        InterlockedExchange(&CurrentSlot->Filter,NULL);
                        InterlockedDecrement(&DProxyTable->UsedSlotCount);
                        WaitStop(CurrentSlot);
                        InterlockedDecrement(&CurrentSlot->DeleteCount);
                        return STATUS_UNSUCCESSFUL;
                }
        }
        return STATUS_UNSUCCESSFUL;
}

2.8 GetCurrentHookInfo
NTSTATUS __stdcall GetCurrentHookInfo(PULONG pLastErrorCode,PULONG pserHookType,PULONG pOsVer,PULONG pHookErrorIndex)
{
        if(OsVer && !LastErrorCode && HookErrorIndex == -1)
        {
                if(pLastErrorCode)
                        *pLastErrorCode = 0;//获取系统buildnumber
                if(pserHookType)
                        *pserHookType = serHookType;
                if(pOsVer)
                        *pOsVer = OsVer;
                if(pHookErrorIndex)
                        *pHookErrorIndex = HookErrorIndex;
        }
        return STATUS_UNSUCCESSFUL;
}

LastErrorCode
0x01        ZwQuerySystemInformation获取失败
0x02        KeServiceDescriptorTable获取失败
0x04        KeAddSystemServiceTable获取失败
0x08        ShadowSSDT获取失败
0x10        MmUserProbeAddress获取失败
0x20        Int2E校验失败

InitState
0x01        ZwQuerySystemInformation获取成功
0x02        KeServiceDescriptorTable获取成功
0x04        ShadowSSDT获取成功
0x08        获取Inline Hook点成功

serHookType 对KiFastCallEntry做inline hook的类型
0.        Nonhook                        HOOKTYPE_NONE
1.        Inlinehook                        HOOKTYPE_INLINE
2.        SSDTHook                        HOOKTYPE_SSDT
3.        金山共存Inlinehook        HOOKTYPE_KSINLINE

OsVer
BuildNumber:
Win2000
2195                1
WinXp
2600                2
WinServer2003
3790                3
WinVista
6000                4
6001                5
6002                6
Win7
7600                7
7601                8
Win8
8102                9
8250                10
8400                11
8432                12
8441                12
8520                13
Win8.1
9200                14
9600                15
Win10
9841                16
9860                17
9926                18
10041        19
10049        20
?? 0

HookErrorIndex
        -1

IsBsod
        记录蓝屏

2.9 GetDProxyTable
Dproxy** GetDProxyTable()
{
        Return DProxyTable;
}

五、        基础库
5.1 获取注册表键值
NTSTATUS GetRegDataWithType(PWCHAR RegPath,PWCHAR KeyName,PVOID OutData,ULONG BufSize,PULONG OutType)
{
        NTSTATUS status;
        HANDLE KeyHandle = NULL;
        ULONG ResultLength = 0;
        OBJECT_ATTRIBUTES Oa;
        UNICODE_STRING URegPath,UKeyName;
        PVOID ValueInfo;
        const int BufSize = sizeof(PKEY_VALUE_PARTIAL_INFORMATION) + sizeof(WCHAR);
        if(!RegPath || !KeyName)
                return STATUS_INVALID_PARAMETER;
        InitializeObjectAttributes(&Oa,&URegPath,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);
        status = ZwOpenKey(&KeyHandle,KEY_EXECUTE,&Oa);
        ValueInfo = ExAllocatePool(NonPagedPool,BufSize);
        if(NT_SUCCESS(status) && ValueInfo)
        {
                RtlZeroMemory(ValueInfo,BufSize);
                RtlInitUnicodeString(&UKeyName,KeyName);
                status = ZwQueryValueKey(KeyHandle,&UKeyName,KeyValuePartialInformation,ValueInfo,BufSize,&ResultLength);
                if(NT_SUCCESS(status))
                {
                        PKEY_VALUE_PARTIAL_INFORMATION Info = (PKEY_VALUE_PARTIAL_INFORMATION)ValueInfo;
                        if(OutType)
                                *OutType = Info->Type;
                        if(OutData)
                                RtlCopyMemory(OutData,Info->Data,BufSize<Info->DataLength?BufSize:Info->DataLength);
                }
        }
        if(KeyHandle)
                ZwClose(KeyHandle);
        if(ValueInfo)
                ExFreePool(ValueInfo);
        return status;
}

NTSTATUS GetRegDataWithSize(PWCHAR RegPath,PWCHAR KeyName,PVOID OutData,ULONG BufSize,PULONG OutSize)
{
        NTSTATUS status;
        HANDLE KeyHandle = NULL;
        ULONG ResultLength = 0;
        OBJECT_ATTRIBUTES Oa;
        UNICODE_STRING URegPath,UKeyName;
        PVOID ValueInfo;
        const int BufSize = sizeof(PKEY_VALUE_PARTIAL_INFORMATION) + sizeof(WCHAR);
        if(!RegPath || !KeyName)
                return STATUS_INVALID_PARAMETER;
        InitializeObjectAttributes(&Oa,&URegPath,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);
        status = ZwOpenKey(&KeyHandle,KEY_EXECUTE,&Oa);
        ValueInfo = ExAllocatePool(NonPagedPool,BufSize);
        if(NT_SUCCESS(status) && ValueInfo)
        {
                RtlZeroMemory(ValueInfo,BufSize);
                RtlInitUnicodeString(&UKeyName,KeyName);
                status = ZwQueryValueKey(KeyHandle,&UKeyName,KeyValuePartialInformation,ValueInfo,BufSize,&ResultLength);
                if(NT_SUCCESS(status))
                {
                        PKEY_VALUE_PARTIAL_INFORMATION Info = (PKEY_VALUE_PARTIAL_INFORMATION)ValueInfo;
                        if(OutSize)
                                *OutSize = Info->DataLength;
                        if(OutData)
                                RtlCopyMemory(OutData,Info->Data,BufSize<Info->DataLength?BufSize:Info->DataLength);
                }
        }
        if(KeyHandle)
                ZwClose(KeyHandle);
        if(ValueInfo)
                ExFreePool(ValueInfo);
        return status;
}

NTSTATUS GetRegDataWithSizeAndType(PWCHAR RegPath,PWCHAR KeyName,PVOID OutData,ULONG BufSize,PULONG OutSize,PULONG OutType)
{
        NTSTATUS status;
        HANDLE KeyHandle = NULL;
        ULONG ResultLength = 0;
        OBJECT_ATTRIBUTES Oa;
        UNICODE_STRING URegPath,UKeyName;
        PVOID ValueInfo;
        const int BufSize = sizeof(PKEY_VALUE_PARTIAL_INFORMATION) + sizeof(WCHAR);
        if(!RegPath || !KeyName)
                return STATUS_INVALID_PARAMETER;
        InitializeObjectAttributes(&Oa,&URegPath,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);
        status = ZwOpenKey(&KeyHandle,KEY_EXECUTE,&Oa);
        ValueInfo = ExAllocatePool(NonPagedPool,BufSize);
        if(NT_SUCCESS(status) && ValueInfo)
        {
                RtlZeroMemory(ValueInfo,BufSize);
                RtlInitUnicodeString(&UKeyName,KeyName);
                status = ZwQueryValueKey(KeyHandle,&UKeyName,KeyValuePartialInformation,ValueInfo,BufSize,&ResultLength);
                if(NT_SUCCESS(status))
                {
                        PKEY_VALUE_PARTIAL_INFORMATION Info = (PKEY_VALUE_PARTIAL_INFORMATION)ValueInfo;
                        if(OutSize)
                                *OutSize = Info->DataLength;
                        if(OutType)
                                *OutType = Info->Type;
                        if(OutData)
                                RtlCopyMemory(OutData,Info->Data,BufSize<Info->DataLength?BufSize:Info->DataLength);
                }
        }
        if(KeyHandle)
                ZwClose(KeyHandle);
        if(ValueInfo)
                ExFreePool(ValueInfo);
        return status;
}

5.2 通过进程名获取进程ID
HANDLE GetProcessIdByName(PWCHAR ProcessName)
{//根据进程名获取进程ID
        HANDLE ProcessId = 0;
        NTSTATUS status = STATUS_SUCCESS;
        SIZE_T size = 512;
        UNICODE_STRING UProcessName;
        LPVOID Buffer;
        RtlInitUnicodeString(&UProcessName,ProcessName);
        while(true)
        {
                Buffer = ExAllocatePool(PagedPool,size);
                if(!Buffer)
                        return 0;
                status = ZwQuerySystemInformation(SystemProcessesAndThreadsInformation,Buffer,size,NULL);
                if(status != STATUS_INFO_LENGTH_MISMATCH)
                        break;
                ExFreePool(Buffer);
                size *= 2;
        }
        if(!NT_SUCCESS(Buffer))
                ExFreePool(Buffer);
        PSYSTEM_PROCESS_INFORMATION ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)Buffer;
        while(ProcessInfo->NextEntryOffset)
        {
                ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)((UCHAR*)ProcessInfo + ProcessInfo->NextEntryOffset);
                if(RtlEqualUnicodeString(&UProcessName,&ProcessInfo->ImageName,TRUE)
                        ProcessId = ProcessInfo->UniqueProcessId;
        }
        ExFreePool(Buffer);
        return ProcessId;
}




元始天尊 发表于 2015-10-2 15:21:07

六、        InlineHook KiFastCallEntry
①        重置蓝屏死机计数用于检测hook造成的蓝屏
②        获取SSDT/SSSDT/ hook点
③        分配跳转表ServiceMapTable
④        改写KiFastCallEntry使跳转表生效
⑤        Hook重要回调
⑥        开启日志记录
⑦        Hook KeUserModeCallback


6.1 获取SSDT/SSSDT/Hook点
ULONG InitState = 0;
ULONG LastErrorCode = 0;


UCHAR int2Ecode1 = {0x8B, 0xFC, 0x3B, 0x35, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x83};
UCHAR int2Ecode2 = {0x8B, 0xFC, 0xF6, 0x45, 0x72, 0x02, 0x75, 0x06, 0xF6, 0x45, 0x6C,
                                                0x01, 0x74, 0x0C, 0x3B, 0x35, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x83};

ULONG GetHookPoint1()
{//检测系统原始KiFastCallEntry
        *(ULONG*)(int2Ecode2 + 4) = MmUserProbeAddress;//构造cmp esi,dword ptr ds:
        if(!MmUserProbeAddress)
                return 0;
        ULONG ptr = GetKiSystemServiceAddr();//KiFastCallEntry总在KiSystemService之后
        if(ptr < NtosBase || ptr > NtosBase+NtosSize)
                return 0;
        for(int offset = 0;offset < 1024;offset++,ptr++)
        {
                /*
                        mov edi,esp
                        cmp esi,dword ptr ds:
                        jae ??
                */
                if(RtlCompareMemory(ptr,int2Ecode1,sizeof(int2Ecode1)) == sizeof(int2Ecode1))
                        return ptr;
        }
        return 0;
}

ULONG GetHookPoint2()
{//检测是否被金山inline hook过得KiFastCallEntry
        *(ULONG*)(int2Ecode2 + 16) = MmUserProbeAddress;//构造cmp esi,dword ptr ds:
        if(!MmUserProbeAddress)
                return 0;
        ULONG ptr = GetKiSystemServiceAddr();
        if(ptr < NtosBase || ptr > NtosBase+NtosSize)
                return 0;
        for(int offset = 0;offset < 1024;offset++,ptr++)
        {
                /*
                        mov edi,esp
                        test byte ptr,2
                        jne $1
                        test byte ptr,1
                        je ??
                        $1:
                        cmp esi,dword ptr ds:
                        jae ??
                */
                if(RtlCompareMemory(ptr,int2Ecode2,sizeof(int2Ecode2)) == sizeof(int2Ecode2))
                        return ptr;
        }
        return 0;
}

ULONG InitState = 0,LastErrorCode = 0,serHookType = 0;
ULONG NtosBase,NtosSize,SSDTBase,SSDTLimit,ShadowSSDTBase,ShadowSSDTLimit,Win32kBase,Win32kSize;
ULONG dwcsrssId;
ULONG BuildIndex;
PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable;
ULONG MmUserProbeAddress;

struct HOOKINFO
{
        ULONG InlinePoint;
        ULONG JmpBackPoint;
        UCHAR OriginCode;
};

HOOKINFO HookInfo1={0},HookInfo2={0};
/*
KiFastCallEntry+0xde:
        mov   ebx,dword ptr
        jmp   81f9e3e0
        nop                                                                                                =>        InlinePoint
        nop
        nop
        jmp   TsFltMgr+0x2300 (f8517300)
        jae   nt!KiSystemCallExit2+0x9f (8053e7ec)        =>        JmpBackPoint
        rep movs dword ptr es:,dword ptr
        call    ebx

        OriginCode;
        8bfc            mov   edi,esp
        3b35549a5580    cmp   esi,dword ptr
*/
NTSTATUS PrepareHook()
{
        RTL_PROCESS_MODULE_INFORMATION Win32kInfo,NtosInfo;
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        ULONG ReturnLength = 0;
        ULONG OutData;
        LPVOID Buffer = NULL;
        RtlZeroMemory(&Win32kInfo,sizeof(Win32kInfo));
        RtlZeroMemory(&NtosInfo,sizeof(NtosInfo));
        InitState = 0;
        LastErrorCode = 0;
        status = GetRegDataWithType(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\TsFltMgr",
                L"thm", &OutData, 4, 0)
        if(NT_SUCCESS(status) && OutData == 1)
                serHookType = HOOKTYPE_SSDT;
        ZwQuerySystemInformation(SystemModuleInformation,&ReturnLength,0,&ReturnLength);
        if(ReturnLength)
                Buffer = ExAllocatePool(PagedPool,ReturnLength);
        if(Buffer)
                status = ZwQuerySystemInformation(SystemModuleInformation,Buffer,ReturnLength,NULL);
        if(!NT_SUCCESS(status))
        {
                ExFreePool(Buffer);
                Buffer = NULL;
        }
        if(Buffer)
        {
                RtlCopyMemory(&NtosInfo,((PRTL_PROCESS_MODULES)Buffer)->Modules,sizeof(NtosInfo));
                ExFreePool(Buffer);
                NtosBase = NtosInfo.ImageBase;
                NtosSize = NtosInfo.ImageSize;
                ULONG FuncAddr = MiLocateExportName(NtosBase,"KeServiceDescriptorTable");
                if(FuncAddr && MmIsAddressValid(FuncAddr))
                {
                        PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable = (PKSERVICE_TABLE_DESCRIPTOR)FuncAddr;
                        SSDTBase = KeServiceDescriptorTable.Base;
                        SSDTLimit = KeServiceDescriptorTable.Limit;
                        InitState |= 2;
                        dwcsrssId = GetProcessIdByName(L"csrss.exe");
                        if(GetProcessInfoByFileName("WIN32K.SYS",&Win32kInfo))
                        {
                                Win32kBase = Win32kInfo.ImageBase;
                                Win32kSize = Win32kInfo.ImageSize;
                                if(NT_SUCCESS(GetShadowSSDTInfo()))
                                        InitState |= 4;
                        }
                       
                        UNICODE_STRING UMmUserProbeAddress;
                        RtlInitUnicodeString(&UMmUserProbeAddress,L"MmUserProbeAddress");
                        ULONG MmUserProbeAddress = MmGetSystemRoutineAddress(&UMmUserProbeAddress);
                        if(MmUserProbeAddress && MmIsAddressValid(MmUserProbeAddress))
                        {
                                HookInfo1.InlinePoint = GetHookPoint1();
                                if(HookInfo1.InlinePoint)
                                        HookInfo1.JmpBackPoint = HookInfo1.InlinePoint + 8;
                                else
                                {
                                        HookInfo2.InlinePoint = GetHookPoint2();
                                        if(HookInfo2.InlinePoint)
                                                HookInfo2.JmpBackPoint = HookInfo2.InlinePoint + 6;
                                }
                                if(HookInfo1.InlinePoint == 0 && HookInfo2.InlinePoint == 0)
                                {
                                        LastErrorCode |= 0x20;
                                        return status;
                                }
                                InitState |= 8;
                                MmUserProbeAddress = *(ULONG*)MmUserProbeAddress;
                                status = STATUS_SUCCESS;
                        }
                        else
                        {
                                LastErrorCode |= 0x10;
                        }
                }
                else
                {
                        LastErrorCode |= 2;
                }
        }
        else
        {
                LastErrorCode |= 1;
        }
        return status;
}

6.2 从KiSystemService获取KiFastCallEntry
struct IDTR
{
        USHORT IDTLimit;
        PKIDTENTRY IDTBase;
};
ULONG GetKiSystemServiceAddr()
{
        IDTR idt = {0};
        RTL_PROCESS_MODULE_INFORMATION NtosInfo,Win32kInfo;
        RtlZeroMemory(&NtosInfo,sizeof(NtosInfo));
        __sidt(&idt);
        if(idt.IDTBase)
        {
                KIDTENTRY int2e = idt.IDTBase;
                if(MmIsAddressValid(int2e))
                        return MAKEULONG(int2e.ExtendedOffset,int2e.Offset);
        }
        return 0;
}

6.3 获取SSSDT信息
NTSTATUS GetShadowSSDTInfo()
{
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        PVOID pt = MiLocateExportName(NtosBase, "KeAddSystemServiceTable");
        PMDL mdl = NULL;
        if(pt && !MmIsAddressValid(pt))
        {//页换出
                mdl = MmCreateMdl(NULL,pt,0x1000);
                if(mdl)
                {
                        MmProbeAndLockPages(mdl,KernelMode,IoReadAccess);
                }
        }
        if(!pt || !MmIsAddressValid(pt))
        {
                LastErrorCode |= 4;
                goto END;
        }

        switch(BuildIndex)
        {
        case WIN2000:
        case WINXP:
        case WINXPSP3:
        case WINVISTA:
        case WINVISTASP1:
        case WINVISTASP2:
        case WIN7:
        case WIN7SP1:
                for(int i=0;i<256;i++)
                {
                        if(MmIsAddressValid(pt) && *(USHORT*)pt == 0x888D)
                        {//8d88603f5580    lea   ecx,nt!KeServiceDescriptorTableShadow
                                PKSERVICE_TABLE_DESCRIPTOR Table = *(ULONG*)(pt+2);
                                ShadowSSDTBase = Table.Base;
                                ShadowSSDTLimit = Table.Limit;
                                status = STATUS_SUCCESS;
                        }
                }
                break;
        case WIN8_8102:
        case WIN8_8250:
        case WIN81_9200:
        case WIN81_9600:
                for(int i=0;i<256;i++)
                {
                        if(MmIsAddressValid(pt) && *(USHORT*)pt == 0xB983)
                        {//83b9603f558083cmp   dword ptr nt!KeServiceDescriptorTableShadow
                                PKSERVICE_TABLE_DESCRIPTOR Table = *(ULONG*)(pt+2);
                                if(KeServiceDescriptorTable == Table)
                                {
                                        ShadowSSDTBase = Table.Base;
                                        ShadowSSDTLimit = Table.Limit;
                                        status = STATUS_SUCCESS;
                                }
                        }
                }
                break;
        case WIN10_9841:
        case WIN10_9860:
        case WIN10_9926:
        case WIN10_10041:
        case WIN10_10049:
                for(int i=0;i<256;i++)
                {
                        if(MmIsAddressValid(pt) && *(USHORT*)pt == 0x3D83)
                        {//833d90d28d8100cmp   dword ptr ,0
                                PKSERVICE_TABLE_DESCRIPTOR Table = *(ULONG*)(pt+2) - 16;
                                if(KeServiceDescriptorTable == Table)
                                {
                                        ShadowSSDTBase = Table.Base;
                                        ShadowSSDTLimit = Table.Limit;
                                        status = STATUS_SUCCESS;
                                }
                        }
                }
                break;
        }
        if(!ShadowSSDTBase)
                LastErrorCode |= 8;
END:
        if(mdl)
        {
                MmUnlockPages(mdl);
                IoFreeMdl(mdl);
        }
}

6.4 初始化InlineHook KiFastCallEntry跳转表
BOOLEAN InitProxyTable()
{
        ULONG BuildIndex = GetBuildNumberAsIndex();
        for(int i = 0;i < APINUMBER;i++)
        {
                for(int j = 0;j < BUILDMAX;j++)
                {
                        if(SProxyTable.ServiceIndex == 0)
                                SProxyTable.ServiceIndex = 1023;//置为无效
                }
        }
        if(GetServiceIndex("ZwCreateKey") == -1)
        {//不能获取到服务号
                if(NtosBase)
                {
                        for(int i = 0;i < APINUMBER;i++)
                        {
                                if(SProxyTable.ServiceTableType == END)
                                        break;
                                else if(SProxyTable.ServiceTableType == SSDT)
                                {
                                        if(SProxyTable.ApiName)
                                        {
                                                UNICODE_STRING UApiName;
                                                ANSI_STRING AApiName;
                                                RtlInitUnicodeString(&UApiName,SProxyTable.ApiName);
                                                if(NT_SUCCESS(RtlUnicodeStringToAnsiString(&AApiName,&UApiName,TRUE)))
                                                {
                                                        GetServiceIndexFromNtos(AApiName.Buffer);
                                                        RtlFreeAnsiString(AApiName);
                                                }
                                        }                               
                                }
                        }
                }
        }
        else
        {//能获取到服务号   由于SProxyTable已存服务号,所以下面代码本身无效
                for(int i = 0;i < APINUMBER;i++)
                {
                        if(SProxyTable.ServiceTableType == END)
                                break;
                        if(SProxyTable.ServiceTableType == SSDT)
                        {
                                if(SProxyTable.ApiName)
                                {
                                        UNICODE_STRING UApiName;
                                        ANSI_STRING AApiName;
                                        RtlInitUnicodeString(&UApiName,SProxyTable.ApiName);
                                        if(NT_SUCCESS(RtlUnicodeStringToAnsiString(&AApiName,&UApiName,TRUE)))
                                        {
                                                ULONG Index = GetServiceIndexFromNtdll(AApiName.Buffer);
                                                if(Index != -1)
                                                        SProxyTable.ServiceIndex = Index;
                                                RtlFreeAnsiString(AApiName);
                                        }
                                }
                        }
                }
        }
        return TRUE;
}

int AllocHookTable()
{//已知系统情况下初始化代理表,直接使用ServiceIndex
        ULONG BuildIndex = GetBuildNumberAsIndex();
        DProxy* Proxydata = NULL;
        ULONG Count = 0;//未成功布置的代理函数个数
        if(BuildIndex >= 0 && BuildIndex < BUILDMAX)
        {
                InitProxyTable();
                for(int i=0;i<APINUMBER;i++)
                {
                        if(SProxyTable.ServiceTableType == END)
                                break;
                        if(SProxyTable.ServiceIndex != 1023)
                        {
                                if(SProxyTable.ApiName && SProxyTable.ProxyFunc && SProxyTable.IndexInTable < APINUMBER)
                                {
                                        Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
                                        if(Proxydata)
                                        {
                                                Proxydata->IsInitialized = FALSE;
                                                Proxydata->ApiName = SProxyTable.ApiName;
                                                Proxydata->TableIndex = SProxyTable.IndexInTable;
                                                Proxydata->ProxyFuncAddr = SProxyTable.ProxyFunc;
                                                Proxydata->ServiceIndex = -1;
                                                KeInitializeEvent(Proxydata->Lock,SynchronizationEvent,FALSE);
                                                DProxyTable.IndexInTable] = Proxydata;
                                                ULONG ServiceType = SProxyTable.ServiceTableType;
                                                ULONG ServiceIndex = SProxyTable.ServiceIndex;
                                                if(ServiceType >= 2 ||ServiceIndex== -1 || ServiceIndex >= 1024)
                                                {
                                                        Count++;
                                                }
                                                else
                                                {
                                                        ServiceMapTable = Proxydata;
                                                        Proxydata->ServiceTableType = ServiceType;
                                                        Proxydata->ServiceIndex = ServiceIndex;
                                                }
                                        }
                                }
                        }
                }
                return Count;
        }
        return APINUMBER;//返回未成功代理的个数
}

int AllocHookTableU()
{//未知系统情况下初始化代理表,临时从Ntos模块获取ServiceIndex
       
        if(!NtosBase)
                return 0;//返回成功布置代理的个数
        for(int i=0;i<APINUMBER;i++)
        {
                if(SProxyTable.ServiceTableType == END)
                        break;
                else if(SProxyTable.ServiceTableType == SSDT)
                {
                        if(SProxyTable.ApiName)
                        {
                                PUNICODE_STRING UApiName;
                                ANSI_STRING AApiName;
                                ULONG Index = -1;
                                RtlInitUnicodeString(&UApiName,SProxyTable.ApiName);
                                if(NT_SUCCESS(RtlUnicodeStringToAnsiString(&AApiName,&UApiName,TRUE)))
                                {
                                        Index = GetServiceIndexFromNtos(AApiName.Buffer);
                                        RtlFreeAnsiString(&AApiName);
                                }
                                if(Index != -1)
                                {
                                        if(SProxyTable.ApiName && SProxyTable.ProxyFunc && SProxyTable.IndexInTable < APINUMBER)
                                        {
                                                Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
                                                if(Proxydata)
                                                {
                                                        Proxydata->IsInitialized = FALSE;
                                                        Proxydata->ApiName = SProxyTable.ApiName;
                                                        Proxydata->TableIndex = SProxyTable.IndexInTable;
                                                        Proxydata->ProxyFuncAddr = SProxyTable.ProxyFunc;
                                                        Proxydata->ServiceIndex = -1;
                                                        KeInitializeEvent(Proxydata->Lock,SynchronizationEvent,FALSE);
                                                        DProxyTable.IndexInTable] = Proxydata;
                                                        ULONG ServiceType = SProxyTable.ServiceTableType;
                                                        ULONG ServiceIndex = SProxyTable.ServiceIndex;
                                                        if(ServiceType >= 2 ||ServiceIndex== -1 || ServiceIndex >= 1024)
                                                        {
                                                                Count++;
                                                                ServiceMapTable = Proxydata;
                                                                Proxydata->ServiceTableType = ServiceType;
                                                                Proxydata->ServiceIndex = ServiceIndex;
                                                        }
                                                }
                                        }
                                }
                        }
                }
        }
        return Count;
}

6.5 获取系统服务号的2种方式
ULONG GetServiceIndexFromNtdll(PCHAR ApiName)
{
        ULONG result = -1;
        RTL_PROCESS_MODULE_INFORMATION ProcessInfo;
        ULONG Index;
        RtlZeroMemory(&ProcessInfo,sizeof(ProcessInfo));
        if(GetProcessInfoByFileName("ntdll.dll",&ProcessInfo) && ProcessInfo.ImageBase && ApiName)
        {
                Index = MiLocateExportName(ProcessInfo.ImageBase,ApiName);
                if(Index)
                {
                        result = *(ULONG*)(Index+1);
                }
        }
        return result;
}

ULONG GetServiceIndexFromNtos(PCHAR ApiName)
{
        ULONG result = -1;
        ULONG Index = MiLocateExportName(ProcessInfo.ImageBase,ApiName);
        if(Index)
        {
                result = *(ULONG*)(Index+1);
        }
        if(Index & 0xFFFFC000)
        {
                result = -1;
        }
        return result;
}

6.6 InlineHook过程
NTSTATUS DoInlineHook()
{
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        ULONG MajorVersion = 0,MinorVersion = 0,BuildNumber = 0;
        PsGetVersion(&MajorVersion,&MinorVersion,&BuildNumber,NULL);
        if(serHookType == HOOKTYPE_SSDT || !(InitState & 8))//外部hook或没找到hook挂载点
                return status;
        if(HookInfo1.InlinePoint)
        {//如果为默认方式hook
                if(GetBuildNumberAsIndex() >= WINVISTA)
                        status = ModifyAndHook(HookInfo1.InlinePoint,InlineKiFastCallEntry1);
                else
                        status = ModifyAndHook(HookInfo1.InlinePoint,InlineKiFastCallEntry2);
                if(NT_SUCCESS(status))
                        serHookType = HOOKTYPE_INLINE;
        }
        else if(HookInfo2.InlinePoint)
        {//如果为金山共存方式hook
                if(GetBuildNumberAsIndex() >= WINVISTA)
                        status = ModifyAndHookK(HookInfo2.InlinePoint,InlineKiFastCallEntry3);
                else
                        status = ModifyAndHookK(HookInfo2.InlinePoint,InlineKiFastCallEntry4);
                if(NT_SUCCESS(status))
                        serHookType = HOOKTYPE_KSINLINE;
        }
        if(NT_SUCCESS(status))
        {
                for(int i=0;i<APINUMBER;i++)
                {
                        if(DProxyTable != 0 && (DProxyTable->ServiceTableType == SSDT || DProxyTable->ServiceTableType == SSSDT))
                                DProxyTable->IsInitialized = TRUE;
                }
        }
}

NTSTATUS DoInlineHookU()
{
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        ULONG MajorVersion = 0,MinorVersion = 0,BuildNumber = 0;
        PsGetVersion(&MajorVersion,&MinorVersion,&BuildNumber,NULL);
        if(serHookType == HOOKTYPE_SSDT || !(InitState & 8))//采用外部hook或没找到hook挂载点
                return status;
        if(HookInfo1.InlinePoint)
        {//如果为默认方式hook
                if(GetBuildNumberAsIndex() >= WINVISTA)
                        status = ModifyAndHook(HookInfo1.InlinePoint,InlineKiFastCallEntry1);
                else
                        status = ModifyAndHook(HookInfo1.InlinePoint,InlineKiFastCallEntry2);
                if(NT_SUCCESS(status))
                        serHookType = HOOKTYPE_INLINE;
        }
        else if(HookInfo2.InlinePoint)
        {//如果为金山共存方式hook
                if(GetBuildNumberAsIndex() >= WINVISTA)
                        status = ModifyAndHookK(HookInfo2.InlinePoint,InlineKiFastCallEntry3);
                else
                        status = ModifyAndHookK(HookInfo2.InlinePoint,InlineKiFastCallEntry4);
                if(NT_SUCCESS(status))
                        serHookType = HOOKTYPE_KSINLINE;
        }
        if(NT_SUCCESS(status))
        {
                for(int i=0;i<APINUMBER;i++)
                {
                        if(DProxyTable != 0 && (DProxyTable->ServiceTableType == SSDT || DProxyTable->ServiceTableType == SSSDT))
                                DProxyTable->IsInitialized = TRUE;
                }
        }
}

NTSTATUS ModifyAndHook(ULONG InlinePoint,FARPROC JmpToFunc)
{//HOOKTYPE_INLINE 更改KiFastCallEntry
        NTSTATUS status;
        PVOID MappedAddress = NULL;
        if(!InlinePoint || !InlineHookFunc)
                return STATUS_UNSUCCESSFUL;
        PMDL mdl = GetWritablePage(InlinePoint,16,&MappedAddress);
        /*
                改写                                                为
                mov edi,esp                                                nop
                cmp esp,dword ptr ds:[?]                nop
                                                                                nop
                                                                                jmp ?
        */
        if(!mdl)
                return STATUS_UNSUCCESSFUL;
        ULONG data = {InlinePoint,JmpToFunc,MappedAddress};
        status = MakeJmp(data,DoHook);
        MmUnlockPages(mdl);
        IoFreeMdl(mdl);
        return status;
}

NTSTATUS ModifyAndHookK(ULONG InlinePoint,FARPROC JmpToFunc)
{//HOOKTYPE_KSINLINE 更改KiFastCallEntry
        NTSTATUS status;
        PVOID MappedAddress = NULL;
        if(!InlinePoint || !InlineHookFunc)
                return STATUS_UNSUCCESSFUL;
        PMDL mdl = GetWritablePage(InlinePoint,16,&MappedAddress);
        if(!mdl)
                return STATUS_UNSUCCESSFUL;
        ULONG data = {InlinePoint,JmpToFunc,MappedAddress};
        status = MakeJmp(data,DoHookK);
        MmUnlockPages(mdl);
        IoFreeMdl(mdl);
        return status;
}

NTSTATUS DoHook(ULONG* data)
{//HOOKTYPE_INLINE
        ULONGLONG shellcode;
        if(!data)
                return STATUS_UNSUCCESSFUL;
        *(ULONGLONG*)(HookInfo1.OriginCode) = *(ULONGLONG*)data;//保存原始8字节
        *(ULONG*)((UCHAR*)&shellcode+4) = data - data - 8;//填写偏移 jmp offset
        *(ULONG*)((UCHAR*)&shellcode) = 0xE9909090;//写入新8字节
        /*
                构造
                nop
                nop
                nop
                jmp ????
        */
        InterlockedCompareExchange64((LONGLONG*)data,shellcode,*(LONGLONG*)data);
        return STATUS_SUCCESS;
}

NTSTATUS DoHookK(ULONG* data)
{//HOOKTYPE_KSINLINE
        ULONGLONG shellcode;
        if(!data)
                return STATUS_UNSUCCESSFUL;
        *(ULONGLONG*)(HookInfo1.OriginCode) = *(ULONGLONG*)data;//保存原始8字节
        *(USHORT*)((UCHAR*)&shellcode+6) = 0x0675;
        *(ULONG*)((UCHAR*)&shellcode+2) = data - data - 8;//填写偏移 jmp offset
        *(ULONG*)((UCHAR*)&shellcode) = 0xE990;//写入新8字节
        InterlockedCompareExchange64((LONGLONG*)data,shellcode,*(LONGLONG*)data);
        return STATUS_SUCCESS;
}

PMDL GetWritablePage(PVOID VirtualAddress,ULONG Length,PVOID* pMappedAddress)
{
        PMDL mdl = IoAllocateMdl(VirtualAddress,Length,FALSE,TRUE,NULL);
        if(mdl)
        {
                MmProbeAndLockPages(mdl,KernelMode,IoWriteAccess);
                PVOID NewAddr = MmGetSystemAddressForMdlSafe (Mdl, NormalPagePriority);
                if(!NewAddr)
                {
                        MmUnlockPages(mdl);
                        IoFreeMdl(mdl);
                        mdl = NULL;
                }
                if(NewAddr)
                        *pMappedAddress = NewAddr;
        }
        return mdl;
}

元始天尊 发表于 2015-10-2 15:22:49

6.7 构造InlineHook跳转后的执行语句
ULONG Filter(ULONG ServiceIndex,ULONG OriginFunc,ULONG Base)
{
        if(ServiceIndex >= 1024)
                return OriginFunc;
        ULONG TableType;
        if(Base == SSDTBase && ServiceIndex <= SSDTLimit)
        {
                TableType = SSDT;
        }
        else if(KeServiceDescriptorTable && KeServiceDescriptorTable->Base == Base && ServiceIndex <= SSDTLimit)
        {
                TableType = SSDT;
        }
        else if(Base == ShadowSSDTBase && ServiceIndex <= ShadowSSDTLimit)
        {
                TableType = SSSDT;
        }
        else
        {
                return OriginFunc;
        }
        if(ServiceMapTable)
        {
                ULONG NewAddr = ServiceMapTable->ProxyFuncAddr;
                if(NewAddr)
                {
                        ServiceMapTable->OriginFuncAddr = OriginFunc;
                        return NewAddr;
                }
        }
        return OriginFunc;
}

void __declspec(naked) InlineKiFastCallEntry1()
{
        /*HOOKTYPE_INLINE   >=VISTA
                输入
                eax=ServiceIndex
                edx=OriginFunc
                edi=SSDTBase
                输出
                edx=FuncAddr最终函数调用地址
        */
        _asm
        {
                pushf;
                pusha;
                push edi;
                push edx;
                push eax;
                call Filter;
                mov ,eax;//改栈中的edx
                popa;
                popf;
                mov edi,esp;
                cmp esi,MmUserProbeAddress;
                push dword ptr HookInfo1.JmpBackPoint;
                retn;//跳回JmpBackPoint
        }
}

void __declspec(naked) InlineKiFastCallEntry2()
{
        /*HOOKTYPE_INLINE   <VISTA
                输入
                eax=ServiceIndex
                edx=OriginFunc
                edi=SSDTBase
                输出
                ebx=FuncAddr最终函数调用地址
        */
        _asm
        {
                pushf;
                pusha;
                push edi;
                push edx;
                push eax;
                call Filter;
                mov ,eax;//改栈中的ebx
                popa;
                popf;
                mov edi,esp;
                cmp esi,MmUserProbeAddress;
                push dword ptr HookInfo1.JmpBackPoint;
                retn;
        }
}

void __declspec(naked) InlineKiFastCallEntry3()
{
        /*HOOKTYPE_KSINLINE   <VISTA
                输入
                eax=ServiceIndex
                edx=OriginFunc
                edi=SSDTBase
                输出
                edx=FuncAddr最终函数调用地址    (KiFastCallEntry后面mov ebx,edx)
        */
        _asm
        {
                pushf;
                pusha;
                push edi;
                push edx;
                push eax;
                call Filter;
                mov ,eax;//改栈中的edx
                popa;
                popf;
                mov edi,esp;
                test byte ptr ,2;
                push dword ptr HookInfo2.JmpBackPoint;
                retn;//跳回JmpBackPoint
        }
}

void __declspec(naked) InlineKiFastCallEntry4()
{
        /*HOOKTYPE_KSINLINE   <VISTA
                输入
                eax=ServiceIndex
                edx=OriginFunc
                edi=SSDTBase
                输出
                ebx=FuncAddr最终函数调用地址
        */
        _asm
        {
                pushf;
                pusha;
                push edi;
                push edx;
                push eax;
                call Filter;
                mov ,eax;//改栈中的edx
                popa;
                popf;
                mov edi,esp;
                test byte ptr ,2;
                push dword ptr HookInfo2.JmpBackPoint;
                retn;//跳回JmpBackPoint
        }
}

6.8 强制单核互斥执行指定Procedure
struct SpinData
{
        KSPIN_LOCK SpinLock;
        ULONG SpinRefCount;
}g_Spin = {0};
KDPC Dpc;

void DpcRoutine(PKDPC Dpc,PVOID DeferredContext,PVOID SystemArgument1,PVOID SystemArgument2)
{
        KIRQL OldIrql;
        SpinData* spin = (SpinData*)DeferredContext;zh
        _disable();
        OldIrql = KeRaiseIrqlToDpcLevel();
        InterlockedIncrement(spin->SpinRefCount);
        KeAcquireSpinLockAtDpcLevel(spin->SpinLock);
        KeReleaseSpinLockFromDpcLevel(spin->SpinLock);
        KeLowerIrql(OldIrql);
        _enable();
}

NTSTATUS MakeJmp(ULONG* data,FARPROC addr)
{
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        ULONG ulCurrentCpu = 0;
        KIRQL OldIrql,NewIrql;
        KAFFINITY CpuAffinity;
        if(!addr)
                return status;
        CpuAffinity = KeQueryActiveProcessors();
        for(int i = 0;i < 32;i++)
        {
                if((CpuAffinity >> i) & 1)
                        ulCurrentCpu++;
        }
        if(ulCurrentCpu == 1)//单核
        {
                _disable();
                OldIrql = KeRaiseIrqlToDpcLevel();
                status = addr(data);
                KeLowerIrql(OldIrql);
                _enable();
        }
        else//多核将除当前cpu以外的cpu用自旋锁锁住
        {
                SpinData* pSpinData = &g_Spin;
                ULONG ulNumberOfActiveCpu = 0;
                KeInitializeSpinLock(&g_Spin.SpinLock);
                for(int i = 0;i < 32;i++)
                {
                        KeInitializeDpc(&Dpc,DpcRoutine,&pSpinData);
                }
                pSpinData->SpinRefCount = 0;
                _disable();
                NewIrql = KeAcquireSpinLock(&g_Spin.SpinLock);
                ulCurrentCpu = KeGetCurrentProcessorNumber();
                for(int i = 0;i < 32;i++)
                {
                        if((CpuAffinity >> i) & 1)
                                ulNumberOfActiveCpu++;
                        if(i != ulCurrentCpu)
                        {
                                KeSetTargetProcessorDpc(Dpc,i);
                                KeSetImportanceDpc(Dpc,HighImportance);
                                KeInsertQueueDpc(Dpc,NULL,NULL);
                        }
                        KeInitializeDpc(&Dpc,DpcRoutine,&pSpinData);
                }
                //此时只有一个核在工作
                for(int i = 0;i < 16;i++)//尝试16次
                {
                        for(int count = 1000000;count > 0;count--);//延时
                        if(g_Spin.SpinRefCount == ulNumberOfActiveCpu - 1)//等待DpcRoutine全部执行到死锁
                        {
                                status = addr(data);
                                break;
                        }
                }
                KeReleaseSpinLock(&g_Spin.SpinLock,NewIrql);//恢复多核运行
                _enable();
        }
        return status;
}

6.9 进行SSDT hook
        在注册表Services\\TsFltMgr thm=1的情况下,或者Inline hook KiFastCallEntry失败的情况下,会进行SSDT表 hook
NTSTATUS BeginSSDTHook()
{
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        int result = -1;
        PVOID MappedAddress = NULL;
        PMDL mdl = NULL;
        if(serHookType == HOOKTYPE_INLINE || serHookType == HOOKTYPE_KSINLINE)//已成功inline hook
                return STATUS_UNSUCCESSFUL;
        serHookType = HOOKTYPE_SSDT;
        for(int i = 0;i <= APINUMBER;i++)
        {
                if(DProxyTable && DProxyTable->ServiceIndex != -1 && !DProxyTable->IsInitialized)
                {
                        if(DProxyTable->ServiceTableType == SSDT)
                        {
                                int index = DProxyTable->ServiceIndex;
                                if(index != 1023 && DProxyTable->ProxyFunc && SSDTBase)
                                {
                                        PVOID MappedAddress = NULL;
                                        PMDL mdl = GetWritablePage(SSDTBase,4*SSDTLimit,&MappedAddress);
                                        if(mdl)
                                        {
                                                DProxyTable->OriginFuncAddr = ((ULONG*)SSDTBase);
                                                ((ULONG*)MappedAddress) = DProxyTable->ProxyFunc;
                                                MmUnlockPages(mdl);
                                                IoFreeMdl(mdl);
                                                result = index;
                                        }
                                }
                        }
                        else if(DProxyTable->ServiceTableType == SSSDT)
                        {
                                int index = DProxyTable->ServiceIndex;
                                if(index != 1023 && DProxyTable->ProxyFunc && ShadowSSDTBase)
                                {
                                        HANDLE CurProcessId = PsGetCurrentProcessId();
                                        HANDLE SmssProcessId = GetProcessIdByName(L"smss.exe");
                                        if(!dwcsrssId)//如果没有获取到csrss.exe的id
                                        {
                                                if(CurProcessId == SmssProcessId)//使用smss.exe的SSSDT
                                                {
                                                        mdl = GetWritablePage(ShadowSSDTBase,4*ShadowSSDTLimit,&MappedAddress);
                                                        if(mdl)
                                                        {
                                                                DProxyTable->OriginFuncAddr = ((ULONG*)ShadowSSDTBase);
                                                                ((ULONG*)MappedAddress) = DProxyTable->ProxyFunc;
                                                                MmUnlockPages(mdl);
                                                                IoFreeMdl(mdl);
                                                                result = index;
                                                        }
                                                }
                                        }
                                        else
                                        {//附加到csrss.exe
                                                PVOID attachobj = AttachDriverToProcess(dwcsrssId);
                                                if(attachobj)
                                                {
                                                        mdl = GetWritablePage(ShadowSSDTBase,4*ShadowSSDTLimit,&MappedAddress);
                                                        if(mdl)
                                                        {
                                                                DProxyTable->OriginFuncAddr = ((ULONG*)ShadowSSDTBase);
                                                                ((ULONG*)MappedAddress) = DProxyTable->ProxyFunc;
                                                                MmUnlockPages(mdl);
                                                                IoFreeMdl(mdl);
                                                                result = index;
                                                        }
                                                        DetachDriverFromProcess(attachobj);
                                                }
                                        }
                                }       
                        }
                        if(result != -1)
                                DProxyTable->IsInitialized = TRUE;
                }
        }
        return STATUS_SUCCESS;
}

struct AttachData
{
        KAPC_STATE ApcState;
        PVOID Process;
};

PVOID AttachDriverToProcess(HANDLE ProcessId)
{
        PVOID Process = NULL;
        AttachData* Buffer = NULL;
        if(ProcessId == PsGetCurrentProcessId())
                return 0xEEEEDDDD;//自身标识
        if(ProcessId && NT_SUCCESS(PsLookupProcessByProcessId(ProcessId,&Process)))
        {
                Buffer = (AttachData*)ExAllocatePool(PagedPool,sizeof(AttachData));
                if(!Buffer)
                {
                        ObDereferenceObject(Process);
                        return NULL;
                }
                Buffer->Process = Process;
                KeStackAttachProcess(Process,&Buffer->ApcState)
        }
}

NTSTATUS DetachDriverFromProcess(PVOID Buffer)
{
        if(Buffer && (ULONG)Buffer != 0xEEEEDDDD)
        {
                AttachData* data = (AttachData*)Buffer;
                KeUnstackDetachProcess(&data->ApcState);
                ObDereferenceObject(data->Process);
                ExFreePool(Buffer);
        }
}

6.10 对重要回调(进程回调、线程回调、映像加载回调)的挂钩
/*
        Sproxy Index:
        普通api使用index 0-0x33 0x37-0x48 0x4A-0x69
        52    CreateNotifyRoutine
        53    ThreadNofify
        54    ImageNotify
        73    CreateNotifyRoutine2
*/
enum
{
        INDEX_KECALLBACK = 51,
        INDEX_PROCESS = 52,
        INDEX_THREAD = 53,
        INDEX_IMAGE = 54,
        INDEX_PROCESSEX = 73,
};

NTSTATUS HookImportantNotify()
{
        if(!DProxyTable)
        {
                DProxy* Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
                if(Proxydata)
                {
                        Proxydata->IsInitialized = FALSE;
                        Proxydata->ApiName = "ProcessNotify";
                        Proxydata->TableIndex = INDEX_PROCESS;
                        Proxydata->ProxyFuncAddr = CreateNotifyRoutine1;
                        Proxydata->ServiceIndex = -1;
                        KeInitializeEvent(&Proxydata->Lock,SynchronizationEvent,FALSE);
                        DProxyTable = Proxydata;
                }
        }
        if(DProxyTable && !DProxyTable->IsInitialized)
        {
                DProxyTable->ServiceTableType = CALLBACK;
                if(NT_SUCCESS(PsSetCreateProcessNotifyRoutine(CreateProcessNotify,FALSE)))
                        DProxyTable->IsInitialized = TRUE;
        }
        if(!DProxyTable)
        {
                DProxy* Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
                if(Proxydata)
                {
                        Proxydata->IsInitialized = FALSE;
                        Proxydata->ApiName = "ProcessNotifyEx";
                        Proxydata->TableIndex = INDEX_PROCESSEX;
                        Proxydata->ProxyFuncAddr = CreateNotifyRoutine1Ex;
                        Proxydata->ServiceIndex = -1;
                        KeInitializeEvent(&Proxydata->Lock,SynchronizationEvent,FALSE);
                        DProxyTable = Proxydata;
                }
        }
        if(DProxyTable && !DProxyTable->IsInitialized)
        {
                DProxyTable->ServiceTableType = CALLBACK;
                if(NT_SUCCESS(PsSetCreateProcessNotifyRoutineEx(CreateProcessNotifyEx,FALSE)))
                        DProxyTable->IsInitialized = TRUE;
        }
        if(!DProxyTable)
        {
                DProxy* Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
                if(Proxydata)
                {
                        Proxydata->IsInitialized = FALSE;
                        Proxydata->ApiName = "ThreadNotify";
                        Proxydata->TableIndex = INDEX_THREAD;
                        Proxydata->ProxyFuncAddr = CreateThreadNotify;
                        Proxydata->ServiceIndex = -1;
                        KeInitializeEvent(&Proxydata->Lock,SynchronizationEvent,FALSE);
                        DProxyTable = Proxydata;
                }
        }
        if(DProxyTable && !DProxyTable->IsInitialized)
        {
                DProxyTable->ServiceTableType = CALLBACK;
                if(NT_SUCCESS(PsSetCreateThreadNotifyRoutine(CreateThreadNotify,FALSE)))
                        DProxyTable->IsInitialized = TRUE;
        }
        if(!DProxyTable)
        {
                DProxy* Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
                if(Proxydata)
                {
                        Proxydata->IsInitialized = FALSE;
                        Proxydata->ApiName = "ImageNotify";
                        Proxydata->TableIndex = INDEX_IMAGE;
                        Proxydata->ProxyFuncAddr = LoadImageNotify;
                        Proxydata->ServiceIndex = -1;
                        KeInitializeEvent(&Proxydata->Lock,SynchronizationEvent,FALSE);
                        DProxyTable = Proxydata;
                }
        }
        if(DProxyTable && !DProxyTable->IsInitialized)
        {
                DProxyTable->ServiceTableType = CALLBACK;
                if(NT_SUCCESS(PsSetLoadImageNotifyRoutine(LoadImageNotify,FALSE)))
                        DProxyTable->IsInitialized = TRUE;
        }
}

6.11 Hook KeUserModeCallback
NTSTATUS HookKeUserModeCallback()
{
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        if(!Win32kBase)
                return status;
        OBJECT_ATTRIBUTES Oa;
        IO_STATUS_BLOCK IoStatusBlock;
        HANDLE SectionHandle = NULL;
        ULONG ViewSize = 0;
        HANDLE FileHandle = NULL;
        PVOID BaseAddress = 0x5000000;
        UNICODE_STRING UKeUserModeCallback;
        if(!DProxyTable)
        {
                DProxy* Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
                if(Proxydata)
                {
                        Proxydata->IsInitialized = FALSE;
                        Proxydata->ApiName = "ImageNotify";
                        Proxydata->TableIndex = INDEX_KECALLBACK;
                        Proxydata->ProxyFuncAddr = ProxyKeUserModeCallback;
                        Proxydata->ServiceIndex = -1;
                        KeInitializeEvent(&Proxydata->Lock,SynchronizationEvent,FALSE);
                        DProxyTable = Proxydata;
                }
        }
        RtlInitUnicodeString(&UKeUserModeCallback,L"\\SystemRoot\\System32\\Win32k.sys");
        InitializeObjectAttributes(&Oa,L"KeUserModeCallback",OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,NULL,NULL);
        status = ZwOpenFile(&FileHandle,GENERIC_READ,&Oa,&IoStatusBlock,FILE_SHARE_READ,FILE_SYNCHRONOUS_IO_NONALERT);
        if(NT_SUCCESS(status))
        {
                Oa.ObjectName = NULL;
                status = ZwCreateSection(&SectionHandle,SECTION_MAP_EXECUTE,&Oa,NULL,PAGE_WRITECOPY,SEC_IMAGE);
                if(NT_SUCCESS(status))
                {
                        status = ZwMapViewOfSection(&SectionHandle,NtCurrentProcess(),&BaseAddress,0,0,NULL,&ViewSize,ViewUnmap,0,PAGE_EXECUTE);
                        if(!NT_SUCCESS(status))
                        {
                                BaseAddress = NULL;
                                ZwMapViewOfSection(&SectionHandle,NtCurrentProcess(),&BaseAddress,0,0,NULL,&ViewSize,ViewUnmap,0,PAGE_EXECUTE);
                        }
                }
        }
        if(BaseAddress)
        {
                if(!DProxyTable->IsInitialized)
                {
                        ULONG IatOffset = GetProcOffsetFromIat(BaseAddress);
                        DProxyTable->OriginFuncAddr = ExchangeMem(IatOffset,Win32kBase,ProxyKeUserModeCallback);
                        if(DProxyTable->OriginFuncAddr)
                        {
                                DProxyTable->IsInitialized;
                                status = STATUS_SUCCESS;
                        }
                }
                ZwUnmapViewOfSection(NtCurrentProcess(),BaseAddress);
        }
        return status;
}

6.12 交换内存
ULONG ExchangeMem(ULONG Offset,ULONG BaseAddress,ULONG NewValue)
{//替换基址BaseAddress 偏移Offset 处的ULONG数据,返回原始数据
        HANDLE CurProcessId = PsGetCurrentProcessId();
        HANDLE SmssProcessId = GetProcessIdByName(L"smss.exe");
        ULONG OriginValue = 0;
        PMDL mdl = NULL;
        if(!dwcsrssId)//如果没有获取到csrss.exe的id
        {
                if(CurProcessId == SmssProcessId)//使用smss.exe的SSSDT
                {
                        mdl = GetWritablePage(BaseAddress+Offset,16,&MappedAddress);
                        if(mdl)
                        {
                                OriginValue = InterlockedExchange(MappedAddress,NewValue);
                                MmUnlockPages(mdl);
                                IoFreeMdl(mdl);
                        }
                }
        }
        else
        {//附加到csrss.exe
                PVOID attachobj = AttachDriverToProcess(dwcsrssId);
                if(attachobj)
                {
                        mdl = GetWritablePage(BaseAddress+Offset,4,&MappedAddress);
                        if(mdl)
                        {
                                OriginValue = InterlockedExchange(MappedAddress,NewValue);
                                MmUnlockPages(mdl);
                                IoFreeMdl(mdl);
                        }
                        DetachDriverFromProcess(attachobj);
                }
        }
        return OriginValue;
}

6.13 获取函数Iat偏移
ULONG GetProcOffsetFromIat(PVOID ImageBase,PCHAR ModuleName,PCHAR ApiName)
{//ImageBase当前进程映像基址ModuleName导入模块映像基址ApiName导入函数名
        ANSI_STRING AApiName;
        UNICODE_STRING UApiname;
        PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
        ULONG ObjProcAddr;
        ULONG Offset = 0;
        PCHAR ImportedName;
        PIMAGE_THUNK_DATA FunctionNameList;
        RtlInitAnsiString(&AApiName,ApiName);
        if(!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UApiname,&AApiName,TRUE)))
                return 0;
        ObjProcAddr = MmGetSystemRoutineAddress(&UApiname);
        RtlFreeUnicodeString(&UApiname);
        ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(ImageBase,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT);
        if(!ImportModuleDirectory)
                return 0;
        for (;(ImportModuleDirectory->Name != 0) && (ImportModuleDirectory->FirstThunk != 0);ImportModuleDirectory++)
        {
                ImportedName = (PCHAR)ImageBase + ImportModuleDirectory->Name;
                if(!stricmp(ModuleName,ImportedName))
                {
                        FunctionNameList = (PIMAGE_THUNK_DATA)((UCHAR*)ImageBase+ImportModuleDirectory->FirstThunk);
                        while(*FunctionNameList != 0)
                        {
                                if((*FunctionNameList) & 0x80000000)
                                {
                                        if(FunctionNameList->u1.Function == ObjProcAddr)
                                                return (UCHAR*)FunctionNameList - (UCHAR*)ImageBase;
                                }
                                else
                                {
                                        IMAGE_IMPORT_BY_NAME *pe_name = (IMAGE_IMPORT_BY_NAME*)((PCHAR)ImageBase + *FunctionNameList);
                                        if(pe_name->Name == 'K' && !stricmp(pe_name->Name,"KeUserModeCallback"))
                                                return (UCHAR*)FunctionNameList - (UCHAR*)ImageBase;
                                }
                                FunctionNameList++;
                        }
                }
        }
        return 0;
}

6.14 另一种方式获取ShadowSSDT信息
当常规方式获取SSSDT失败时,会临时设置ZwSetSystemInformation的过滤函数捕获系统设置服务表(SYSTEM_INFORMATION_CLASS =SystemExtendServiceTableInformation),
void TryAnotherWayToGetShadowSSDT()
{
        AddPrevFilter(EZwSetSystemInformation,ZwSetSystemInformationFilter1,0,0,NULL);
}

ULONG OldKeAddSystemServiceTable;

ULONG __stdcall ZwSetSystemInformationFilter1(FilterPacket* Packet)
{//改EAT以获取SSSDT
        if(!ShadowSSDTBase && Packet->Params == SystemExtendServiceTableInformation && !OldKeAddSystemServiceTable)
        {
                OldKeAddSystemServiceTable = ExchangeEat(NtosBase,NewKeAddSystemServiceTable);
                if(OldKeAddSystemServiceTable)
                {
                        Packet->TagSlot = 0xABCDEEEE;//用于标记
                        Packet->PostFilterSlot = ZwSetSystemInformationFilter2;
                        Packet->UsedSlotCount++;
                }
        }
        return SYSMON_PASSTONEXT;
}

ULONG __stdcall ZwSetSystemInformationFilter2(FilterPacket* Packet)
{//获取之后恢复EAT
        if(Packet->TagSlot == 0xABCDEEEE)//检查标记
        {
                if(serHookType != 1 && serHookType != 3)//是否SSDT型Hook
                {
                        BeginSSDTHook();
                }
        }
        return SYSMON_PASSTONEXT;
}

BOOLEAN __stdcall KeAddSystemServiceTable(PULONG_PTR Base,PULONG Count,ULONG Limit,PUCHAR Number,ULONG Index)
{//获取SSSDT
        RTL_PROCESS_MODULE_INFORMATION ProcessInfo;
        RtlZeroMemory(&ProcessInfo,sizeof(ProcessInfo));
        if(!ShadowSSDTBase && GetProcessInfoByFileName("win32k.sys",&ProcessInfo) &&
                Base >= ProcessInfo.ImageBase && Base <= ProcessInfo.ImageBase+ProcessInfo.ImageSize)
        {
                Win32kBase = ProcessInfo.ImageBase;
                Win32kSize = ProcessInfo.ImageSize;
                ShadowSSDTBase = Base;
                ShadowSSDTLimit = Limit;
                ExchangeEat(NtosBase,OldKeAddSystemServiceTable);
        }
        returnOldKeAddSystemServiceTable(Base,Count,Limit,Number,Index);
}

ULONG ExchangeEat(ULONG ImageBase,ULONG NewFunc)
{
        PVOID Address = MiLocateExportName(ImageBase,"KeAddSystemServiceTable");
        if(Address)
        {
                return ExchangeMem(0,Address,NewFunc);
        }
        return 0;
}

Prodigal 发表于 2017-9-10 22:42:17

不知道能不能用

UnMovedMover 发表于 2018-1-29 11:19:48

嗨 您好 下载了您的压缩包 但是需要您的QQ号码:(

ljh951028 发表于 2018-8-10 16:10:28

想学习一下驱动的开发,下载了您的文档。请问你的qq是多少啊

clteng5316 发表于 2019-1-14 15:29:54

想学习一下驱动的开发,下载了您的文档。请问你的qq是多少啊
页: [1]
查看完整版本: TsSysKit深度分析