暂停系统中任意驱动的时钟--StopIoTimer

这篇文章主要说暂停IoTimer,可能有人说直接调用IoStopTimer就好了,不过,这篇文章说的是如何通过自己的驱动程序去停止其他驱动的时钟,比如说现在正在运行的一个驱动叫IoTimer.sys(上一篇文章介绍的的驱动程序),现在我们想要暂停它里面的时钟,在不卸载驱动的情况下,我们该怎么做呢?

现在我们就介绍一下方法:
在系统中,有一根双向链表链接这系统中的所有IoTimer,画张示意图说明一下:

暂停系统中任意驱动的时钟--StopIoTimer_第1张图片

现在有两个问题要解决:
1.怎么找到这个链表呢?
2.遍历链表,怎么确定哪个IoTimer就是IoTimer.sys里面的IoTimer呢*(IoTimer.sys是上一篇写的介绍IoTimer的使用示例生成的驱动,不知道的可以看一下上一篇博客)

现在我们一个一个问题解决:

第一个问题,找到链表头不就找到链表了嘛
现在分x86和x64两种情况说明怎么找链表头

x64
在IoInitializeTimer这个函数里面有一句代码
fffff800042db450 488d0d4974e0ff lea rcx,[nt!IopTimerQueueHead (fffff800040e28a0)]
暂停系统中任意驱动的时钟--StopIoTimer_第2张图片

