腾讯管家攻防驱动分析-Tssyskit


layout: wiki
title: 腾讯管家攻防驱动分析-Tssyskit
categories: WindowsDriver
description: 腾讯管家攻防驱动分析-Tssyskit
keywords:
url: https://lichao890427.github.io/ https://github.com/lichao890427/


Tssyskit分析

  该驱动为qq管家穿透驱动,提供文件、注册表穿透,和解锁文件、驱动加载、句柄、进程等操作,导出接口给其他驱动使用,设备名\Device\TSSysKit,符号名\DosDevices\TSSysKit。加密手段:Rabbit算法、MD5算法。

一、驱动入口DriverEntry

  • 获取系统版本_1
  • 获取EPROCESS的ObjectTypeIndex (win7以前 0x1C win8 0x1F Win8.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

int CheckIopLoadDriver()
{
    unsigned int IopLoadDriverNext; // esi@2
    PRTL_PROCESS_MODULES modules; // ebx@5
    int IopLoadDriver; // esi@8
    PVOID Base; // eax@9
    PVOID Callers[4]; // [sp+8h] [bp-18h]@1
    BOOL ret; // [sp+18h] [bp-8h]@1
    ULONG SystemInformationLength; // [sp+1Ch] [bp-4h]@1

    Callers[0] = 0;
    Callers[1] = 0;
    Callers[2] = 0;
    Callers[3] = 0;
    ret = 0;
    SystemInformationLength = 0;
    ::IopLoadDriver = 0;
    if ( RtlWalkFrameChain(Callers, 4u, 0) == 4 ) 
        // [0]=RtlWalkFrameChain next
        // [1]=DriverEntry
        // [2]=IopLoadDriver
        // [3]=IopInitializeSystemDrivers
    {
        IopLoadDriverNext = Callers[3];
        if ( MmIsAddressValid(Callers[3]) )
        {
            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[0].ImageBase;
                                if ( IopLoadDriver >= Base && IopLoadDriver <= (Base + modules->Modules[0].ImageSize) )
                                {                               // 检测IopLoadDriver是否在ntos中
                                    ::IopLoadDriver = IopLoadDriver;
                                    ret = 1;
                                }
                            }
                        }
                    }
                    ExFreePool(modules);
                }
            }
        }
    }
    return ret;
}

1.2 执行删除任务 DoDeleteJob

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

ShutdownRecord.ini格式:
[DELETEFILECOUNT]
Count=3
[DELETEFILELIST]
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)
{//重置/保存注册表对象ObjectInitialzer例程,用于ObOpenObjectByName执行前后
    FARPROC* Initailier = NULL;
    if(Type <0 || Type >= ECmMax)
    {
        if(!RegObjectInitialzer[Type] || !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[Type])
        {
            *OutFunc = *Initailier;
            *Initailier = RegObjectInitialzer[Type];
            return TRUE;
        }
    }
    else
    {//Set
        if(*OutFunc != *Initailier)
        {
            *Initailier = *OutFunc;
            return TRUE;
        }
    }
    return FALSE;
}

2.4 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;
}

2.5 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;
}

2.6 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[VersionIndex][ECmQueryValueKey].InitFlag && CmMatchData[VersionIndex][ECmQueryValueKey].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[VersionIndex][ECmQueryValueKey].FuncAddr(KeyBody->KeyControlBlock,LocalValueName,
                    KeyValueInformationClass,KeyValueInformation,Length,ResultLength);
                break;
            case WINVISTA:
            case WIN7:
            case WIN7_1:
                CmMatchData[VersionIndex][ECmQueryValueKey].FuncAddr(KeyBody,KeyValueInformationClass,KeyValueInformation
                    Length,ResultLength,LocalValueName);
                break;
            case WIN8:
                CmMatchData[VersionIndex][ECmQueryValueKey].FuncAddr(KeyBody,LocalValueName,KeyValueInformationClass,
                    KeyValueInformation,Length,ResultLength);
                break;
            case WIN8_1:
            case WIN10:
                CmMatchData[VersionIndex][ECmQueryValueKey].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;
}

2.7 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[VersionIndex][ECmQueryValueKey].InitFlag && CmMatchData[VersionIndex][ECmQueryValueKey].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[VersionIndex][ECmSetValueKey].FuncAddr(KeyBody->KeyControlBlock,&LocalValueName,Type,Data,DataSize);
                    break;
                case WINVISTA:
                case WIN7:
                case WIN7_1:
                case WIN8:
                case WIN8_1:
                    CmMatchData[VersionIndex][ECmSetValueKey].FuncAddr(KeyBody,&LocalValueName,Type,Data,DataSize,0,
                        HandleInformation.HandleAttributes & 4);
                    break;
                case WIN10:
                    CmMatchData[VersionIndex][ECmSetValueKey].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;
}

2.8 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[VersionIndex][ECmDeleteValueKey].InitFlag && CmMatchData[VersionIndex][ECmDeleteValueKey].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[VersionIndex][ECmDeleteValueKey].FuncAddr(KeyBody->KeyControlBlock,LocalValueName);
                    break;
                case WINVISTA:
                case WIN7:
                case WIN7_1:
                    CmMatchData[VersionIndex][ECmDeleteValueKey].FuncAddr(KeyBody,KeyHandle,HandleInformation.HandleAttributes & 4,LocalValueName);
                    break;
                case WIN8:
                    CmMatchData[VersionIndex][ECmDeleteValueKey].FuncAddr(KeyBody,LocalValueName,KeyHandle,HandleInformation.HandleAttributes & 4);
                    break;
                case WIN8_1:
                case WIN10:
                    CmMatchData[VersionIndex][ECmDeleteValueKey].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;
}

2.9 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[VersionIndex][ECmDeleteKey].InitFlag && CmMatchData[VersionIndex][ECmDeleteKey].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[VersionIndex][ECmDeleteKey].FuncAddr(KeyBody);
                break;
            default:
                status = STATUS_NOT_SUPPORTED;
                break;
            }
        }
    }
    else
    {
        status = STATUS_NOT_SUPPORTED;
    }
    if(KeyBody)
        ObDereferenceObject(KeyBody);
    return status;
}

