• 浅谈DPCHookSSDT和RemoveDPC


      最近学了DPC这一对,把Win7 32位和64位都做了,查阅了大量的资料,并且进行了大量调试,理一下思路,为了后面更好的学习。

       转载请注明出处:http://www.cnblogs.com/littlepear/p/6733145.html

     1. 当我们需要定时的完成某项任务时,就需要注册一个DPC定时器了,在Ring3中, CTimer类中有一个SetTimer()函数,对应的驱动中的函数就是KeSetTimer()了。Timer和要执行回调函数结构的DPC都必须初始化, DPC需提供一个回调函数。然后会把KTimer插入到一个timer table的链表中,具体什么样的链表,我们移除的时候再看。

      

    typedef struct MY_TIMER_
    {
        KDPC        Dpc;
        KTIMER        Timer;
        PKDEFERRED_ROUTINE    func;
        PVOID                private_context;
    }MY_TIMER, *PMY_TIMER;
    
    
    VOID    MyTimerInit(PMY_TIMER Timer, PKDEFERRED_ROUTINE Func)
    {
        KeInitializeTimer(&(Timer->Timer));        //定时器的Timer和要执行的回调函数结构Dpc都必须先初始化
        KeInitializeDpc(&(Timer->Dpc), Func, Timer);//第三个参数把Timer作为 DeferredContext传给回调函数,更好的封装
        Timer->func = Func;
    }
    
    BOOLEAN        MyTimerSet(PMY_TIMER Timer, LONG Ms, PVOID context)
    {
        LARGE_INTEGER        Interval;
        Interval = RtlConvertLongToLargeInteger(-10000 * Ms);    //100ns每unit    1s 负数代表相对时间
        Timer->private_context = context;                    //传一块上下背景文,便于利用
        return KeSetTimer(&(Timer->Timer), Interval, &(Timer->Dpc));
        //            定时器   延后执行的时间     要执行的回调函数结构
        //return KeSetTimerEx(&(Timer->Timer), Interval,1000, &(Timer->Dpc));
    }

    为了更好的理解KeSetTimer函数,我查了下wrk,下面是wrk的源码。

    BOOLEAN
    KeSetTimer (
        __inout PKTIMER Timer,
        __in LARGE_INTEGER DueTime,
        __in_opt PKDPC Dpc
        )
    
    /*++
    
    Routine Description:
    
        This function sets a timer to expire at a specified time. If the timer is
        already set, then it is implicitly canceled before it is set to expire at
        the specified time. Setting a timer causes its due time to be computed,
        its state to be set to Not-Signaled, and the timer object itself to be
        inserted in the timer list.
    
    Arguments:
    
        Timer - Supplies a pointer to a dispatcher object of type timer.
    
        DueTime - Supplies an absolute or relative time at which the timer
            is to expire.
    
        Dpc - Supplies an optional pointer to a control object of type DPC.
    
    Return Value:
    
        A boolean value of TRUE is returned if the the specified timer was
        currently set. Else a value of FALSE is returned.
    
    --*/
    
    {
    
        //
        // Set the timer with a period of zero.
        //
    
        return KeSetTimerEx(Timer, DueTime, 0, Dpc);
    }
    
    
    BOOLEAN
    KeSetTimerEx (
        __inout PKTIMER Timer,
        __in LARGE_INTEGER DueTime,
        __in LONG Period,
        __in_opt PKDPC Dpc
        )
    
    /*++
    
    Routine Description:
    
        This function sets a timer to expire at a specified time. If the timer is
        already set, then it is implicitly canceled before it is set to expire at
        the specified time. Setting a timer causes its due time to be computed,
        its state to be set to Not-Signaled, and the timer object itself to be
        inserted in the timer list.
    
    Arguments:
    
        Timer - Supplies a pointer to a dispatcher object of type timer.
    
        DueTime - Supplies an absolute or relative time at which the timer
            is to expire.
    
        Period - Supplies an optional period for the timer in milliseconds.
    
        Dpc - Supplies an optional pointer to a control object of type DPC.
    
    Return Value:
    
        A boolean value of TRUE is returned if the the specified timer was
        currently set. Otherwise, a value of FALSE is returned.
    
    --*/
    
    {
    
        ULONG Hand;
        BOOLEAN Inserted;
        KIRQL OldIrql;
        BOOLEAN RequestInterrupt;
    
        ASSERT_TIMER(Timer);
    
        ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    
        //
        // Raise IRQL to dispatcher level and lock dispatcher database.
        //
        // Capture the timer inserted status and if the timer is currently
        // set, then remove it from the timer list.
        //
    
        KiLockDispatcherDatabase(&OldIrql);
        Inserted = Timer->Header.Inserted;
        if (Inserted != FALSE) {
            KiRemoveTreeTimer(Timer);
        }
    
        //
        // Set the DPC address, set the period, and compute the timer due time.
        // If the timer has already expired, then signal the timer. Otherwise,
        // set the signal state to false and attempt to insert the timer in the
        // timer table.
        //
        // N.B. The signal state must be cleared before it is inserted in the
        //      timer table in case the period is not zero.
        //
    
        Timer->Dpc = Dpc;
        Timer->Period = Period;
        if (KiComputeDueTime(Timer, DueTime, &Hand) == FALSE) {
            RequestInterrupt = KiSignalTimer(Timer);
            KiUnlockDispatcherDatabaseFromSynchLevel();
            if (RequestInterrupt == TRUE) {
                KiRequestSoftwareInterrupt(DISPATCH_LEVEL);
            }
    
        } else {
            Timer->Header.SignalState = FALSE;
            KiInsertOrSignalTimer(Timer, Hand);
        }
    
        KiExitDispatcher(OldIrql);
    
        //
        // Return boolean value that signifies whether the timer was set or
        // not.
        //
    
        return Inserted;
    }
    KeSetTimer

    下面是我完整的DPCHookSSDT代码

     1 #include <ntifs.h>
     2 
     3 #define SEC_IMAGE  0x001000000
     4 
     5 
     6 extern
     7 PIMAGE_NT_HEADERS
     8 NTAPI
     9 RtlImageNtHeader(PVOID BaseAddress);
    10 
    11 extern
    12 char* PsGetProcessImageFileName(PEPROCESS EProcess);
    13 
    14 typedef
    15 NTSTATUS(*pfnNtOpenProcess)(
    16     _Out_    PHANDLE            ProcessHandle,
    17     _In_     ACCESS_MASK        DesiredAccess,
    18     _In_     POBJECT_ATTRIBUTES ObjectAttributes,
    19     _In_opt_ PCLIENT_ID         ClientId
    20     );
    21 
    22 typedef struct MY_TIMER_
    23 {
    24     KDPC        Dpc;
    25     KTIMER        Timer;
    26     PKDEFERRED_ROUTINE    func;
    27     PVOID                private_context;
    28 }MY_TIMER, *PMY_TIMER;
    29 
    30 typedef struct _SYSTEM_SERVICE_DESCRIPTOR_TABLE_
    31 {
    32     PVOID    ServiceTableBase;                    //SSDT(System Service Dispatch Table)服务表的基地址
    33     PVOID    ServiceCounterTableBase;            //用于checked builds,包含SSDT中每个服务被调用的次数
    34     PVOID    NumberOfServices;                    //服务函数的个数,NumberOfService * 4就是整个地址表的大小    64位 0x191, 32位 0x11c 
    35     PVOID    ParamTableBase;                        //SSPT(System Service Parameter Table)的基地址
    36 }SYSTEM_SERVICE_DESCRIPTOR_TABLE, *PSYSTEM_SERVICE_DESCRIPTOR_TABLE;
    37 
    38 BOOLEAN    GetSSDTAddressInWin7_x64(ULONG64* SSDTAddress);
    39 BOOLEAN GetSSDTAddressInWin7_x86(ULONG32* SSDTAddress);
    40 VOID DriverUnload(PDRIVER_OBJECT DriverObject);
    41 BOOLEAN    GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(CHAR* szFuntionName, ULONG32* SSDTFunctionIndex);
    42 PVOID
    43 GetExportVariableAddressFromNtosKrnlExportTableByVariableName(WCHAR* wzVariableName);
    44 BOOLEAN     Ring0MappingPEFile(WCHAR* szFileFullPath, PVOID* MappingBaseAddress, ULONG_PTR* MappingViewSize);
    45 ULONG32    CalcFunctionOffsetInSSDT(PVOID ServiceTableBase, PVOID FunctionAddress, ULONG32 ParamterCount);
    46 VOID    HookSSDTInWin7_x64(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, PVOID MyFunctionAddress,
    47     PVOID OldFuntionAddress, ULONG32 OldFunctionParamterCount, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);
    48 VOID    HookSSDTInWin7_x86(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 MyFunctionAddress);
    49 VOID InlineHook(ULONG64 OldFuntionAddress, ULONG64 MyFunctionAddress, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);
    50 NTSTATUS MyOpenProcess(
    51     _Out_    PHANDLE            ProcessHandle,
    52     _In_     ACCESS_MASK        DesiredAccess,
    53     _In_     POBJECT_ATTRIBUTES ObjectAttributes,
    54     _In_opt_ PCLIENT_ID         ClientId
    55     );
    56 VOID WPOFF();
    57 VOID WPON();
    58 
    59 VOID UnHookSSDTInWin7_x64(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionOffset, PVOID OldFunctionAddress,
    60     UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);
    61 VOID UnHookSSDTInWin7_x86(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionAddress);
    62 VOID UnlineHook(PVOID OldFunctionAddress, CHAR* OldFunctionCode, ULONG32 PatchCodeLength);
    63 
    64 VOID    MyTimerInit(PMY_TIMER Timer, PKDEFERRED_ROUTINE Func);
    65 
    66 BOOLEAN        MyTimerSet(PMY_TIMER Timer, LONG Ms, PVOID context);
    67 
    68 VOID CustomDpc(
    69     _In_     struct _KDPC *Dpc,
    70     _In_opt_ PVOID        DeferredContext,
    71     _In_opt_ PVOID        SystemArgument1,
    72     _In_opt_ PVOID        SystemArgument2
    73     );
    DPCHookSSDT.h
      1 #include "NewDPCHookSSDT.h"
      2 #include <ntimage.h>
      3 #include <Ntstrsafe.h>
      4 
      5 //bp NewDPCHookSSDT!DriverEntry
      6 ULONG32   __NtOpenProcessIndex = 0;
      7 PVOID      __ServiceTableBase = NULL;
      8 ULONG32      __OldNtOpenProcessOffset = 0;
      9 pfnNtOpenProcess      __OldNtOpenProcessAddress = NULL;  //这里无所谓,PVOID也可以
     10 BOOLEAN      __IsHook = FALSE;
     11 UCHAR      __OldCode[15] = { 0 };
     12 
     13 MY_TIMER    MyTimer;
     14 
     15 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
     16 {
     17     NTSTATUS    Status = STATUS_UNSUCCESSFUL;
     18     char        szFunctionName[] = "ZwOpenProcess";
     19     ULONG_PTR    SSDTAddress = 0;    //保存整个SSDT基地址            KeServiceDescriptorTable
     20     ULONG32        TempOffset = 0;
     21     DriverObject->DriverUnload = DriverUnload;
     22     
     23 #ifdef _WIN64
     24     if (GetSSDTAddressInWin7_x64(&SSDTAddress) == FALSE)
     25     {
     26         return Status;
     27     }
     28 #else
     29     if (GetSSDTAddressInWin7_x86(&SSDTAddress) == FALSE)
     30     {
     31         return Status;
     32     }
     33 #endif
     34 
     35     DbgPrint("SSDT:%p
    ", SSDTAddress);                                    //0x23h
     36     if (GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(szFunctionName, &__NtOpenProcessIndex) == FALSE)
     37     {
     38         return Status;
     39     }
     40      
     41     __ServiceTableBase = ((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase;
     42 #ifdef _WIN64
     43     __OldNtOpenProcessOffset = ((PULONG32)__ServiceTableBase)[__NtOpenProcessIndex]; 
     44     TempOffset = __OldNtOpenProcessOffset >> 4;    //抹掉最右边的一位
     45     __OldNtOpenProcessAddress = (PVOID)((ULONG64)__ServiceTableBase + TempOffset);
     46     HookSSDTInWin7_x64(__ServiceTableBase, __NtOpenProcessIndex, MyOpenProcess, KeBugCheckEx, 5, __OldCode, 15);
     47 #else
     48     __OldNtOpenProcessAddress = (pfnNtOpenProcess)(((PULONG32)__ServiceTableBase)[__NtOpenProcessIndex]);
     49     /*kd > u 0x84016ba1
     50         nt!NtOpenProcess:
     51     84016ba1 8bff            mov     edi, edi
     52         84016ba3 55              push    ebp
     53         84016ba4 8bec            mov     ebp, esp
     54         84016ba6 51              push    ecx
     55         84016ba7 51              push    ecx
     56         84016ba8 64a124010000    mov     eax, dword ptr fs : [00000124h]
     57         84016bae 8a803a010000    mov     al, byte ptr[eax + 13Ah]
     58         84016bb4 8b4d14          mov     ecx, dword ptr[ebp + 14h]*/
     59 
     60     //0x00145dc8
     61 
     62     HookSSDTInWin7_x86(__ServiceTableBase, __NtOpenProcessIndex, (ULONG32)MyOpenProcess);//强制转换后,MyOpenProcess才可以传,真奇怪
     63 #endif
     64     MyTimerInit(&MyTimer, (PKDEFERRED_ROUTINE)CustomDpc);
     65     MyTimerSet(&MyTimer, 1000, NULL);
     66     return STATUS_SUCCESS;
     67 }
     68 
     69 VOID    MyTimerInit(PMY_TIMER Timer, PKDEFERRED_ROUTINE Func)
     70 {
     71     KeInitializeTimer(&(Timer->Timer));        //定时器的Timer和要执行的回调函数结构Dpc都必须先初始化
     72     KeInitializeDpc(&(Timer->Dpc), Func, Timer);//第三个参数把Timer作为 DeferredContext传给回调函数,更好的封装
     73     Timer->func = Func;
     74 }
     75 
     76 BOOLEAN        MyTimerSet(PMY_TIMER Timer, LONG Ms, PVOID context)
     77 {
     78     LARGE_INTEGER        Interval;
     79     Interval = RtlConvertLongToLargeInteger(-10000 * Ms);    //100ns每unit    1s 负数代表相对时间
     80     Timer->private_context = context;                    //传一块上下背景文,便于利用
     81     return KeSetTimer(&(Timer->Timer), Interval, &(Timer->Dpc));
     82     //            定时器   延后执行的时间     要执行的回调函数结构
     83     //return KeSetTimerEx(&(Timer->Timer), Interval,1000, &(Timer->Dpc));
     84 }
     85 
     86 VOID CustomDpc(
     87     _In_     struct _KDPC *Dpc,
     88     _In_opt_ PVOID        DeferredContext,
     89     _In_opt_ PVOID        SystemArgument1,
     90     _In_opt_ PVOID        SystemArgument2
     91     )
     92 {
     93     PMY_TIMER  Timer = (PMY_TIMER)DeferredContext;
     94     PVOID        MyContext = Timer->private_context;
     95     DbgPrint("CustomDpc()
    ");
     96 #ifdef _WIN64
     97     HookSSDTInWin7_x64(__ServiceTableBase, __NtOpenProcessIndex, MyOpenProcess, KeBugCheckEx, 5, __OldCode, 15);
     98 #else
     99     HookSSDTInWin7_x86(__ServiceTableBase, __NtOpenProcessIndex, (ULONG32)MyOpenProcess);//强制转换后,MyOpenProcess才可以传,真奇怪
    100 #endif // _WIN64
    101     MyTimerSet(Timer, 1000, MyContext);
    102     //如果前面是KeSetTimerEx函数,这里就不用写MyTimerSet啦
    103 }
    104 
    105 VOID DriverUnload(PDRIVER_OBJECT DriverObject)
    106 {
    107     DbgPrint("ByeBye,Driver!
    ");
    108 
    109     KeCancelTimer(&(MyTimer.Timer));
    110 
    111     if (__IsHook)
    112     {
    113 #ifdef _WIN64
    114 
    115         UnHookSSDTInWin7_x64(__ServiceTableBase, __NtOpenProcessIndex, __OldNtOpenProcessOffset, KeBugCheckEx,
    116             __OldCode, 15);
    117 #else
    118         UnHookSSDTInWin7_x86(__ServiceTableBase, __NtOpenProcessIndex, __OldNtOpenProcessAddress);
    119 #endif
    120         __IsHook = FALSE;
    121     }
    122 }
    123 
    124 BOOLEAN    GetSSDTAddressInWin7_x64(ULONG64* SSDTAddress)
    125 {
    126     //rdmsr c0000082
    127     CHAR*    StartSearchAddress = (char*)__readmsr(0xc0000082);            
    128     CHAR*    EndSearchAddress = StartSearchAddress + PAGE_SIZE; //4KB
    129     CHAR*    i = NULL;
    130     UCHAR    v1 = 0, v2 = 0, v3 = 0;
    131     //必须用UCHAR类型,因为Char的范围是 -128~127   0x80-0x7F
    132     INT64    Offset = 0;
    133     *SSDTAddress = NULL;
    134     for (i = StartSearchAddress; i < EndSearchAddress; i++)
    135     {
    136         if (MmIsAddressValid(i) && MmIsAddressValid(i + 1) && MmIsAddressValid(i + 2))
    137         {
    138             v1 = *i;
    139             v2 = *(i + 1);
    140             v3 = *(i + 2);
    141             if (v1 == 0x4c && v2 == 0x8d && v3 == 0x15)
    142             {
    143                 // 4c8d15238f4700
    144                 memcpy(&Offset, i+3, 4);
    145                 *SSDTAddress = Offset + (ULONG64)i+7;
    146                 break;
    147             }
    148         }
    149     }
    150     if (*SSDTAddress == NULL)
    151     {
    152         return FALSE;
    153     }
    154     return TRUE;
    155 }
    156 
    157 BOOLEAN GetSSDTAddressInWin7_x86(ULONG32* SSDTAddress)
    158 {
    159     //32位下Ntoskrnl.exe有导出 KeServiceDescriptorTable,直接查找即可
    160     *SSDTAddress = NULL;
    161     *SSDTAddress = (ULONG32)GetExportVariableAddressFromNtosKrnlExportTableByVariableName(L"KeServiceDescriptorTable");
    162     if (*SSDTAddress != NULL)
    163     {
    164         return TRUE;
    165     }
    166     return FALSE;
    167 }
    168 PVOID
    169 GetExportVariableAddressFromNtosKrnlExportTableByVariableName(WCHAR* wzVariableName)
    170 {
    171     //通过导出变量名字从NtosKrnl中获得导出变量地址
    172     UNICODE_STRING    uniVariableName;
    173     PVOID            VariableAddress = NULL;
    174 
    175     if (wzVariableName&&wcslen(wzVariableName) > 0)
    176     {
    177         RtlUnicodeStringInit(&uniVariableName, wzVariableName);
    178         //从Ntos模块的导出表中获得导出变量的地址
    179         VariableAddress = MmGetSystemRoutineAddress(&uniVariableName);
    180     }
    181     return VariableAddress;
    182 }
    183 //从内存中读出
    184 BOOLEAN    GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(CHAR* szFuntionName, ULONG32* SSDTFunctionIndex)
    185 {
    186     WCHAR            szFileFullPath[] = L"\SystemRoot\System32\ntdll.dll";    //C:Windows 
    187     ULONG_PTR        MappingViewSize = 0;
    188     PVOID            MappingBaseAddress = 0;
    189     BOOLEAN            IsOk = FALSE;
    190     PIMAGE_NT_HEADERS    Image_Nt_Headers = NULL;
    191     PIMAGE_EXPORT_DIRECTORY        ImageExportDirectory = NULL;    //导出表
    192     //因为不识别DWORD,所以用UINT32
    193     UINT32*            AddressOfFunctions = NULL;
    194     UINT32*            AddressOfNames = NULL;
    195     UINT16*            AddressOfNameOrdinals = NULL;
    196     int                i = 0;
    197     char*            v1 = NULL;
    198     ULONG32            OrdinalOfFunction = 0;
    199     PVOID            AddressOfFunction = 0;
    200 #ifdef _WIN64
    201     /*
    202     0:004> u zwopenprocess
    203     ntdll!NtOpenProcess:
    204     00000000`774ddc10 4c8bd1          mov     r10,rcx
    205     00000000`774ddc13 b823000000      mov     eax,23h
    206     00000000`774ddc18 0f05            syscall
    207     00000000`774ddc1a c3              ret
    208     00000000`774ddc1b 0f1f440000      nop     dword ptr [rax+rax]
    209     */
    210     ULONG32            Offset_SSDTFunctionIndex = 4;
    211 #else
    212     /*
    213     0:004> u zwopenprocess
    214     ntdll!NtOpenProcess:
    215     00000000`774ddc10 4c8bd1          mov     r10,rcx
    216     00000000`774ddc13 b823000000      mov     eax,23h
    217     00000000`774ddc18 0f05            syscall
    218     00000000`774ddc1a c3              ret
    219     00000000`774ddc1b 0f1f440000      nop     dword ptr [rax+rax]
    220     */
    221     ULONG32            Offset_SSDTFunctionIndex = 1;
    222 #endif
    223     
    224 
    225     *SSDTFunctionIndex = -1;
    226     IsOk = Ring0MappingPEFile(szFileFullPath, &MappingBaseAddress, &MappingViewSize);
    227     if (IsOk == FALSE)
    228     {
    229         return FALSE;
    230     }
    231     else
    232     {
    233         __try {
    234             Image_Nt_Headers = RtlImageNtHeader(MappingBaseAddress);    //extern进来
    235             if (Image_Nt_Headers&&Image_Nt_Headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
    236             {
    237                 ImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((char*)MappingBaseAddress
    238                     + Image_Nt_Headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    239 
    240                 AddressOfFunctions = (UINT32*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfFunctions);
    241                 //函数的地址(RVA)
    242                 AddressOfNames = (UINT32*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfNames);;
    243                 //函数名字的地址(RVA)
    244                 AddressOfNameOrdinals = (UINT16*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfNameOrdinals);
    245                 //有名字的序号的首地址(RVA)
    246                 for (i = 0; i < ImageExportDirectory->NumberOfNames; i++)
    247                 {
    248                     v1 = (char*)((char*)MappingBaseAddress + AddressOfNames[i]); //可以这样写 ImageExportDirectory->AddressOfNames + i * 4
    249                     if (_stricmp(szFuntionName, v1) == 0)
    250                     {
    251                         OrdinalOfFunction = AddressOfNameOrdinals[i];
    252                         AddressOfFunction = (PVOID)((char*)MappingBaseAddress + AddressOfFunctions[OrdinalOfFunction]);//AddressOfFunctions[AddressOfNameOrdinals[i]]
    253                         *SSDTFunctionIndex = *(ULONG32*)((char*)AddressOfFunction + Offset_SSDTFunctionIndex);
    254                         break;
    255                     }
    256                 }
    257             }
    258         }
    259         __except(EXCEPTION_EXECUTE_HANDLER)
    260         {}
    261 
    262     }
    263     ZwUnmapViewOfSection(NtCurrentProcess(), MappingBaseAddress);
    264     if (*SSDTFunctionIndex == -1)
    265     {
    266         return FALSE;
    267     }
    268     return TRUE;
    269 }
    270                             //函数需要,所以传双字            二维指针
    271 BOOLEAN     Ring0MappingPEFile(WCHAR* szFileFullPath, PVOID* MappingBaseAddress, ULONG_PTR* MappingViewSize)
    272 {
    273     NTSTATUS            Status;
    274     UNICODE_STRING        Temp;
    275     OBJECT_ATTRIBUTES    oa;
    276     HANDLE                hFile = NULL;
    277     HANDLE                hSection = NULL;
    278     IO_STATUS_BLOCK        IoStatusBlock;
    279 
    280     if (!szFileFullPath&&MmIsAddressValid(szFileFullPath))
    281     {
    282         return FALSE;
    283     }
    284     if (!MappingBaseAddress&&MmIsAddressValid(MappingBaseAddress))
    285     {
    286         return FALSE;
    287     }
    288     RtlUnicodeStringInit(&Temp, szFileFullPath);
    289     InitializeObjectAttributes(&oa,    //out
    290         &Temp,                    //in ObjectName
    291         OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,//被系统在和ObjectName比较匹配时不区分大小写||此句柄只能用于内核模式下
    292         NULL,                    //与ObjectName参数匹配的根目录对象,如果ObjectName是对象的全路径则设置此参数为NULL
    293         NULL                    //驱动程序可以使用NULL用于创建一个具有默认安全描述符的对象
    294         );
    295     //打开文件,获得文件句柄
    296     Status = IoCreateFile(&hFile,
    297         GENERIC_READ | SYNCHRONIZE, //可读|同步
    298         &oa,
    299         &IoStatusBlock,            //返回I/O请求的完成情况
    300         NULL,
    301         FILE_ATTRIBUTE_NORMAL,
    302         FILE_SHARE_READ,
    303         FILE_OPEN,
    304         FILE_SYNCHRONOUS_IO_NONALERT,
    305         NULL,
    306         0,
    307         CreateFileTypeNone,
    308         NULL,
    309         IO_NO_PARAMETER_CHECKING
    310         );
    311     if (!NT_SUCCESS(Status))
    312     {
    313         return    FALSE;
    314     }
    315     oa.ObjectName = NULL;
    316     Status = ZwCreateSection(&hSection,
    317         SECTION_QUERY | SECTION_MAP_READ,
    318         &oa,
    319         NULL,
    320         PAGE_WRITECOPY,
    321         SEC_IMAGE,//内存按1M对齐 0x1000 000
    322         hFile
    323         );
    324     ZwClose(hFile);
    325     if (!NT_SUCCESS(Status))
    326     {
    327         return FALSE;
    328     }
    329     Status = ZwMapViewOfSection(hSection,
    330         NtCurrentProcess(),
    331         MappingBaseAddress,
    332         0,
    333         0,
    334         0,
    335         MappingViewSize,
    336         ViewUnmap,            //不能被映射到子进程中
    337         0,
    338         PAGE_WRITECOPY
    339         );
    340     ZwClose(hSection);
    341     if (!NT_SUCCESS(Status))
    342     {
    343         return FALSE;
    344     }
    345     return TRUE;
    346 }
    347 
    348 ULONG32    CalcFunctionOffsetInSSDT(PVOID ServiceTableBase, PVOID FunctionAddress, ULONG32 ParamterCount)
    349 {
    350     //完全没必要像下面这样折腾,就是一个做个SSDT表中类似的地址,有时间自己写一个
    351     ULONG32  Offset = 0;
    352     CHAR     Temp = 0;
    353     CHAR     Bits[4] = { 0 };
    354     int      i = 0;
    355     Offset = (ULONG32)((ULONG64)FunctionAddress - (ULONG64)ServiceTableBase);
    356     Offset = Offset << 4;
    357     if (ParamterCount > 4)
    358     {
    359         ParamterCount = ParamterCount-4;     //NtReadFile  9个参数  和参数压栈有关
    360     }
    361     else
    362     {
    363         ParamterCount = 0;
    364     }                                    
    365     memcpy(&Temp, &Offset, 1);        // 1010 0010    <<4-----> 0010 0000 后面处理参数
    366 #define SETBIT(x,y) x|=(1<<y)         //将X的第Y位置1
    367 #define CLRBIT(x,y) x&=~(1<<y)        //将X的第Y位清0
    368 #define GETBIT(x,y) (x & (1 << y))    //取X的第Y位,返回0或非0
    369 
    370     for (i = 0; i < 4; i++)
    371     {
    372         Bits[i] = GETBIT(ParamterCount, i);
    373         if (Bits[i])
    374         {
    375             SETBIT(Temp, i);
    376         }
    377         else
    378         {
    379             CLRBIT(Temp, i);
    380         }
    381     }
    382     memcpy(&Offset, &Temp, 1);
    383     return Offset;
    384 }
    385 
    386 //write protect 第17位
    387 VOID WPOFF()
    388 {
    389     _disable();
    390     __writecr0(__readcr0() & (~(0x10000)));
    391 
    392 }
    393 
    394 VOID WPON()
    395 {
    396     __writecr0(__readcr0() ^ 0x10000);
    397     _enable();
    398 }
    399 
    400 VOID    HookSSDTInWin7_x64(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, PVOID MyFunctionAddress,
    401     PVOID OldFuntionAddress, ULONG32 OldFunctionParamterCount, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength)
    402 {
    403     ULONG32        MyOffset = 0;
    404     WPOFF();
    405     InlineHook(OldFuntionAddress, MyFunctionAddress, OldFunctionCode, PatchCodeLength);
    406     WPON();
    407 
    408     MyOffset = CalcFunctionOffsetInSSDT(ServiceTableBase, OldFuntionAddress, OldFunctionParamterCount);
    409     WPOFF();
    410     ((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = MyOffset;
    411     WPON();
    412 
    413     __IsHook = TRUE;
    414 }
    415 
    416 VOID    HookSSDTInWin7_x86(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 MyFunctionAddress)
    417 {
    418     WPOFF();
    419     ((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)MyFunctionAddress;
    420     WPON();
    421 
    422     __IsHook = TRUE;
    423 }
    424 
    425 VOID InlineHook(ULONG64 OldFuntionAddress, ULONG64 MyFunctionAddress, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength)
    426 {
    427     CHAR PatchCode[] = "xFFx25x00x00x00x00xFFxFFxFFxFFxFFxFFxFFxFF";  //神坑啊,脑残啊,写成PatchCode 到memcpy才崩溃
    428     ULONG64 Temp = MyFunctionAddress;
    429     memcpy(OldFunctionCode, (PVOID)OldFuntionAddress, PatchCodeLength); //保存原来的函数指令
    430     memcpy(PatchCode + 6, &Temp, 8);
    431     memset((PVOID)OldFuntionAddress, 0x90, PatchCodeLength);  //先全部打上NOP(计组)
    432     memcpy((PVOID)OldFuntionAddress, PatchCode, 14);
    433 }
    434 
    435 
    436 //SSDT HOOK的替换函数如何对访问进行过滤”比“如何实现SSDT HOOK”要复杂多了,详见ediary   HookNtOpenProcess后的事情
    437 NTSTATUS MyOpenProcess(
    438     _Out_    PHANDLE            ProcessHandle,
    439     _In_     ACCESS_MASK        DesiredAccess,
    440     _In_     POBJECT_ATTRIBUTES ObjectAttributes,
    441     _In_opt_ PCLIENT_ID         ClientId
    442     )
    443 {
    444     //EnumProcessByForce.exe
    445     //调用OpenProcess---->去NtDll导出表中寻找ntdll!NtOpenProcess或者ntdll!ZwOpenProcess 导出表有名称的索引---->切入内核-->跳板nt!ZwOpenProcess  Ntoskernl.exe(NtOpenProcess mov eax,23h SSDT[23h])
    446     // ---->KeCheckBugEx ---->Jmp MyOpenProcess
    447     PEPROCESS    EProcess = PsGetCurrentProcess(); //EnumProcessByForce.exe
    448     if (EProcess != NULL && MmIsAddressValid(EProcess))
    449     {
    450         char *szProcessImageFileName = PsGetProcessImageFileName(EProcess);
    451         if (strstr(szProcessImageFileName, "EnumProcess") != 0)
    452         {
    453             return STATUS_ACCESS_DENIED;    //黑名单中返回
    454         }
    455     }
    456     __OldNtOpenProcessAddress(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId); //白名单
    457                                                     //OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, i)
    458     //return STATUS_SUCCESS;      死循环
    459     //return STATUS_UNSUCCESSFUL;  阻塞      很有趣
    460 }
    461 
    462 VOID UnHookSSDTInWin7_x64(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionOffset, PVOID OldFunctionAddress,
    463     UCHAR* OldFunctionCode, ULONG32 PatchCodeLength)
    464 {
    465     WPOFF();
    466     UnlineHook(OldFunctionAddress, OldFunctionCode, PatchCodeLength);
    467     WPON();
    468 
    469     WPOFF();
    470     ((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)OldFunctionOffset;
    471     WPON();
    472 }
    473 
    474 VOID UnlineHook(PVOID OldFunctionAddress, CHAR* OldFunctionCode, ULONG32 PatchCodeLength)
    475 {
    476     memcpy((PVOID)OldFunctionAddress, OldFunctionCode, PatchCodeLength);
    477 }
    478 
    479 VOID UnHookSSDTInWin7_x86(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionAddress)
    480 {
    481     WPOFF();
    482     ((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)OldFunctionAddress;
    483     WPON();
    484 }
    DPCHookSSDT.c

    2. 接下来就是RemoveDPC了,首先我们要找到DPC,关于Win7以前的版本可以参考这份博客,讲解的很详细,http://bbs.pediy.com/thread-148135.htm

    win7下定时器链表被放在KPRCB结构中,64位下,在KPRCB+0x2200的位置:

    相关结构:

    所以大体流程就是:取KPRCB地址,+0x2200偏移得到_KTIMER_TABLE,+0x200偏移得到_KTIMER_TABLE.TimerEntries
    最后遍历_KTIMER_TABLE.TimerEntries.Entry 。32位下类似,只是偏移不同。

    那么现在关键是获得KPRCB地址,那怎么获得呢?

    每一个CPU中都有一个KPRCB结构地址,它保存在KiProcessorBlock全局变量中。

     而KiProcessorBlock在KdDebuggerData64这个结构中,KdDebuggerData64可以从KdVersionBlock中得到。方法如下:

    KdVersionBlock在KPCR中位置如图所示,这里需要注意,对于多处理器的环境下,如果想正确获取KdVersionBlock的值,必须保证当前的线程运行在1号处理器上。

    具体原因可查看这份博客:http://www.youranshare.com/push/code/win-c-cpp/439.html

    然后查看KdVersionBlock结构,最下面的便是KdDebuggerData64结构。

    从wrk上查看KdDebuggerData64结构体的定义,发现KiProcessorBlock在0x218h的偏移处。

      1 DO NOT ADD OR REMOVE FIELDS FROM THE MIDDLE OF THIS STRUCTURE!!!
      2 //
      3 // If you remove a field, replace it with an "unused" placeholder.
      4 // Do not reuse fields until there has been enough time for old debuggers
      5 // and extensions to age out.
      6 //
      7 typedef struct _KDDEBUGGER_DATA64 {
      8 
      9     DBGKD_DEBUG_DATA_HEADER64 Header;
     10 
     11     //
     12     // Base address of kernel image
     13     //
     14 
     15     ULONG64   KernBase;
     16 
     17     //
     18     // DbgBreakPointWithStatus is a function which takes an argument
     19     // and hits a breakpoint.  This field contains the address of the
     20     // breakpoint instruction.  When the debugger sees a breakpoint
     21     // at this address, it may retrieve the argument from the first
     22     // argument register, or on x86 the eax register.
     23     //
     24 
     25     ULONG64   BreakpointWithStatus;       // address of breakpoint
     26 
     27     //
     28     // Address of the saved context record during a bugcheck
     29     //
     30     // N.B. This is an automatic in KeBugcheckEx's frame, and
     31     // is only valid after a bugcheck.
     32     //
     33 
     34     ULONG64   SavedContext;
     35 
     36     //
     37     // help for walking stacks with user callbacks:
     38     //
     39 
     40     //
     41     // The address of the thread structure is provided in the
     42     // WAIT_STATE_CHANGE packet.  This is the offset from the base of
     43     // the thread structure to the pointer to the kernel stack frame
     44     // for the currently active usermode callback.
     45     //
     46 
     47     USHORT  ThCallbackStack;            // offset in thread data
     48 
     49     //
     50     // these values are offsets into that frame:
     51     //
     52 
     53     USHORT  NextCallback;               // saved pointer to next callback frame
     54     USHORT  FramePointer;               // saved frame pointer
     55 
     56     //
     57     // pad to a quad boundary
     58     //
     59     USHORT  PaeEnabled:1;
     60 
     61     //
     62     // Address of the kernel callout routine.
     63     //
     64 
     65     ULONG64   KiCallUserMode;             // kernel routine
     66 
     67     //
     68     // Address of the usermode entry point for callbacks.
     69     //
     70 
     71     ULONG64   KeUserCallbackDispatcher;   // address in ntdll
     72 
     73 
     74     //
     75     // Addresses of various kernel data structures and lists
     76     // that are of interest to the kernel debugger.
     77     //
     78 
     79     ULONG64   PsLoadedModuleList;
     80     ULONG64   PsActiveProcessHead;
     81     ULONG64   PspCidTable;
     82 
     83     ULONG64   ExpSystemResourcesList;
     84     ULONG64   ExpPagedPoolDescriptor;
     85     ULONG64   ExpNumberOfPagedPools;
     86 
     87     ULONG64   KeTimeIncrement;
     88     ULONG64   KeBugCheckCallbackListHead;
     89     ULONG64   KiBugcheckData;
     90 
     91     ULONG64   IopErrorLogListHead;
     92 
     93     ULONG64   ObpRootDirectoryObject;
     94     ULONG64   ObpTypeObjectType;
     95 
     96     ULONG64   MmSystemCacheStart;
     97     ULONG64   MmSystemCacheEnd;
     98     ULONG64   MmSystemCacheWs;
     99 
    100     ULONG64   MmPfnDatabase;
    101     ULONG64   MmSystemPtesStart;
    102     ULONG64   MmSystemPtesEnd;
    103     ULONG64   MmSubsectionBase;
    104     ULONG64   MmNumberOfPagingFiles;
    105 
    106     ULONG64   MmLowestPhysicalPage;
    107     ULONG64   MmHighestPhysicalPage;
    108     ULONG64   MmNumberOfPhysicalPages;
    109 
    110     ULONG64   MmMaximumNonPagedPoolInBytes;
    111     ULONG64   MmNonPagedSystemStart;
    112     ULONG64   MmNonPagedPoolStart;
    113     ULONG64   MmNonPagedPoolEnd;
    114 
    115     ULONG64   MmPagedPoolStart;
    116     ULONG64   MmPagedPoolEnd;
    117     ULONG64   MmPagedPoolInformation;
    118     ULONG64   MmPageSize;
    119 
    120     ULONG64   MmSizeOfPagedPoolInBytes;
    121 
    122     ULONG64   MmTotalCommitLimit;
    123     ULONG64   MmTotalCommittedPages;
    124     ULONG64   MmSharedCommit;
    125     ULONG64   MmDriverCommit;
    126     ULONG64   MmProcessCommit;
    127     ULONG64   MmPagedPoolCommit;
    128     ULONG64   MmExtendedCommit;
    129 
    130     ULONG64   MmZeroedPageListHead;
    131     ULONG64   MmFreePageListHead;
    132     ULONG64   MmStandbyPageListHead;
    133     ULONG64   MmModifiedPageListHead;
    134     ULONG64   MmModifiedNoWritePageListHead;
    135     ULONG64   MmAvailablePages;
    136     ULONG64   MmResidentAvailablePages;
    137 
    138     ULONG64   PoolTrackTable;
    139     ULONG64   NonPagedPoolDescriptor;
    140 
    141     ULONG64   MmHighestUserAddress;
    142     ULONG64   MmSystemRangeStart;
    143     ULONG64   MmUserProbeAddress;
    144 
    145     ULONG64   KdPrintCircularBuffer;
    146     ULONG64   KdPrintCircularBufferEnd;
    147     ULONG64   KdPrintWritePointer;
    148     ULONG64   KdPrintRolloverCount;
    149 
    150     ULONG64   MmLoadedUserImageList;
    151 
    152     // NT 5.1 Addition
    153 
    154     ULONG64   NtBuildLab;
    155     ULONG64   KiNormalSystemCall;
    156 
    157     // NT 5.0 QFE addition
    158 
    159     ULONG64   KiProcessorBlock;
    160     ULONG64   MmUnloadedDrivers;
    161     ULONG64   MmLastUnloadedDriver;
    162     ULONG64   MmTriageActionTaken;
    163     ULONG64   MmSpecialPoolTag;
    164     ULONG64   KernelVerifier;
    165     ULONG64   MmVerifierData;
    166     ULONG64   MmAllocatedNonPagedPool;
    167     ULONG64   MmPeakCommitment;
    168     ULONG64   MmTotalCommitLimitMaximum;
    169     ULONG64   CmNtCSDVersion;
    170 
    171     // NT 5.1 Addition
    172 
    173     ULONG64   MmPhysicalMemoryBlock;
    174     ULONG64   MmSessionBase;
    175     ULONG64   MmSessionSize;
    176     ULONG64   MmSystemParentTablePage;
    177 
    178     // Server 2003 addition
    179 
    180     ULONG64   MmVirtualTranslationBase;
    181 
    182     USHORT    OffsetKThreadNextProcessor;
    183     USHORT    OffsetKThreadTeb;
    184     USHORT    OffsetKThreadKernelStack;
    185     USHORT    OffsetKThreadInitialStack;
    186 
    187     USHORT    OffsetKThreadApcProcess;
    188     USHORT    OffsetKThreadState;
    189     USHORT    OffsetKThreadBStore;
    190     USHORT    OffsetKThreadBStoreLimit;
    191 
    192     USHORT    SizeEProcess;
    193     USHORT    OffsetEprocessPeb;
    194     USHORT    OffsetEprocessParentCID;
    195     USHORT    OffsetEprocessDirectoryTableBase;
    196 
    197     USHORT    SizePrcb;
    198     USHORT    OffsetPrcbDpcRoutine;
    199     USHORT    OffsetPrcbCurrentThread;
    200     USHORT    OffsetPrcbMhz;
    201 
    202     USHORT    OffsetPrcbCpuType;
    203     USHORT    OffsetPrcbVendorString;
    204     USHORT    OffsetPrcbProcStateContext;
    205     USHORT    OffsetPrcbNumber;
    206 
    207     USHORT    SizeEThread;
    208 
    209     ULONG64   KdPrintCircularBufferPtr;
    210     ULONG64   KdPrintBufferSize;
    211 
    212     ULONG64   KeLoaderBlock;
    213 
    214     USHORT    SizePcr;
    215     USHORT    OffsetPcrSelfPcr;
    216     USHORT    OffsetPcrCurrentPrcb;
    217     USHORT    OffsetPcrContainedPrcb;
    218 
    219     USHORT    OffsetPcrInitialBStore;
    220     USHORT    OffsetPcrBStoreLimit;
    221     USHORT    OffsetPcrInitialStack;
    222     USHORT    OffsetPcrStackLimit;
    223 
    224     USHORT    OffsetPrcbPcrPage;
    225     USHORT    OffsetPrcbProcStateSpecialReg;
    226     USHORT    GdtR0Code;
    227     USHORT    GdtR0Data;
    228 
    229     USHORT    GdtR0Pcr;
    230     USHORT    GdtR3Code;
    231     USHORT    GdtR3Data;
    232     USHORT    GdtR3Teb;
    233 
    234     USHORT    GdtLdt;
    235     USHORT    GdtTss;
    236     USHORT    Gdt64R3CmCode;
    237     USHORT    Gdt64R3CmTeb;
    238 
    239     ULONG64   IopNumTriageDumpDataBlocks;
    240     ULONG64   IopTriageDumpDataBlocks;
    241 
    242 } KDDEBUGGER_DATA64, *PKDDEBUGGER_DATA64;
    KdDebuggerData64

    相应的代码:(通常在内核模式下段寄存器FS指向的是KPCR结构,用户模式下指向的是TEB结构)

    而我调试64位的时候发现,KdVersionBlock都为null,那我们就不能用上面的方法去得KPRCB了,

    不过我们却发现,在msr寄存器的0xC0000101处,存的是KPCR,我们直接_KPCR+偏移0x20就得到KPRCB了。

    结构体中的Self是自己的地址,CurrentPrcb是KPRCB的地址。

    最后回到正题,我们通过遍历KTIMER_TABLE.TimerEntries.Entry链表,利用CONTAINING_RECORD得到KTIMER结构,判断它的地址是否在我们sys模块地址范围内即可。最后KeCancelTimer掉它。

     

    (第一个地址是KTIMER,第二个地址是sys的基地址,判断是否落入范围)

    代码如下:

     1 #include <ntifs.h>
     2 
     3 typedef struct _KTIMER_TABLE_ENTRY
     4 {
     5     ULONG_PTR            Lock;
     6     LIST_ENTRY        Entry;
     7     ULARGE_INTEGER    Time;
     8 } KTIMER_TABLE_ENTRY, *PKTIMER_TABLE_ENTRY;
     9 
    10 typedef struct _LDR_DATA_TABLE_ENTRY64
    11 {
    12     LIST_ENTRY64    InLoadOrderLinks;
    13     LIST_ENTRY64    InMemoryOrderLinks;
    14     LIST_ENTRY64    InInitializationOrderLinks;
    15     PVOID            DllBase;
    16     PVOID            EntryPoint;
    17     ULONG            SizeOfImage;
    18     UNICODE_STRING    FullDllName;
    19     UNICODE_STRING     BaseDllName;
    20     ULONG            Flags;
    21     USHORT            LoadCount;
    22     USHORT            TlsIndex;
    23     PVOID            SectionPointer;
    24     ULONG            CheckSum;
    25     PVOID            LoadedImports;
    26     PVOID            EntryPointActivationContext;
    27     PVOID            PatchInformation;
    28     LIST_ENTRY64    ForwarderLinks;
    29     LIST_ENTRY64    ServiceTagLinks;
    30     LIST_ENTRY64    StaticLinks;
    31     PVOID            ContextInformation;
    32     ULONG64            OriginalBase;
    33     LARGE_INTEGER    LoadTime;
    34 } LDR_DATA_TABLE_ENTRY64, *PLDR_DATA_TABLE_ENTRY64;
    35 
    36 
    37 
    38 typedef struct _LDR_DATA_TABLE_ENTRY32
    39 {
    40     LIST_ENTRY32 InLoadOrderLinks;
    41     LIST_ENTRY32 InMemoryOrderLinks;
    42     LIST_ENTRY32 InInitializationOrderLinks;
    43     ULONG DllBase;
    44     ULONG EntryPoint;
    45     ULONG SizeOfImage;
    46     UNICODE_STRING32 FullDllName;
    47     UNICODE_STRING32 BaseDllName;
    48     ULONG Flags;
    49     USHORT LoadCount;
    50     USHORT TlsIndex;
    51     union {
    52         LIST_ENTRY32 HashLinks;
    53         struct {
    54             ULONG SectionPointer;
    55             ULONG  CheckSum;
    56         };
    57     };
    58     union {
    59         struct {
    60             ULONG  TimeDateStamp;
    61         };
    62         struct {
    63             ULONG LoadedImports;
    64         };
    65     };
    66 } LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32;
    67 
    68 
    69 #ifdef _WIN64
    70 #define LDR_DATA_TABLE_ENTRY LDR_DATA_TABLE_ENTRY64
    71 #define PLDR_DATA_TABLE_ENTRY PLDR_DATA_TABLE_ENTRY64
    72 #else
    73 #define LDR_DATA_TABLE_ENTRY LDR_DATA_TABLE_ENTRY32
    74 #define PLDR_DATA_TABLE_ENTRY PLDR_DATA_TABLE_ENTRY32
    75 #endif
    76 
    77 VOID DriverUnload(PDRIVER_OBJECT DriverObject);
    78 
    79 NTSTATUS GetKernelModuleInformationByKernelModuleName(PDRIVER_OBJECT DriverObject, WCHAR* wzKernelModuleName, PVOID* KernelModuleBase, ULONG_PTR* KernelModuleSize);
    80 
    81 PVOID
    82 GetExportVariableAddressFromNtosKrnlExportTableByVariableName(WCHAR* wzVariableName);
    83 
    84 BOOLEAN    GetKiWaitVariableAddress(PULONG64* KiWaitNever, PULONG64* KiWaitAlways);
    85 
    86 KDPC* TransTimerDPCEx(PKTIMER Timer, ULONG64 KiWaitNever, ULONG64 KiWaitAlways);
    87 
    88 PULONG GetKiProcessorBlock();
    89 
    90 BOOLEAN    GetDPCTimerInfoByModuleInfo(PVOID KernelModuleBase, ULONG_PTR KernelModuleSize, ULONG_PTR* Timer);
    91 BOOLEAN    RemoveDPCFromNtos(PVOID KernelModuleBase, ULONG_PTR KernelModuleSize);
    RemoveDPC.h
      1 #include "RemoveDPC.h"
      2 #include <ntstrsafe.h>
      3 //bp RemoveDPC!DriverEntry
      4 
      5 PVOID    __KernelModuleBase = NULL;
      6 ULONG_PTR    __KernelModuleSize = 0;
      7 
      8 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
      9 {
     10     NTSTATUS Status = STATUS_SUCCESS;
     11     PDEVICE_OBJECT  DeviceObject = NULL;
     12     DbgPrint("DriverSuccuss
    ");
     13     DriverObject->DriverUnload = DriverUnload;
     14 
     15     WCHAR        wzKernelModuleName[] = L"NewDPCHookSSDT.sys";
     16     if (GetKernelModuleInformationByKernelModuleName(DriverObject, wzKernelModuleName, &__KernelModuleBase, &__KernelModuleSize) == STATUS_UNSUCCESSFUL)
     17     {
     18         return STATUS_UNSUCCESSFUL;
     19     }
     20     RemoveDPCFromNtos(__KernelModuleBase, __KernelModuleSize);
     21     return Status;
     22 }
     23 
     24 
     25 NTSTATUS GetKernelModuleInformationByKernelModuleName(PDRIVER_OBJECT DriverObject,WCHAR* wzKernelModuleName,PVOID* KernelModuleBase,ULONG_PTR* KernelModuleSize)
     26 {
     27     PLDR_DATA_TABLE_ENTRY    CurrentEntry = NULL;
     28     PLDR_DATA_TABLE_ENTRY    NextEntry = NULL;
     29     if (DriverObject&&MmIsAddressValid(DriverObject))
     30     {
     31         CurrentEntry = (PLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection;
     32         NextEntry = (PLDR_DATA_TABLE_ENTRY)CurrentEntry->InLoadOrderLinks.Flink;
     33         while (NextEntry != CurrentEntry)
     34         {
     35             if (NextEntry->BaseDllName.Length >= wcslen(wzKernelModuleName))
     36             {
     37                 if (NextEntry->BaseDllName.Buffer
     38                     &&MmIsAddressValid((PVOID)NextEntry->BaseDllName.Buffer)
     39                     && !_wcsnicmp(wzKernelModuleName, (WCHAR*)NextEntry->BaseDllName.Buffer, wcslen(wzKernelModuleName)))  //这里掉坑了,wcsnicmp是比较函数,相等时返回0,
     40                                                                                                                          //再次掉坑,第三个参数表示比较的的字母的个数,如果是0,肯定相等
     41                 {
     42                     DbgPrint("%S
    ", wzKernelModuleName);
     43                     DbgPrint("%S
    ", (WCHAR*)NextEntry->BaseDllName.Buffer);
     44                     *KernelModuleBase = NextEntry->DllBase;
     45                     *KernelModuleSize = NextEntry->SizeOfImage;
     46                     return STATUS_SUCCESS;
     47                 }
     48             }
     49             NextEntry = (PLDR_DATA_TABLE_ENTRY)NextEntry->InLoadOrderLinks.Flink;
     50         }
     51     }
     52     return STATUS_UNSUCCESSFUL;
     53 }
     54 
     55 BOOLEAN    RemoveDPCFromNtos(PVOID KernelModuleBase, ULONG_PTR KernelModuleSize)
     56 {
     57     ULONG_PTR  Timer = NULL;
     58     if (GetDPCTimerInfoByModuleInfo(KernelModuleBase, KernelModuleSize, &Timer) == FALSE)
     59     {
     60         return FALSE;
     61     }
     62     if (Timer && MmIsAddressValid(Timer))
     63     {
     64         if (KeCancelTimer(Timer))
     65         {
     66             return TRUE;
     67         }
     68     }
     69     return FALSE;
     70 }
     71 
     72                          
     73 PULONG GetKiProcessorBlock()
     74 {
     75     ULONG* KiProcessorBlock = 0;
     76 
     77     KeSetSystemAffinityThread(1); //使当前线程运行在第一个处理器上  
     78 
     79     _asm
     80     {
     81         push eax
     82         mov  eax, FS:[0x34]; 得到KdVersionBlock的地址
     83             add  eax, 20h; 得到指向DebuggerDataList的地址
     84             mov  eax, [eax]; 得到DebuggerDataList的地址
     85             mov  eax, [eax]; 取出里面的内容,即KdDebuggerData64结构
     86             mov  eax, [eax + 218h]; 取出KiProcessBlock的地址
     87             mov  KiProcessorBlock, eax;放到变量里
     88             pop  eax
     89     }
     90 
     91     KeRevertToUserAffinityThread();
     92 
     93     return KiProcessorBlock;
     94 
     95 }
     96 
     97 BOOLEAN    GetDPCTimerInfoByModuleInfo(PVOID KernelModuleBase, ULONG_PTR KernelModuleSize,ULONG_PTR* Timer)
     98 {
     99     ULONG32 NumberOfProcessors = KeNumberProcessors;        //一般运行在第一个CPU上
    100     ULONG_PTR    KPRCB = 0;
    101     PUCHAR        TimerEntries = NULL;
    102     PULONG_PTR    KiWaitNever = NULL;
    103     PULONG_PTR    KiWaitAlways = NULL;
    104     PLIST_ENTRY    CurrentEntry = NULL;
    105     PLIST_ENTRY    NextEntry = NULL;
    106     PKTIMER        MyTimer = NULL;
    107     int i = 0;
    108     KIRQL OldIrql = KeRaiseIrqlToDpcLevel();
    109 #ifdef _WIN64
    110 
    111     KeSetSystemAffinityThread(1);        //使当前线程运行在第一个CPU上
    112     KPRCB = (ULONG64)__readmsr(0xC0000101) + 0x20;    //msr(0xC0000101)处位置存的是KPCR
    113     KeRevertToUserAffinityThread();
    114     TimerEntries = (PUCHAR)(*(ULONG64*)KPRCB + 0x2200 + 0x200);
    115     if (GetKiWaitVariableAddress(&KiWaitNever, &KiWaitAlways) == FALSE)
    116     {
    117         return FALSE;
    118     }
    119     for (i = 0; i < 0x100; i++)
    120     {
    121         CurrentEntry = (PLIST_ENTRY)(TimerEntries + sizeof(KTIMER_TABLE_ENTRY)*i + 8);
    122         NextEntry = CurrentEntry->Blink;
    123         if (MmIsAddressValid(CurrentEntry) && MmIsAddressValid(NextEntry))
    124         {
    125             while (NextEntry != CurrentEntry)
    126             {
    127                 PKDPC    RealDPC;
    128                 MyTimer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
    129 
    130                 RealDPC = TransTimerDPCEx(MyTimer, *KiWaitNever, *KiWaitAlways);
    131                 if (MmIsAddressValid(MyTimer) && MmIsAddressValid(RealDPC) && MmIsAddressValid(RealDPC->DeferredRoutine))
    132                 {
    133                     if ((ULONG64)MyTimer >= (ULONG64)KernelModuleBase && (ULONG64)MyTimer <= (ULONG64)KernelModuleBase + KernelModuleSize)
    134                     {
    135                         *Timer = (ULONG64)MyTimer;
    136                         KeLowerIrql(OldIrql);
    137                         return TRUE;
    138                     }
    139                 }
    140                 NextEntry = NextEntry->Blink;
    141             }
    142         }
    143     }
    144 #else
    145     PULONG                      KiProcessorBlock = NULL;
    146     KiProcessorBlock = (PULONG)GetKiProcessorBlock();
    147     TimerEntries = (PUCHAR)(*KiProcessorBlock + 0x1960 + 0x40);
    148     for (i = 0; i < 0x100; i++)
    149     {
    150         CurrentEntry = (PLIST_ENTRY)(TimerEntries + sizeof(KTIMER_TABLE_ENTRY)*i + 4);
    151         NextEntry = CurrentEntry->Blink;
    152         if (MmIsAddressValid(CurrentEntry) && MmIsAddressValid(NextEntry))
    153         {
    154             while (NextEntry != CurrentEntry)
    155             {
    156                 MyTimer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
    157 
    158                 if (MmIsAddressValid(MyTimer) && MmIsAddressValid(MyTimer->Dpc) && MmIsAddressValid(MyTimer->Dpc->DeferredRoutine))
    159                 {
    160                     if ((ULONG32)MyTimer >= (ULONG32)KernelModuleBase && (ULONG32)MyTimer <= (ULONG32)KernelModuleBase + KernelModuleSize)
    161                     {
    162                         *Timer = (ULONG32)MyTimer;
    163                         KeLowerIrql(OldIrql);
    164                         return TRUE;
    165                     }
    166                 }
    167                 NextEntry = NextEntry->Blink;
    168             }
    169         }
    170     }
    171 
    172 #endif
    173     
    174     
    175     KeLowerIrql(OldIrql);
    176     return FALSE;
    177 }
    178 
    179 
    180 
    181 KDPC* TransTimerDPCEx(PKTIMER Timer, ULONG64 KiWaitNever, ULONG64 KiWaitAlways)
    182 {
    183     ULONG64            DPC = (ULONG64)Timer->Dpc;     //Time 
    184     DPC ^= KiWaitNever;
    185     DPC = _rotl64(DPC, (UCHAR)(KiWaitNever & 0xFF));
    186     DPC ^= (ULONG64)Timer;
    187     DPC = _byteswap_uint64(DPC);
    188     DPC ^= KiWaitAlways;
    189     return (KDPC*)DPC;
    190 }
    191 
    192 BOOLEAN    GetKiWaitVariableAddress(PULONG64* KiWaitNever, PULONG64* KiWaitAlways)
    193 {
    194     /*
    195     kd> u kesettimer l 50
    196     nt!KeSetTimer:
    197     fffff800`03ef10a8 4883ec38        sub     rsp,38h
    198     fffff800`03ef10ac 4c89442420      mov     qword ptr [rsp+20h],r8
    199     fffff800`03ef10b1 4533c9          xor     r9d,r9d
    200     fffff800`03ef10b4 4533c0          xor     r8d,r8d
    201     fffff800`03ef10b7 e814000000      call    nt!KiSetTimerEx (fffff800`03ef10d0)
    202     fffff800`03ef10bc 4883c438        add     rsp,38h
    203     fffff800`03ef10c0 c3              ret
    204     fffff800`03ef10c1 90              nop
    205     fffff800`03ef10c2 90              nop
    206     fffff800`03ef10c3 90              nop
    207     fffff800`03ef10c4 90              nop
    208     fffff800`03ef10c5 90              nop
    209     fffff800`03ef10c6 90              nop
    210     fffff800`03ef10c7 90              nop
    211     nt!KxWaitForLockChainValid:
    212     fffff800`03ef10c8 90              nop
    213     fffff800`03ef10c9 90              nop
    214     fffff800`03ef10ca 90              nop
    215     fffff800`03ef10cb 90              nop
    216     fffff800`03ef10cc 90              nop
    217     fffff800`03ef10cd 90              nop
    218     fffff800`03ef10ce 90              nop
    219     fffff800`03ef10cf 90              nop
    220     nt!KiSetTimerEx:
    221     fffff800`03ef10d0 48895c2408      mov     qword ptr [rsp+8],rbx
    222     fffff800`03ef10d5 4889542410      mov     qword ptr [rsp+10h],rdx
    223     fffff800`03ef10da 55              push    rbp
    224     fffff800`03ef10db 56              push    rsi
    225     fffff800`03ef10dc 57              push    rdi
    226     fffff800`03ef10dd 4154            push    r12
    227     fffff800`03ef10df 4155            push    r13
    228     fffff800`03ef10e1 4156            push    r14
    229     fffff800`03ef10e3 4157            push    r15
    230     fffff800`03ef10e5 4883ec50        sub     rsp,50h
    231     fffff800`03ef10e9 488b0518502200  mov     rax,qword ptr [nt!KiWaitNever (fffff800`04116108)]
    232     fffff800`03ef10f0 488b1de9502200  mov     rbx,qword ptr [nt!KiWaitAlways (fffff800`041161e0)]
    233     */
    234     ULONG64        KeSetTimer = 0;
    235     PUCHAR        StartSearchAddress = 0;
    236     PUCHAR        EndSearchAddress = 0;
    237     ULONG64        iOffset = 0;
    238     PUCHAR        i = NULL;
    239     KeSetTimer = (ULONG64)GetExportVariableAddressFromNtosKrnlExportTableByVariableName(L"KeSetTimer");
    240     
    241     StartSearchAddress = (PUCHAR)KeSetTimer;
    242     EndSearchAddress = StartSearchAddress + 0x500;
    243 
    244     for (i = StartSearchAddress; i < EndSearchAddress; i++)
    245     {
    246         if (*i == 0x48 && *(i + 1) == 0x8B && *(i + 2) == 0x05)
    247         {
    248             memcpy(&iOffset, i + 3, 4);
    249             *KiWaitNever = (PULONG64)(iOffset + (ULONG64)i + 7);
    250             i = i + 7;
    251             memcpy(&iOffset, i + 3, 4);
    252             *KiWaitAlways = (PULONG64)(iOffset + (ULONG64)i + 7);
    253             return TRUE;
    254         }
    255     }
    256 
    257     return FALSE;
    258 }
    259 
    260 PVOID
    261 GetExportVariableAddressFromNtosKrnlExportTableByVariableName(WCHAR* wzVariableName)
    262 {
    263     //通过导出变量名字从NtosKrnl中获得导出变量地址
    264     UNICODE_STRING    uniVariableName;
    265     PVOID            VariableAddress = NULL;
    266 
    267     if (wzVariableName&&wcslen(wzVariableName) > 0)
    268     {
    269         RtlUnicodeStringInit(&uniVariableName, wzVariableName);
    270         //从Ntos模块的导出表中获得导出变量的地址
    271         VariableAddress = MmGetSystemRoutineAddress(&uniVariableName);
    272     }
    273     return VariableAddress;
    274 }
    275 
    276 VOID DriverUnload(PDRIVER_OBJECT DriverObject)
    277 {
    278     DbgPrint("Unload Success
    ");
    279 }
    RemoveDPC.c

    That's all.

  • 相关阅读:
    Flink实战(八十):FLINK-SQL使用基础(七)Flink SQL Clien读取Kafka数据流式写入Hive(用hive 管理kafka元数据)
    离线电商数仓(六十九)之即席查询(二)kylin使用
    离线电商数仓(六十八)之即席查询(一)kylin简介与安装
    离线电商数仓(六十七)之数据质量监控(三)Griffin(四) 安装及使用(二)
    离线电商数仓(六十六)之数据质量监控(二)Griffin(三) 安装及使用(一)
    Virtio-fs介绍与性能优化
    overlayfs mount shared =+ kata + OCI bundle rootfs
    Getting started with containerd
    Container Runtime
    containerd
  • 原文地址:https://www.cnblogs.com/littlepear/p/6733145.html
Copyright © 2020-2023  润新知