[原创] 驱动开发:内核枚举IoTimer定时器
2022-10-14 13:24:0 Author: bbs.pediy.com(查看原文) 阅读量:6 收藏

今天继续分享内核枚举系列知识,这次我们来学习如何通过代码的方式枚举内核IoTimer定时器,内核定时器其实就是在内核中实现的时钟,该定时器的枚举非常简单,因为在IoInitializeTimer初始化部分就可以找到IopTimerQueueHead地址,该变量内存储的就是定时器的链表头部。枚举IO定时器的案例并不多见,即便有也是无法使用过时的,此教程学到肯定就是赚到了。

这里解释一下为什么要找IoInitializeTimer这个函数他是一个初始化函数,既然是初始化里面一定会涉及到链表的存储问题,找到他就能找到定时器链表基址,该函数的定义如下。

如上方的基础知识有了也就够了,接着就是实际开发部分,首先我们需要编写一个GetIoInitializeTimerAddress()函数,让该函数可以定位到IoInitializeTimer所在内核中的基地址上面,具体实现调用代码如下所示。

接着我们在反汇编代码中寻找IoTimerQueueHead,此处在LyShark系统内这个偏移位置是nt!IoInitializeTimer+0x5d 具体输出位置如下。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

// By: LyShark 内核开发系列教程

// https://www.cnblogs.com/LyShark/articles/16784393.html

typedef struct _IO_TIMER

{

  INT16        Type;

  INT16        TimerFlag;

  LONG32       Unknown;

  LIST_ENTRY   TimerList;

  PVOID        TimerRoutine;

  PVOID        Context;

  PVOID        DeviceObject;

}IO_TIMER, *PIO_TIMER;

// 得到IoInitializeTimer基址

PVOID GetIoInitializeTimerAddress()

{

  PVOID VariableAddress = 0;

  UNICODE_STRING uioiTime = { 0 };

  RtlInitUnicodeString(&uioiTime, L"IoInitializeTimer");

  VariableAddress = (PVOID)MmGetSystemRoutineAddress(&uioiTime);

  if (VariableAddress != 0)

  {

    return VariableAddress;

  }

  return 0;

}

VOID UnDriver(PDRIVER_OBJECT driver)

{

  DbgPrint("卸载完成... \n");

}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)

{

  DbgPrint(("hello lyshark.com \n"));

  // 得到基址

  PUCHAR IoInitializeTimer = GetIoInitializeTimerAddress();

  DbgPrint("IoInitializeTimer Address = %p \n", IoInitializeTimer);

  // 搜索IoTimerQueueHead地址

  /*

    nt!IoInitializeTimer+0x5d:

    fffff806`349963cd 488d5008        lea     rdx,[rax+8]

    fffff806`349963d1 48897018        mov     qword ptr [rax+18h],rsi

    fffff806`349963d5 4c8d05648de0ff  lea     r8,[nt!IopTimerLock (fffff806`3479f140)]

    fffff806`349963dc 48897820        mov     qword ptr [rax+20h],rdi

    fffff806`349963e0 488d0d99f6cdff  lea     rcx,[nt!IopTimerQueueHead (fffff806`34675a80)]

    fffff806`349963e7 e8c43598ff      call    nt!ExInterlockedInsertTailList (fffff806`343199b0)

    fffff806`349963ec 33c0            xor     eax,eax

  */

  INT32 iOffset = 0;

  PLIST_ENTRY IoTimerQueueHead = NULL;

  PUCHAR StartSearchAddress = IoInitializeTimer;

  PUCHAR EndSearchAddress = IoInitializeTimer + 0xFF;

  UCHAR v1 = 0, v2 = 0, v3 = 0;

  for (PUCHAR i = StartSearchAddress; i < EndSearchAddress; i++)

  {

    if (MmIsAddressValid(i) && MmIsAddressValid(i + 1) && MmIsAddressValid(i + 2))

    {

      v1 = *i;

      v2 = *(i + 1);

      v3 = *(i + 2);

      // fffff806`349963e0 48 8d 0d 99 f6 cd ff  lea rcx,[nt!IopTimerQueueHead (fffff806`34675a80)]

      if (v1 == 0x48 && v2 == 0x8d && v3 == 0x0d)

      {

        memcpy(&iOffset, i + 3, 4);

        IoTimerQueueHead = (PLIST_ENTRY)(iOffset + (ULONG64)i + 7);

        DbgPrint("IoTimerQueueHead = %p \n", IoTimerQueueHead);

        break;

      }

    }

  }

  // 枚举列表

  KIRQL OldIrql;

  // 获得特权级

  OldIrql = KeRaiseIrqlToDpcLevel();

  if (IoTimerQueueHead && MmIsAddressValid((PVOID)IoTimerQueueHead))

  {

    PLIST_ENTRY NextEntry = IoTimerQueueHead->Flink;

    while (MmIsAddressValid(NextEntry) && NextEntry != (PLIST_ENTRY)IoTimerQueueHead)

    {

      PIO_TIMER Timer = CONTAINING_RECORD(NextEntry, IO_TIMER, TimerList);

      if (Timer && MmIsAddressValid(Timer))

      {

        DbgPrint("IO对象地址: %p \n", Timer);

      }

      NextEntry = NextEntry->Flink;

    }

  }

  // 恢复特权级

  KeLowerIrql(OldIrql);

  Driver->DriverUnload = UnDriver;

  return STATUS_SUCCESS;

}


文章来源: https://bbs.pediy.com/thread-274721.htm
如有侵权请联系:admin#unsafe.sh