2.10 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_OBJECT  TopDeviceObjectHint;
} 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_CONTEXT  DriverCreateContext;
} 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_CONTEXT  DriverCreateContext;
} OPEN_PACKET_WIN8, *POPEN_PACKET_WIN8;
#pragma pack(pop)

三、控制码

  IRP_MJ_DEVICE_CONTROL => 调用DeviceIoControl派遣(DeviceIoControlDispatch),能力:

  • 解锁文件
  • 驱动加载
  • 句柄操作
  • 进程打开、结束
  • 注册表穿透操作

3.1 TSSysKit x86 IoControlCode对应表

0x221C00
    解锁文件
    buffer=     sizeof=0x804
    +00 NTSTATUS status     out
    +04 WCHAR FileName[1024]    in
0x221C04
0x221C08
0x221C0C
0x221C10
0x221C14
    尚未实现
0x222004
    普通结束进程
    buffer=     sizeof=4
    +00 DWORD ProcessId
0x222008
    穿透NtDeleteKey
    buffer=     sizeof=8
    +00 NTSTATUS status     out
    +04 HANDLE  KeyHandle   in
0x22200C
    穿透NtDeleteValueKey        成员含义见NtDeleteValueKey
    buffer=     sizeof=0xC
    +00 NTSTATUS status     out
    +04 HANDLE  KeyHandle   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 HANDLE  KeyHandle   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 HANDLE  KeyHandle   out
    +04 NTSTATUS status     out     注意status不是第一成员了!!
    +08 ACCESS_MASK DesiredAccess   in
    +0C POBJECT_ATTRIBUTES ObjectAttributes in
0x222410
    同0x222008  NtDeleteKey
    buffer=     sizeof=8
    +00 NTSTATUS status
    +04 HANDLE KeyHandle
0x222414
    穿透删除注册表项NtDeleteValueKey    成员含义见NtDeleteValueKey
    buffer=     sizeof=0xC
    +00 NTSTATUS status     out 
    +04 HANDLE  KeyHandle   in
    +08 PUNICODE_STRING ValueName   in
0x222418
    穿透设置注册表项NtSetValueKeyEx     成员含义见NtSetValueKey
    buffer=     sizeof=0x1C
    +00 NTSTATUS status     out 
    +04 HANDLE  KeyHandle   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 ResultLength  out
    +04 NTSTATUS status     out     注意status不是第一成员了!!
    +08 HANDLE  KeyHandle   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 ResultLength  out
    +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=     sizeof=0x1C
    +00 NTSTATUS status     out
    +04 ULONG ResultLength  out
    +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[260] 驱动文件路径
    +208    DWORD Type  驱动注册表Type项
    +20C    DWORD Start 驱动注册表项Start类型
    +210    DWORD flag  (决定是否设置注册表Tag和Group信息)
    +214    ???
    +468    DWORD Tag 驱动注册表Tag项
    +46C    WCHAR DisplayName[300] 驱动注册表项DisplayName
    +6C4    WCHAR ServiceName[300] 驱动服务名
0x222430
    获取操作系统版本
    buffer=RTL_OSVERSIONINFOEXW     sizeof=0x11C
0x222800
0x222804
    2个初始化TSSysKit的通道
0x224008
    +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 PIO_APC_ROUTINE ApcRoutine  in
    +10 PVOID 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 PIO_APC_ROUTINE ApcRoutine  in
    +10 PVOID 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[260]; //驱动文件路径
    DWORD Type;  //驱动注册表Type项
    DWORD Start; //驱动注册表项Start类型
    WCHAR Group[300];//驱动注册表Group名
    DWORD Tag; //驱动注册表Tag项
    WCHAR DisplayName[300]; //驱动注册表项DisplayName
    WCHAR ServiceName[300]; //驱动服务名
};

#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);
}

3.2 TSSysKit x64 IoControlCode对应表

0x22200C
    穿透创建文件
    Buffer= sizeof=0x50 具体参数含义见NtCreateFile
    +00 NTSTATUS status     out
    +08 PHANDLE FileHandle 
    +10 ACCESS_MASK DesiredAccess 
    +18 POBJECT_ATTRIBUTES ObjectAttributes 
    +20 PIO_STATUS_BLOCK IoStatusBloc
    +28 PLARGE_INTEGER AllocationSize 
    +30 ULONG FileAttributes
    +34 ULONG ShareAccess
    +38 ULONG CreateDisposition
    +3C ULONG CreateOptions
    +40 PVOID EaBuffer 
    +48 ULONG EaLength 
0x222010
    穿透打开文件
    Buffer= sizeof=0x30     具体参数含义见NtOpenFile
    +00 NTSTATUS status     out
    +08 PHANDLE FileHandle
    +10 PHANDLE FileHandle
    +18 POBJECT_ATTRIBUTES ObjectAttributes
    +20 PIO_STATUS_BLOCK IoStatusBlock
    +28 ULONG ShareAccess
    +2C ULONG OpenOptions
0x222014
    穿透读取文件
    Buffer= sizeof=0x50     具体参数含义见NtReadFile
    +00 NTSTATUS status     out
    +08 HANDLE FileHandle   in
    +10 HANDLE Event        in
    +18 PIO_APC_ROUTINE ApcRoutine  in
    +20 PVOID ApcContext            in
    +28 PIO_STATUS_BLOCK IoStatusBlock  in
    +30 PVOID Buffer        out
    +38 ULONG Length        in
    +40 PLARGE_INTEGER ByteOffset   
    +48 PULONG Key
0x222018
    穿透写入文件
    Buffer= sizeof=0x50     具体参数含义见NtWriteFile
    +00 NTSTATUS status     out
    +08 HANDLE FileHandle   in
    +10 HANDLE Event        in
    +18 PIO_APC_ROUTINE ApcRoutine  in
    +20 PVOID ApcContext            in
    +28 PIO_STATUS_BLOCK IoStatusBlock  in
    +30 PVOID Buffer        out
    +38 ULONG Length        in
    +40 PLARGE_INTEGER ByteOffset   
    +48 PULONG Key
0x22201C
    普通关闭句柄NtClose
    buffer=     sizeof=0x10
    +00 NTSTATUS status     out
    +04 HANDLE Handle   in