IopTimerQueueHead 这个就是链表头节点
我们只要找到IoInitializeTimer这个函数,这个函数地址通过MmGetSystemRoutineAddress这个系统例程就可以得到,得到函数地址之后往下搜索, 找到488d0d后,得到488d0d后面的4974e0ff,这是一个相对偏移,要计算一下才可得到绝对地址,
4974e0ff+fffff800`042db450+7 就是IopTimerQueueHead 的地址。

再说说x86的情况
暂停系统中任意驱动的时钟--StopIoTimer_第3张图片

IoInitializeTimer这个函数里面有一句代码
83f94648 b98083f683 mov ecx,offset nt!IopTimerQueueHead (83f68380)
通过MmGetSystemRoutineAddress这个系统例程得到IoInitializeTimer地址函数,往下搜索b9,找到b9后,b9后面的8083f683就是IopTimerQueueHead 的地址,x86下不用计算,直接获得绝对地址。

第一个问题解决了
现在我们说说第二个问题
这个问题在x86和x64下是一样的,我就不分开写了

我们看一下IoTimer结构体和回头再第一张图

暂停系统中任意驱动的时钟--StopIoTimer_第4张图片

暂停系统中任意驱动的时钟--StopIoTimer_第5张图片

发现这个结构体里面有一个成员是TimerRoutine,这个成员指向IoTimer所关联的派遣函数,就是我们上一片所写的TimerRoutine函数,
既然这样我们可以判断这个成员里面的地址是不是在IoTimer.sys的范围内,从而判断是不是我们想要的IoTimer。

什么意思呢,就是说,我们可以获得IoTimer.sys的模块基地址,记为ModuleBase,获得IoTimer.sys的模块大小,记为ModuleSize(怎么获得,我就不说了,具体可以看代码)
我们判断 TimerRoutine大于ModuleBase&&
TimerRoutineModuleBase+ModuleSize 条件成立,那就找到时钟了。

时钟都得到了,那它就任由我们处置了,直接调用IoStopTimer就可以暂停时钟了。

打完收工,现在看代码!

#pragma once
#include

typedef struct _LDR_DATA_TABLE_ENTRY
{
    LIST_ENTRY  InLoadOrderLinks;   // 加载顺序
    LIST_ENTRY  InMemoryOrderLinks; // 在内存中的顺序
    LIST_ENTRY  InInitializationOrderLinks; // 初始化顺序
    PVOID       DllBase;        // 模块的基地址
    PVOID       EntryPoint;     // DriverEntry
    ULONG32     SizeOfImage;    // 模块的大小
#ifdef _WIN64
    ULONG32   UnKnow0;
#endif
    UNICODE_STRING FullDllName; // 包含路径的名称
    UNICODE_STRING BaseDllName; // 不包含路径的名称
    UINT32      Flags;
    UINT16      LoadCount;
    UINT16      TlsIndex;
    union
    {
        LIST_ENTRY  HashLinks;
        struct
        {
            PVOID   SectionPointer;
            UINT32  CheckSum;
        };
    };
    union
    {
        UINT32      TimeDateStamp;
        PVOID       LoadedImports;
    };
    PVOID        EntryPointActivationContext; // _ACTIVATION_CONTEXT*
    PVOID        PatchInformation;
    LIST_ENTRY   ForwarderLinks;
    LIST_ENTRY   ServiceTagLinks;
    LIST_ENTRY   StaticLinks;
    PVOID        ContextInformation;
    ULONG_PTR    OriginalBase;
    LARGE_INTEGER  LoadTime;
}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

/*
Win7_x64
kd> dt _IO_TIMER
ntdll!_IO_TIMER
+0x000 Type             : Int2B
+0x002 TimerFlag        : Int2B
+0x008 TimerList        : _LIST_ENTRY
+0x018 TimerRoutine     : Ptr64     void
+0x020 Context          : Ptr64 Void
+0x028 DeviceObject     : Ptr64 _DEVICE_OBJECT
Win7_x86
kd> dt _IO_TIMER
ntdll!_IO_TIMER
+0x000 Type             : Int2B
+0x002 TimerFlag        : Int2B
+0x004 TimerList        : _LIST_ENTRY
+0x00c TimerRoutine     : Ptr32     void
+0x010 Context          : Ptr32 Void
+0x014 DeviceObject     : Ptr32 _DEVICE_OBJECT
*/

typedef struct _IO_TIMER
{
    CHAR Type[2];
    CHAR TimerFlag[2];
#ifdef _WIN64
    CHAR UnKnow[4];
#endif // _WIN64
    LIST_ENTRY ListEntry;
    PVOID TimerRoutine;
    PVOID Context;
    DEVICE_OBJECT* DeviceObject;
}IO_TIMER,*PIO_TIMER;


typedef
VOID(*pfnIoStopTimer)(
    _In_ PDEVICE_OBJECT DeviceObject
    );

VOID DriverUnload(PDRIVER_OBJECT DriverObject);
BOOLEAN GetKernelModuleInfoByDriverObject(PDRIVER_OBJECT DriverObject, WCHAR* ModuleName, PVOID* ModuleBase, ULONG_PTR* ModuleSize);
PVOID GetExportVariableAddressFromNtosExportTableByVariableName(WCHAR * VariableName);
BOOLEAN GetIoTimerInfoByModuleInfo(ULONG_PTR* Timer, ULONG_PTR ModuleBase, ULONG_PTR ModuleSize, PLIST_ENTRY* ListEntry);





#include"ResumeIoTimer.h"

pfnIoStopTimer __f1 = NULL;
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
{
    NTSTATUS   Status = STATUS_UNSUCCESSFUL;
    WCHAR      ModuleName[] = L"IoTimerInlineHookx86.sys";
    PVOID      ModuleBase = NULL;
    ULONG_PTR  ModuleSize = 0;
    ULONG_PTR  Timer;
    PLIST_ENTRY ListEntry = { 0 };
    DriverObject->DriverUnload = DriverUnload;
    if (GetKernelModuleInfoByDriverObject(DriverObject, ModuleName, &ModuleBase, &ModuleSize) == FALSE)
    {
        return Status;
    }
    DbgPrint("ModuleBase is %p \r\n", ModuleBase);
    DbgPrint("ModuleSize is %p \r\n", ModuleSize);


    if (GetIoTimerInfoByModuleInfo(&Timer, ModuleBase, ModuleSize, &ListEntry) == FALSE)
    {
        return Status;
    }

    // 停止时钟
    if (Timer != NULL&&MmIsAddressValid((PVOID)Timer))
    {
        IoStopTimer(((PIO_TIMER)Timer)->DeviceObject);
        /*
        要是害怕IoStopTimer被IAT钩子钩了,那可以这样:
        __f1 = (pfnIoStopTimer)GetExportVariableFormNtosExportTableByVariableName(L"IoStopTimer");
        if (__f1!=NULL)
        {
        __f1((PDEVICE_OBJECT)((PIO_TIMER)Timer)->DeviceObject);
        }
        */
    }
    // 删除时钟,当对方驱动卸载的时候会造成蓝屏
/*  if (Timer != NULL&&MmIsAddressValid((PVOID)Timer))
    {
        RemoveEntryList(ListEntry);
        ExFreePool((PVOID)Timer);
    }*/
    return STATUS_SUCCESS;
}

VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
    DbgPrint("ByeByeDriver\r\n");
}


BOOLEAN GetIoTimerInfoByModuleInfo(ULONG_PTR* Timer,ULONG_PTR ModuleBase,ULONG_PTR ModuleSize,PLIST_ENTRY* ListEntry)
{
    PVOID  IoInitTimer = NULL;
    PUCHAR StartSearchAddress = NULL;
    PUCHAR EndSearchAddress = NULL;
    PUCHAR i = NULL;
    UCHAR  v1 = 0;
    UCHAR  v2 = 0;
    UCHAR  v3 = 0;
    INT32  Offset = 0;
    PLIST_ENTRY IopTimerQueueHead = { 0 };
    PLIST_ENTRY NextEntry = { 0 };
    PIO_TIMER   IoTimer = NULL;
    KIRQL OldIrql;

    IoInitTimer = GetExportVariableAddressFromNtosExportTableByVariableName(L"IoInitializeTimer");
    if (IoInitTimer == NULL)
    {
        return FALSE;
    }

#ifdef _WIN64
    /*
    kd> u IoInitializeTimer l 30
nt!IoInitializeTimer:
fffff800`042db3e0 48895c2408      mov     qword ptr [rsp+8],rbx
fffff800`042db3e5 48896c2410      mov     qword ptr [rsp+10h],rbp
fffff800`042db3ea 4889742418      mov     qword ptr [rsp+18h],rsi
fffff800`042db3ef 57              push    rdi
fffff800`042db3f0 4883ec20        sub     rsp,20h
fffff800`042db3f4 488b5928        mov     rbx,qword ptr [rcx+28h]
fffff800`042db3f8 498bf0          mov     rsi,r8
fffff800`042db3fb 488bea          mov     rbp,rdx
fffff800`042db3fe 488bf9          mov     rdi,rcx
fffff800`042db401 4885db          test    rbx,rbx
fffff800`042db404 753f            jne     nt!IoInitializeTimer+0x65 (fffff800`042db445)
fffff800`042db406 8d5330          lea     edx,[rbx+30h]
fffff800`042db409 33c9            xor     ecx,ecx
fffff800`042db40b 41b8496f5469    mov     r8d,69546F49h
fffff800`042db411 e8fa67d3ff      call    nt!ExAllocatePoolWithTag (fffff800`04011c10)
fffff800`042db416 488bd8          mov     rbx,rax
fffff800`042db419 4885c0          test    rax,rax
fffff800`042db41c 7507            jne     nt!IoInitializeTimer+0x45 (fffff800`042db425)
fffff800`042db41e b89a0000c0      mov     eax,0C000009Ah
fffff800`042db423 eb41            jmp     nt!IoInitializeTimer+0x86 (fffff800`042db466)
fffff800`042db425 33d2            xor     edx,edx
fffff800`042db427 488bc8          mov     rcx,rax
fffff800`042db42a 448d4230        lea     r8d,[rdx+30h]
fffff800`042db42e e85d49c0ff      call    nt!memset (fffff800`03edfd90)
fffff800`042db433 41bb09000000    mov     r11d,9
fffff800`042db439 48897b28        mov     qword ptr [rbx+28h],rdi
fffff800`042db43d 6644891b        mov     word ptr [rbx],r11w
fffff800`042db441 48895f28        mov     qword ptr [rdi+28h],rbx
fffff800`042db445 488d5308        lea     rdx,[rbx+8]
fffff800`042db449 4c8d05f0cde3ff  lea     r8,[nt!IopTimerLock (fffff800`04118240)]
fffff800`042db450 488d0d4974e0ff  lea     rcx,[nt!IopTimerQueueHead (fffff800`040e28a0)]

    */
    StartSearchAddress = (PUCHAR)IoInitTimer;
    EndSearchAddress = StartSearchAddress + PAGE_SIZE;
    for (i = StartSearchAddress; i < EndSearchAddress; i++)
    {
        if (MmIsAddressValid(i) && MmIsAddressValid(i + 1) && MmIsAddressValid(i + 2))
        {
            v1 = *i;
            v2 = *(i + 1);
            v3 = *(i + 2);
            if (v1 == 0x48 && v2 == 0x8d && v3 == 0x0d)
            {
                memcpy(&Offset, i + 3, 4);
                // 计算Timer链表的链表头
                IopTimerQueueHead = (PLIST_ENTRY)((PUCHAR)i + 7 + Offset);
                break;
            }
        }
    }

#else
    /*
    kd> u IoInitializeTimer l 30
nt!IoInitializeTimer:
83f945f3 8bff            mov     edi,edi
83f945f5 55              push    ebp
83f945f6 8bec            mov     ebp,esp
83f945f8 56              push    esi
83f945f9 8b7508          mov     esi,dword ptr [ebp+8]
83f945fc 8b5618          mov     edx,dword ptr [esi+18h]
83f945ff 85d2            test    edx,edx
83f94601 7531            jne     nt!IoInitializeTimer+0x41 (83f94634)
83f94603 68496f5469      push    69546F49h
83f94608 6a18            push    18h
83f9460a 52              push    edx
83f9460b e8f5c9f8ff      call    nt!ExAllocatePoolWithTag (83f21005)
83f94610 8bd0            mov     edx,eax
83f94612 85d2            test    edx,edx
83f94614 7507            jne     nt!IoInitializeTimer+0x2a (83f9461d)
83f94616 b89a0000c0      mov     eax,0C000009Ah
83f9461b eb37            jmp     nt!IoInitializeTimer+0x61 (83f94654)
83f9461d 57              push    edi
83f9461e 6a06            push    6
83f94620 59              pop     ecx
83f94621 33c0            xor     eax,eax
83f94623 8bfa            mov     edi,edx
83f94625 f3ab            rep stos dword ptr es:[edi]
83f94627 6a09            push    9
83f94629 58              pop     eax
83f9462a 668902          mov     word ptr [edx],ax
83f9462d 897214          mov     dword ptr [edx+14h],esi
83f94630 895618          mov     dword ptr [esi+18h],edx
83f94633 5f              pop     edi
83f94634 8b450c          mov     eax,dword ptr [ebp+0Ch]
83f94637 89420c          mov     dword ptr [edx+0Ch],eax
83f9463a 8b4510          mov     eax,dword ptr [ebp+10h]
83f9463d 894210          mov     dword ptr [edx+10h],eax
83f94640 6840b7f683      push    offset nt!IopTimerLock (83f6b740)
83f94645 83c204          add     edx,4
83f94648 b98083f683      mov     ecx,offset nt!IopTimerQueueHead (83f68380)

    */
    StartSearchAddress = (PUCHAR)IoInitTimer;
    EndSearchAddress = StartSearchAddress + PAGE_SIZE;
    for (i = StartSearchAddress; i < EndSearchAddress; i++)
    {
        if (MmIsAddressValid(i))
        {
            v1 = *i;
            if (v1 == 0xb9)
            {
                // x86下是b9指令后面跟的是绝对地址
                memcpy(&Offset, i + 1, 4);
                // 计算Timer链表的链表头
                IopTimerQueueHead = (PLIST_ENTRY)Offset;
                break;
            }
        }
    }

#endif
    // 遍历每个IoTimer,通过查看TimerRoutine是不是在Module之内,确定所要查找的Module
    if (IopTimerQueueHead != NULL&&MmIsAddressValid((PVOID)IopTimerQueueHead))
    {
        OldIrql = KeRaiseIrqlToDpcLevel();
        NextEntry = IopTimerQueueHead->Flink;
        while (NextEntry!=IopTimerQueueHead&&MmIsAddressValid(NextEntry))
        {
            IoTimer = CONTAINING_RECORD(NextEntry, IO_TIMER, ListEntry);
            // 找到某个模块内的时钟
            if ((ULONG_PTR)(IoTimer->TimerRoutine) >= ModuleBase
                && (ULONG_PTR)(IoTimer->TimerRoutine) <= ModuleBase + ModuleSize)
            {
                *Timer = (ULONG_PTR)IoTimer;
                *ListEntry = NextEntry;
                KeLowerIrql(OldIrql);
                return TRUE;
            }
            NextEntry = NextEntry->Flink;
        }
        KeLowerIrql(OldIrql);
        return FALSE;
    }
    else
    {
        return FALSE;
    }
}



BOOLEAN GetKernelModuleInfoByDriverObject(PDRIVER_OBJECT DriverObject, WCHAR* ModuleName, PVOID* ModuleBase, ULONG_PTR* ModuleSize)
{
    PLDR_DATA_TABLE_ENTRY CurrentEntry = NULL;
    PLDR_DATA_TABLE_ENTRY NextEntry = NULL;

    if (DriverObject == NULL && !MmIsAddressValid((PVOID)DriverObject))
    {
        return FALSE;
    }

    // DriverSection就是PLDR_DATA_TABLE_ENTRY结构
    CurrentEntry = NextEntry = (PLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection;
    NextEntry = (PLDR_DATA_TABLE_ENTRY)CurrentEntry->InLoadOrderLinks.Flink;
    while (CurrentEntry != NextEntry)
    {
        if (NextEntry->BaseDllName.Buffer&&
            NextEntry->BaseDllName.Length>0 &&
            MmIsAddressValid((PVOID)NextEntry->BaseDllName.Buffer)
            && !wcsncmp(ModuleName, (WCHAR*)NextEntry->BaseDllName.Buffer, NextEntry->BaseDllName.Length))
        {
            *ModuleBase = NextEntry->DllBase;
            *ModuleSize = NextEntry->SizeOfImage;
            DbgPrint("ModuleBase is %p \r\n", *ModuleBase);
            DbgPrint("ModuleSize is %p \r\n", *ModuleSize);
            return TRUE;
        }
        NextEntry = NextEntry->InLoadOrderLinks.Flink;
    }

    return FALSE;
}

PVOID GetExportVariableAddressFromNtosExportTableByVariableName(WCHAR * VariableName)
{
    PVOID VariableAddress = NULL;
    UNICODE_STRING v1 = { 0 };

    if (VariableName&& wcslen(VariableName) > 0)
    {
        RtlInitUnicodeString(&v1, VariableName);
        VariableAddress = MmGetSystemRoutineAddress(&v1);
    }

    return VariableAddress;
}

你可能感兴趣的:(驱动,驱动,IoTimer,windows)