0x222020
    穿透设置文件
    Buffer= sizeof=0x30       具体参数含义见NtSetInformationFile
    +00 NTSTATUS status;
    +08 HANDLE FileHandle           in
    +10 PIO_STATUS_BLOCK IoStatus       out 
    +18 PVOID FileInformation       in
    +20 ULONG Length            in
    +24 FILE_INFORMATION_CLASS FileInformationClass in
    +28 BOOL DelCurrentFile     in
0x222024
    穿透查询文件
    Buffer= sizeof=0x30       具体参数含义见NtQueryInformationFile
    +00 NTSTATUS status             out
    +08 HANDLE FileHandle           in
    +10 PIO_STATUS_BLOCK IoStatus       out 
    +18 PVOID FileInformation       in
    +20 ULONG Length            in
    +24 FILE_INFORMATION_CLASS FileInformationClass in
    +28 BOOL DelCurrentFile     in
0x222028
    尚未实现
0x22202C    
    穿透查询目录
    Buffer= sizeof=0x58 具体参数含义见NtQueryDirectoryFile
    +00 NTSTATUS status     out
    +08 HANDLE FileHandle   in
    +10 HANDLE Event        in
    +18     PIO_APC_ROUTINE ApcRoutine  未使用
    +20 PVOID ApcContext    未使用
    +28     PIO_STATUS_BLOCK IoStatus       out
    +30 PVOID FileInformation   in
    +38 ULONG Length        in
    +3C FILE_INFORMATION_CLASS FileInformationClass in
    +40 BOOLEAN ReturnSingleEntry       in
    +48 PUNICODE_STRING FileName    in
    +50 BOOLEAN RestartScan in
0x222030
    获取内部版本号
    buffer=     sizeof=8
    +0  <=  0x20110929i64
0x222034    
    穿透查询文件属性
    Buffer= sizeof=0x18     具体参数含义见NtQueryAttributesFile
    +00 NTSTATUS status     out
    +08 POBJECT_ATTRIBUTES ObjectAttributes     in          路径前缀匹配\??\c:
    +10 FILE_NETWORK_OPEN_INFORMATION networkInformation    out
0x222038    
    解锁文件
    buffer=     sizeof=0x804
    +00 NTSTATUS status     out
    +04 WCHAR FileName[1024]    in
0x222144
    普通关闭句柄NtClose
    buffer=     sizeof=0x10
    +00 NTSTATUS    status out
    +08 HANDLE      Handle in
0x222148
    穿透创建注册表项NtCreateKey         成员含义见NtCreateKey
    buffer=     sizeof=0x20
    +00 HANDLE  KeyHandle   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
0x22214C
    穿透打开注册表项NtOpenKey           成员含义见NtOpenKey
    buffer=     sizeof=0x20
    +00 HANDLE  KeyHandle   out
    +08 NTSTATUS status     out     注意status不是第一成员了!!
    +10 ACCESS_MASK DesiredAccess   in
    +18 POBJECT_ATTRIBUTES ObjectAttributes in
0x222150
    穿透删除注册表项NtDeleteKey         成员含义见NtDeleteKey
    buffer=     sizeof=0x10
    +00 NTSTATUS status
    +08 HANDLE KeyHandle
0x222154
    穿透删除注册表项NtDeleteValueKey    成员含义见NtDeleteValueKey
    buffer=     sizeof=0x18
    +00 NTSTATUS status     out 
    +08 HANDLE  KeyHandle   in
    +10 PUNICODE_STRING ValueName   in
0x222158
    穿透设置注册表项NtSetValueKeyEx     成员含义见NtSetValueKey
    buffer=     sizeof=0x30
    +00 NTSTATUS status     out 
    +08 HANDLE  KeyHandle   in
    +10 PUNICODE_STRING ValueName   in
    +18 ULONG TitleIndex    未使用
    +1C ULONG   Type    in
    +20 PVOID   Data    in
    +28 ULONG   DataSize    in
0x22215C
    穿透设置注册表项NtQueryValueKey     成员含义见NtQueryValueKey
    buffer=     sizeof=0x30
    +00 DWORD ResultLength  out
    +04 NTSTATUS status     out     注意status不是第一成员了!!
    +08 HANDLE  KeyHandle   in
    +10 PUNICODE_STRING ValueName
    +18 ULONG Type          out     KeyValueInformation->DataLength
    +20 PVOID Data          out     KeyValueInformation->Data
    +28 ULONG DataLength    out     KeyValueInformation->DataLength
0x222160
    穿透枚举注册表项NtEnumerateKey      成员含义见NtEnumerateKey
    buffer=     sizeof=0x28
    +00 NTSTATUS status     out
    +04 ULONG ResultLength  out
    +08 HANDLE KeyHandle    in
    +10 ULONG Index     in
    +14 KEY_INFORMATION_CLASS KeyValueInformationClass    in
    +18 PVOID KeyInformation   out
    +20 ULONG Length    in
0x222164
    穿透枚举注册表项NtEnumerateValueKey     成员含义见NtEnumerateValueKey
    buffer=     sizeof=0x28
    +00 NTSTATUS status     out
    +04 ULONG ResultLength  out
    +08 HANDLE KeyHandle    in
    +10 ULONG Index     in
    +14 KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass    in
    +18 PVOID KeyValueInformation   out
    +20 ULONG Length    in
0x222284
    通过进程id或进程对象名(只能选一)穿透打开进程NtOpenProcess   成员含义见NtOpenProcess
    buffer=     sizeof=0x30
    +00 NTSTATUS status     out
    +08 HANDLE ProcessHandle    out
    +10 ACCESS_MASK DesiredAccess in
    +18 POBJECT_ATTRIBUTES ObjectAttributes in
    +20 PCLIENT_ID ClientId
0x222288
    buffer=     sizeof=4
    +00 DWORD ProcessId
0x222430
    获取操作系统版本
    buffer=RTL_OSVERSIONINFOEXW     sizeof=0x11C
0x222800
0x222804
    2个初始化TSSysKit的通道
0x222808
    获取CPUID信息
    buffer=     sizeof=0x38
    +00 ULONG Fn0000_0000_EBX   EBX EDX ECX 组成"GenuineIntel"或"AuthenticAMD"
    +04 ULONG Fn0000_0000_EDX
    +08 ULONG Fn0000_0000_ECX
    +10 ULONG CpuType   0:未知    1:INTEL    2:AMD
    +14 BOOLEAN VMBit   是否支持vm   Intel Virutalization Technology / AMD Secure Virtual Machine
    +18 ULONGLONG MSR3A  Intel  IA32_FEATURE_CONTROL   MSR(0x3A)  / AMD Read NX support 
    +20 ULONGLONG  NXsupport        Intel CR4  / AMD Msr(0xC0000080)
    +28 ULONGLONG VMXONBit  Intel MSR(0x3A) activate VMXON outside of SMX mode  /  AMD Msr(0xC0010114)
    +30 ULONG NRIP    Fn8000_000A_EDX&4

四、默认派遣例程

  • 检查当前所属进程是否有腾讯标记 (CheckDriverLoaderValid)
  • 重置驱动注册表项信息 (ResetRegServiceInfo)
  • 随机化EPROCESS的ImageFileName(RandomImageNameToHide)

4.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;
        }
    }
}

4.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[0];
} 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;
 }

4.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;
}

4.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);
}

4.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);
}

4.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 % 5] = (TimeFields.Second % 26) + 'A';
    }
}

4.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[i].OffsetToFileName;
            If(!stricmp(modules->Modules[i].FullPathName[offset],FileName)
            {
                Memcpy(Buffer, &modules->Modules[i],Size);
                Find = TRUE;
                Break;
            }
        }
}
ExFreePool(modules);
Return FALSE;
}

4.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 [esp+4]
        Int 2Eh
        Retn 18h
    }
}

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

4.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;
    }
}

4.10 基础库功能——检测腾讯程序合法性

  对当加载驱动的进程进行md5校验,如果校验失败则拒绝加载,从\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\TSKSP\InstallDir获取q管安装目录

void CheckTsFileValid(PEPROCESS Process)
{
    NTSTATUS status;
    const int BufSize = 522;
    WCHAR CurProcFileDosName[260];
    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);
}

4.11 解锁文件

  • 设置文件属性为FILE_ATTRIBUTE_NORMAL
  • 执行IopCloseFile IRP_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)
{//设置文件属性为NORMAL
    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[i].Object == FileObject)
                    {
                        ObjectTypeIndex = HandleInformation2->Handles[i].ObjectTypeIndex;
                        Break;
                    }
                }
                if(ObjectTypeIndex)
                {
                    for(int i=0;i<HandleInformation2->NumberOfHandles;i++)
                    {
                        if(HandleInformation2->Handles[i].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[i].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[i].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[i].UniqueProcessId;
                                                        HANDLE ObjectHandle = HandleInformation2->Handles[i].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[i].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;
}

五、获取ObjectInitializer

  获取RegObjectInitializer:

  • 1.获取操作系统版本并转化为数组下标[0-9]
  • 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.获取操作系统版本并转化为数组下标[0-9]
  • 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  

5.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;
}

5.2获取ParseProcedure

FARPROC RegObjectInitialzer[6];
FARPROC FileObjectInitialzer[6];
// 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[0].ImageBase;
        NtosEnd = NtosBegin + modules->Modules[0].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[2] = Proc;
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

5.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;
}

5.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;
}

5.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[0] += TimeFields.Milliseconds % 9;
    ValueName[1] += TimeFields.Second % 8;
    ValueName[3] += TimeFields.Minute % 7;
    ValueName[4] += TimeFields.Milliseconds % 9;
    ValueName[5] += TimeFields.Second % 8;
    KeyPath[25] += TimeFields.Second % 9;
    KeyPath[26] += TimeFields.Milliseconds % 8;
    KeyPath[27] += TimeFields.Second % 7;
    KeyPath[28] += TimeFields.Milliseconds % 9;
    KeyPath[29] += 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 [ebp+18h]
80619a25 ff7514          push    dword ptr [ebp+14h]
80619a28 8d45c4          lea     eax,[ebp-3Ch]
80619a2b 50              push    eax
80619a2c ff7704          push    dword ptr [edi+4]
80619a2f e88e0b0100      call    nt!CmSetValueKey (8062a5c2)

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

--x64 下的情况 
CM_MATCH_DATA Ano[]=
{
    {7, 1},
    0, NULL, NCmSetValueKey, 0xFFFFFFFF,
    {
        0x90,0x00,0x00,0x00,0x48,0x89,0x44,0x24,0x28,0x44,0x89,0x74,0x24,0x20,0x4C,0x8B,
        0x4C,0x24,0x60,0x44,0x8B,0xC7,0x48,0x8D,0x54,0x24,0x50,0x48,0x8B,0x4C,0x24,0x48,
    },
    {9, 0},
    0, NULL, 0, 0,
    {
        0,
    }
}

BOOLEAN CheckAndGetCmInnerFunc(ULONG Address,int CmIndex)                           
{//通过回溯查找cm*地址
    UCHAR Code[32];
    if(!Address || Address - 0x2F <= 0x7FFFFFFF || !IsAddressRegionValid(Address-0x2F,0x2F))
        return FALSE;
    if(CmMatchData[VersionIndex][CmIndex].CodeMask)
    {
        RtlCopyMemory(Code,Address-0x25,sizeof(Code));
        for(int i=31;i>=0;i--)
        {
            ULONG bit = CmMatchData[VersionIndex][CmIndex].CodeMask >> (31-i);
            if(bit & 1)
            {
                if(CmMatchData[VersionIndex][CmIndex].ByteCode[i] != Code[i])
                    goto CompareAnother;
            }
            else if(bit == 0)
            {
                CmMatchData[VersionIndex][CmIndex].FuncAddr = Address+*(ULONG_PTR*)(Address-1);
                CellRoutineBit |= CmMatchData[VersionIndex][CmIndex].CmFlag;
                CmMatchData[VersionIndex][CmIndex].InitFlag = TRUE;
                return TRUE;
            }
        }
    }
    return FALSE;
CompareAnother:

    for(int j=0;Ano[j].Version[0] != 9;j++)
    {
        if(Ano[j].Version[0] == VersionIndex && Ano[j].Version[1] == CmIndex)
        {
            for(int i=31;i>=0;i--)
            {
                ULONG bit = Ano[j].CodeMask >> (31-i);
                if(bit & 1)
                {
                    if(Ano[j].ByteCode[i] != Code[i])
                        goto CompareAnother;
                }
                else if(bit == 0)
                {
                    CmMatchData[VersionIndex][CmIndex].FuncAddr = Address+*(ULONG_PTR*)(Address-1);
                    CellRoutineBit |= CmMatchData[VersionIndex][CmIndex].CmFlag;
                    CmMatchData[VersionIndex][CmIndex].InitFlag = TRUE;
                    return TRUE;
                }
            }
        }
    }
    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[VersionIndex][CmIndex].InitFlag && CmMatchData[VersionIndex][CmIndex].FuncAddr)
        {
            if(!(CmMatchData[VersionIndex][CmIndex].CmFlag & CellRoutineBit))
                CellRoutineBit |= CmMatchData[VersionIndex][CmIndex].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;
}

5.6 匹配结构

X86的情况:

  用于匹配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,
};

#pragma pack(4)
struct CM_MATCH_DATA
{
    ULONG Version[2];//版本
    ULONG InitFlag;//是否初始化
    ULONG FuncAddr;//获取到的cm函数地址
    ULONG CmFlag;//cm函数类型,1~0x100000 对应于各个cm函数
    ULONG CodeMask;//32bit对应于BYTE ByteCode[32]的掩码,决定是否比较
    UCHAR ByteCode[32];//用于比较cm函数的机器码
};
CM_MATCH_DATA CmMatchData[MaxVersion][ECmMax]=
{
{//NON
    {
        {0, 0},
        0, NULL, NCmQueryValueKey, 0x00000000,
        {
            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, 0x00000000,
        {
            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, 0x00000000,
        {
            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, 0x00000000,
        {
            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, 0x00000000,
        {
            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, 0x00000000,
        {
            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,
        },
    },
},
{//WIN2000
    {
        {1, 0},
        0, NULL, NCmQueryValueKey, 0x00176DB6,
        {
            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, 0x0000BB6E,
        {
            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, 0x00003DB6,
        {
            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, 0x0006DB6D,
        {
            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, 0x001AEDB6,
        {
            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, 0x001AEDB6,
        {
            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,
        },
    },
},
{//WINXPSP1
    {
        {2, 0},
        0, NULL, NCmQueryValueKey, 0x003B6DB6,
        {
            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, 0x0000BB6E,
        {
            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, 0x00001DB6,
        {
            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, 0x0000DB6D,
        {
            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, 0x000EEDB6,
        {
            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,
        },
    },
    {
        {2, 5},
        0, NULL, NCmEnumerateValueKey, 0x000EEDB6,
        {
            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,
        },
    },
},
{//WINXPSP3
    {
        {3, 0},
        0, NULL, NCmQueryValueKey, 0x00176DB6,
        {
            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, 0x0000BB6E,
        {
            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, 0x00001DB6,
        {
            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, 0x0000DB6D,
        {
            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, 0x000EEDB6,
        {
            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, 0x000EEDB6,
        {
            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,
        },
    },
},
{//WINVISTA
    {
        {4, 0},
        0, NULL, NCmQueryValueKey, 0x01DB6DB6,
        {
            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,
        },
    },
    {
        {4, 1},
        0, NULL, NCmSetValueKey, 0x0003BB6E,
        {
            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, 0x00037FF6,
        {
            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, 0x000003FD,
        {
            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, 0x0016DBB6,
        {
            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, 0x0002DB76,
        {
            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,
        },
    },
},
{//WIN7
    {
        {5, 0},
        0, NULL, NCmQueryValueKey, 0x01DB6DB6,
        {
            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,
        },
    },
    {
        {5, 1},
        0, NULL, NCmSetValueKey, 0x007FBB6E,
        {
            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, 0x00007FF6,
        {
            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, 0x00067E61,
        {
            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, 0x0016DBB6,
        {
            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, 0x0002DB76,
        {
            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,
        },
    },
},
{//WIN7SP1
    {
        {6, 0},
        0, NULL, NCmQueryValueKey, 0x01DB6DB6,
        {
            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, 0x0003BB6E,
        {
            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, 0x00037FF6,
        {
            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, 0x000003FD,
        {
            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, 0x0016DBB6,
        {
            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, 0x0002DB76,
        {
            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,
        },
    },
},
{//WIN8
    {
        {7, 0},
        0, NULL, NCmQueryValueKey, 0x001DA7A6,
        {
            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, 0x00FFFB6E,
        {
            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, 0x001FFDB6,
        {
            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, 0x000003FD,
        {
            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, 0x07DB6DB6,
        {
            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, 0x0036DB76,
        {
            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,
        },
    },
},
{//WIN8.1
    {
        {8, 0},
        0, NULL, NCmQueryValueKey, 0x00786DBE,
        {
            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, 0x0E1F76DD,
        {
            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,0x88,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, 0x0F0F879C,
        {
            0x00,0x00,0x00,0x00,0x40,0x66,0x89,0x81,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,
        },
    },
},
{//WIN10
    {
        {9, 0},
        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,
        },
    },
},
};

X64的情况

#pragma pack(8)
struct CM_MATCH_DATA
{
    ULONG Version[2];//版本
    ULONG InitFlag;//是否初始化
    ULONG _gap;//8字节对齐
    ULONGLONG FuncAddr;//获取到的cm函数地址
    ULONG CmFlag;//cm函数类型,1~0x100000 对应于各个cm函数
    ULONG CodeMask;//32bit对应于BYTE ByteCode[32]的掩码,决定是否比较
    UCHAR ByteCode[32];//用于比较cm函数的机器码
};
CM_MATCH_DATA CmMatchData[MaxVersion][ECmMax]=
{
{//NON
    {
        {0, 0},
        0, NULL, NCmQueryValueKey, 0x00000000,
        {
            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, 0x00000000,
        {
            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, 0x00000000,
        {
            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, 0x00000000,
        {
            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, 0x00000000,
        {
            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, 0x00000000,
        {
            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,
        },
    },
},
{//WIN2000
    {
        {1, 0},
        0, NULL, NCmQueryValueKey, 0x00000000,
        {
            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, 1},
        0, NULL, NCmSetValueKey, 0x00000000,
        {
            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, 2},
        0, NULL, NCmDeleteValueKey, 0x00000000,
        {
            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, 3},
        0, NULL, NCmDeleteKey, 0x00000000,
        {
            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, 4},
        0, NULL, NCmEnumerateKey, 0x00000000,
        {
            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, 5},
        0, NULL, NCmEnumerateValueKey, 0x00000000,
        {
            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,
        },
    },
},
{//WINXPSP1
    {
        {2, 0},
        0, NULL, NCmQueryValueKey, 0x00000000,
        {
            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,
        },
    },
    {
        {2, 1},
        0, NULL, NCmSetValueKey, 0x00000000,
        {
            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,
        },
    },
    {
        {2, 2},
        0, NULL, NCmDeleteValueKey, 0x00000000,
        {
            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,
        },
    },
    {
        {2, 3},
        0, NULL, NCmDeleteKey, 0x00000000,
        {
            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,
        },
    },
    {
        {2, 4},
        0, NULL, NCmEnumerateKey, 0x00000000,
        {
            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,
        },
    },
    {
        {2, 5},
        0, NULL, NCmEnumerateValueKey, 0x00000000,
        {
            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,
        },
    },
},
{//WINXPSP3
    {
        {3, 0},
        0, NULL, NCmQueryValueKey, 0xFFFFFFFF,
        {
            0x44,0x89,0x64,0x24,0x20,0x4D,0x8B,0xCE,0x44,0x8B,0xC3,0x48,0x8D,0x94,0x24,0x30,
            0x01,0x00,0x00,0x4C,0x8B,0x64,0x24,0x48,0x4C,0x89,0x64,0x24,0x40,0x49,0x8B,0xCC,
        },
    },
    {
        {3, 1},
        0, NULL, NCmSetValueKey, 0xFFFFFFFF,
        {
            0x01,0x00,0x00,0x48,0x89,0x44,0x24,0x28,0x44,0x89,0x74,0x24,0x20,0x4D,0x8B,0xCD,
            0x44,0x8B,0x84,0x24,0x58,0x01,0x00,0x00,0x48,0x8D,0x54,0x24,0x48,0x48,0x8B,0xCE,
        },
    },
    {
        {3, 2},
        0, NULL, NCmDeleteValueKey, 0xFFFFFFFF,
        {
            0x28,0x44,0x24,0x40,0x66,0x0F,0x7F,0x84,0x24,0xC0,0x00,0x00,0x00,0x4C,0x8B,0x84,
            0x24,0x10,0x01,0x00,0x00,0x48,0x8D,0x94,0x24,0xC0,0x00,0x00,0x00,0x48,0x8B,0xCE,
        },
    },
    {
        {3, 3},
        0, NULL, NCmDeleteKey, 0xFFFFFFFF,
        {
            0x49,0x3B,0xCD,0x74,0x0A,0xF6,0x41,0x04,0x80,0x0F,0x85,0xE2,0x44,0x0B,0x00,0x41,
            0x3A,0xF5,0x0F,0x85,0x93,0x44,0x0B,0x00,0x41,0x3B,0xFD,0x7C,0x0F,0x48,0x8B,0xCB,
        },
    },
    {
        {3, 4},
        0, NULL, NCmEnumerateKey, 0xFFFFFFFF,
        {
            0x4C,0x89,0x74,0x24,0x20,0x45,0x8B,0xCC,0x44,0x8B,0x84,0x24,0x58,0x01,0x00,0x00,
            0x4C,0x8B,0x64,0x24,0x50,0x49,0x8B,0xD4,0x48,0x8B,0x74,0x24,0x40,0x48,0x8B,0xCE,
        },
    },
    {
        {3, 5},
        0, NULL, NCmEnumerateValueKey, 0xFFFFFFFF,
        {
            0x00,0x00,0x89,0x44,0x24,0x20,0x4C,0x8B,0x8C,0x24,0x38,0x01,0x00,0x00,0x44,0x8B,
            0xC6,0x8B,0x94,0x24,0x28,0x01,0x00,0x00,0x4C,0x8B,0x64,0x24,0x50,0x49,0x8B,0xCC,
        },
    },
},
{//WINVISTA
    {
        {4, 0},
        0, NULL, NCmQueryValueKey, 0xFFFFFFFF,
        {
            0x4C,0x89,0x6C,0x24,0x28,0x44,0x89,0x64,0x24,0x20,0x4D,0x8B,0xCE,0x44,0x8B,0xC7,
            0x48,0x8D,0x94,0x24,0x40,0x01,0x00,0x00,0x4C,0x8B,0x64,0x24,0x60,0x49,0x8B,0xCC,
        },
    },
    {
        {4, 1},
        0, NULL, NCmSetValueKey, 0xFFFFFFFF,
        {
            0x48,0x8B,0x84,0x24,0x20,0x01,0x00,0x00,0x48,0x89,0x44,0x24,0x28,0x44,0x89,0x6C,
            0x24,0x20,0x4D,0x8B,0xCC,0x44,0x8B,0xC6,0x48,0x8D,0x54,0x24,0x48,0x48,0x8B,0xCF,
        },
    },
    {
        {4, 2},
        0, NULL, NCmDeleteValueKey, 0xFFFFFFFF,
        {
            0x28,0x44,0x24,0x40,0x66,0x0F,0x7F,0x84,0x24,0xB0,0x00,0x00,0x00,0x4C,0x8B,0x84,
            0x24,0x00,0x01,0x00,0x00,0x48,0x8D,0x94,0x24,0xB0,0x00,0x00,0x00,0x48,0x8B,0xCF,
        },
    },
    {
        {4, 3},
        0, NULL, NCmDeleteKey, 0xFFE7F3FF,
        {
            0x49,0x3B,0xCD,0x74,0x0A,0xF6,0x41,0x04,0x80,0x0F,0x85,0x58,0x38,0x0E,0x00,0x41,
            0x3A,0xF5,0x0F,0x85,0x06,0x38,0x0E,0x00,0x41,0x3B,0xDD,0x7C,0x1D,0x48,0x8B,0xCF,
        },
    },
    {
        {4, 4},
        0, NULL, NCmEnumerateKey, 0xFFFFFFFF,
        {
            0x30,0x89,0x74,0x24,0x28,0x4C,0x89,0x74,0x24,0x20,0x45,0x8B,0xCD,0x45,0x8B,0xC7,
            0x48,0x8B,0x7C,0x24,0x50,0x48,0x8B,0xD7,0x48,0x8B,0x74,0x24,0x40,0x48,0x8B,0xCE,
        },
    },
    {
        {4, 5},
        0, NULL, NCmEnumerateValueKey, 0xFFFFFFFF,
        {
            0x24,0x28,0x44,0x89,0x64,0x24,0x20,0x4C,0x8B,0xCE,0x45,0x8B,0xC7,0x44,0x8B,0xAC,
            0x24,0x68,0x01,0x00,0x00,0x41,0x8B,0xD5,0x48,0x8B,0x74,0x24,0x50,0x48,0x8B,0xCE,
        },
    },
},
{//WIN7
    {
        {5, 0},
        0, NULL, NCmQueryValueKey, 0xFFFFFFFF,
        {
            0x4C,0x89,0x6C,0x24,0x28,0x44,0x89,0x64,0x24,0x20,0x4D,0x8B,0xCE,0x44,0x8B,0xC7,
            0x48,0x8D,0x94,0x24,0x40,0x01,0x00,0x00,0x4C,0x8B,0x64,0x24,0x60,0x49,0x8B,0xCC,
        },
    },
    {
        {5, 1},
        0, NULL, NCmSetValueKey, 0xFFFFFFFF,
        {
            0x48,0x8B,0x84,0x24,0x30,0x01,0x00,0x00,0x48,0x89,0x44,0x24,0x28,0x44,0x89,0x6C,
            0x24,0x20,0x4D,0x8B,0xCC,0x44,0x8B,0xC6,0x48,0x8D,0x54,0x24,0x48,0x48,0x8B,0xCF,
        },
    },
    {
        {5, 2},
        0, NULL, NCmDeleteValueKey, 0xFFFFFFFF,
        {
            0x28,0x44,0x24,0x40,0x66,0x0F,0x7F,0x84,0x24,0xB0,0x00,0x00,0x00,0x4C,0x8B,0x84,
            0x24,0x00,0x01,0x00,0x00,0x48,0x8D,0x94,0x24,0xB0,0x00,0x00,0x00,0x48,0x8B,0xCF,
        },
    },
    {
        {5, 3},
        0, NULL, NCmDeleteKey, 0xFFE7F3FF,
        {
            0x49,0x3B,0xCD,0x74,0x0A,0xF6,0x41,0x04,0x80,0x0F,0x85,0x7A,0x55,0x0D,0x00,0x41,
            0x3A,0xF5,0x0F,0x85,0x28,0x55,0x0D,0x00,0x41,0x3B,0xDD,0x7C,0x1D,0x48,0x8B,0xCF,
        },
    },
    {
        {5, 4},
        0, NULL, NCmEnumerateKey, 0xFFFFFFFF,
        {
            0x44,0x89,0x64,0x24,0x28,0x48,0x89,0x7C,0x24,0x20,0x45,0x8B,0xCE,0x45,0x8B,0xC7,
            0x48,0x8B,0x7C,0x24,0x50,0x48,0x8B,0xD7,0x48,0x8B,0x74,0x24,0x40,0x48,0x8B,0xCE,
        },
    },
    {
        {5, 5},
        0, NULL, NCmEnumerateValueKey, 0xFFFFFFFF,
        {
            0x24,0x28,0x44,0x89,0x64,0x24,0x20,0x4C,0x8B,0xCE,0x45,0x8B,0xC7,0x44,0x8B,0xAC,
            0x24,0x68,0x01,0x00,0x00,0x41,0x8B,0xD5,0x48,0x8B,0x74,0x24,0x50,0x48,0x8B,0xCE,
        },
    },
},
{//WIN7SP1
    {
        {6, 0},
        0, NULL, NCmQueryValueKey, 0x00000000,
        {
            0x48,0x8D,0x94,0x24,0x30,0x01,0x00,0x00,0x4C,0x8B,0x64,0x24,0x48,0x4C,0x89,0x64,
            0x24,0x40,0x49,0x8B,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        },
    },
    {
        {6, 1},
        0, NULL, NCmSetValueKey, 0x00000000,
        {
            0x4D,0x8B,0xCD,0x44,0x8B,0x84,0x24,0x58,0x01,0x00,0x00,0x48,0x8D,0x54,0x24,0x48,
            0x48,0x8B,0xCE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        },
    },
    {
        {6, 2},
        0, NULL, NCmDeleteValueKey, 0x00000000,
        {
            0x4C,0x8B,0x84,0x24,0x10,0x01,0x00,0x00,0x48,0x8D,0x94,0x24,0xC0,0x00,0x00,0x00,
            0x48,0x8B,0xCE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        },
    },
    {
        {6, 3},
        0, NULL, NCmDeleteKey, 0x00000000,
        {
            0x41,0x3A,0xF5,0x0F,0x85,0x4B,0x37,0x0D,0x00,0x41,0x3B,0xFD,0x7C,0x0F,0x48,0x8B,
            0xCB,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        },
    },
    {
        {6, 4},
        0, NULL, NCmEnumerateKey, 0x00000000,
        {
            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,
        },
    },
    {
        {6, 5},
        0, NULL, NCmEnumerateValueKey, 0x00000000,
        {
            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,
        },
    },
},
{//WIN8
    {
        {7, 0},
        0, NULL, NCmQueryValueKey, 0xDFF7FFFF,
        {
            0x4C,0x89,0x7C,0x24,0x28,0x44,0x89,0x74,0x24,0x20,0x4D,0x8B,0xCC,0x44,0x8B,0xC7,
            0x48,0x8D,0x94,0x24,0x70,0x01,0x00,0x00,0x4C,0x8B,0x74,0x24,0x50,0x49,0x8B,0xCE,
        },
    },
    {
        {7, 1},
        0, NULL, NCmSetValueKey, 0xFFFFFFFF,
        {
            0x00,0x00,0x48,0x89,0x44,0x24,0x28,0x89,0x5C,0x24,0x20,0x4C,0x8B,0x4C,0x24,0x60,
            0x45,0x8B,0xC5,0x48,0x8D,0x54,0x24,0x50,0x48,0x8B,0x7C,0x24,0x48,0x48,0x8B,0xCF,
        },
    },
    {
        {7, 2},
        0, NULL, NCmDeleteValueKey, 0xFFFF7FFE,
        {
            0xE1,0x01,0x0F,0x28,0x44,0x24,0x40,0x66,0x0F,0x7F,0x84,0x24,0xE0,0x00,0x00,0x00,
            0x4C,0x8B,0xC6,0x48,0x8D,0x94,0x24,0xE0,0x00,0x00,0x00,0x48,0x8B,0x4C,0x24,0x50,
        },
    },
    {
        {7, 3},
        0, NULL, NCmDeleteKey, 0x009887FF,
        {
            0xE4,0x01,0x00,0x00,0xFF,0xC0,0x66,0x89,0x81,0xE4,0x01,0x00,0x00,0x66,0x85,0xC0,
            0x0F,0x84,0xB8,0x00,0x00,0x00,0x48,0x8B,0x7D,0xA7,0x45,0x8A,0xFD,0x48,0x8B,0xCF,
        },
    },
    {
        {7, 4},
        0, NULL, NCmEnumerateKey, 0xFFFFFFFF,
        {
            0x30,0x89,0x74,0x24,0x28,0x48,0x89,0x7C,0x24,0x20,0x45,0x8B,0xCC,0x45,0x8B,0xC6,
            0x48,0x8B,0x7C,0x24,0x50,0x48,0x8B,0xD7,0x48,0x8B,0x74,0x24,0x48,0x48,0x8B,0xCE,
        },
    },
    {
        {7, 5},
        0, NULL, NCmEnumerateValueKey, 0xFFFFFFFF,
        {
            0x00,0x4C,0x89,0x64,0x24,0x28,0x89,0x74,0x24,0x20,0x4D,0x8B,0xCE,0x45,0x8B,0xC7,
            0x44,0x8B,0x74,0x24,0x50,0x41,0x8B,0xD6,0x48,0x8B,0x74,0x24,0x58,0x48,0x8B,0xCE,
        },
    },
},
{//WIN8.1
    {
        {8, 0},
        0, NULL, NCmQueryValueKey, 0xFFFFFFFF,
        {
            0x01,0x00,0x00,0x4C,0x89,0x6C,0x24,0x28,0x44,0x89,0x7C,0x24,0x20,0x4D,0x8B,0xCC,
            0x44,0x8B,0x44,0x24,0x48,0x48,0x8D,0x94,0x24,0x60,0x01,0x00,0x00,0x49,0x8B,0xCE,
        },
    },
    {
        {8, 1},
        0, NULL, NCmSetValueKey, 0xFFFFFFFF,
        {
            0xB8,0x00,0x00,0x00,0x48,0x89,0x44,0x24,0x28,0x44,0x89,0x74,0x24,0x20,0x4C,0x8B,
            0x4C,0x24,0x68,0x44,0x8B,0xC7,0x48,0x8D,0x54,0x24,0x50,0x48,0x8B,0x4C,0x24,0x60,
        },
    },
    {
        {8, 2},
        0, NULL, NCmDeleteValueKey, 0xFFFFFFFF,
        {
            0xE1,0x01,0x0F,0x28,0x44,0x24,0x40,0x66,0x0F,0x7F,0x84,0x24,0xE0,0x00,0x00,0x00,
            0x4C,0x8B,0xC6,0x48,0x8D,0x94,0x24,0xE0,0x00,0x00,0x00,0x48,0x8B,0x4C,0x24,0x50,
        },
    },
    {
        {8, 3},
        0, NULL, NCmDeleteKey, 0xFFFFFFFF,
        {
            0xE4,0x01,0x00,0x00,0xFF,0xC0,0x66,0x89,0x81,0xE4,0x01,0x00,0x00,0x66,0x85,0xC0,
            0x0F,0x84,0xBC,0x00,0x00,0x00,0x48,0x8B,0x7D,0xB7,0x45,0x8A,0xFD,0x48,0x8B,0xCF,
        },
    },
    {
        {8, 4},
        0, NULL, NCmEnumerateKey, 0xFFFFFFFF,
        {
            0x8B,0x84,0x24,0xA0,0x01,0x00,0x00,0x89,0x44,0x24,0x28,0x4C,0x89,0x74,0x24,0x20,
            0x45,0x8B,0xCF,0x45,0x8B,0xC5,0x48,0x8B,0x54,0x24,0x58,0x48,0x8B,0x4C,0x24,0x48,
        },
    },
    {
        {8, 5},
        0, NULL, NCmEnumerateValueKey, 0xFFFFFFFF,
        {
            0x4C,0x24,0x58,0x48,0x39,0x5C,0x24,0x60,0x0F,0x85,0x7E,0xC0,0x19,0x00,0x4C,0x89,
            0x6C,0x24,0x28,0x89,0x44,0x24,0x20,0x4D,0x8B,0xCE,0x44,0x8B,0xC6,0x41,0x8B,0xD7,
        },
    },
},
{//WIN10
    {
        {9, 0},
        0, NULL, NCmQueryValueKey, 0x00000000,
        {
            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,
        },
    },
    {
        {9, 1},
        0, NULL, NCmSetValueKey, 0x00000000,
        {
            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,
        },
    },
    {
        {9, 2},
        0, NULL, NCmDeleteValueKey, 0x00000000,
        {
            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,
        },
    },
    {
        {9, 3},
        0, NULL, NCmDeleteKey, 0x00000000,
        {
            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,
        },
    },
    {
        {9, 4},
        0, NULL, NCmEnumerateKey, 0x00000000,
        {
            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,
        },
    },
    {
        {9, 5},
        0, NULL, NCmEnumerateValueKey, 0x00000000,
        {
            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,
        },
    },
},
},

5.8 获取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;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容