中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C語言驅動開發內核枚舉IoTimer定時器怎么實現

發布時間:2022-12-08 16:59:22 來源:億速云 閱讀:120 作者:iii 欄目:開發技術

本篇內容主要講解“C語言驅動開發內核枚舉IoTimer定時器怎么實現”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“C語言驅動開發內核枚舉IoTimer定時器怎么實現”吧!

正文

IoTimer內核定時器其實就是在內核中實現的時鐘,該定時器的枚舉非常簡單,因為在IoInitializeTimer初始化部分就可以找到IopTimerQueueHead地址,該變量內存儲的就是定時器的鏈表頭部。枚舉IO定時器的案例并不多見,即便有也是無法使用過時的,此教程學到肯定就是賺到了。

C語言驅動開發內核枚舉IoTimer定時器怎么實現

枚舉Io定時器過程

  • 1.找到IoInitializeTimer函數,該函數可以通過MmGetSystemRoutineAddress得到。

  • 2.找到地址以后,我們向下增加0xFF偏移量,并搜索特征定位到IopTimerQueueHead鏈表頭。

  • 3.將鏈表頭轉換為IO_TIMER結構體,并循環鏈表頭輸出。

這里解釋一下為什么要找IoInitializeTimer這個函數他是一個初始化函數,既然是初始化里面一定會涉及到鏈表的存儲問題,找到他就能找到定時器鏈表基址,該函數的定義如下。

NTSTATUS 
  IoInitializeTimer(
    IN PDEVICE_OBJECT  DeviceObject,     // 設備對象指針
    IN PIO_TIMER_ROUTINE  TimerRoutine,  // 定時器例程
    IN PVOID  Context                    // 傳給定時器例程的函數
    );

接著我們需要得到IO定時器的結構定義,在DEVICE_OBJECT設備對象指針中存在一個Timer屬性。

lyshark.com: kd> dt _DEVICE_OBJECT
ntdll!_DEVICE_OBJECT
   +0x000 Type             : Int2B
   +0x002 Size             : Uint2B
   +0x004 ReferenceCount   : Int4B
   +0x008 DriverObject     : Ptr64 _DRIVER_OBJECT
   +0x010 NextDevice       : Ptr64 _DEVICE_OBJECT
   +0x018 AttachedDevice   : Ptr64 _DEVICE_OBJECT
   +0x020 CurrentIrp       : Ptr64 _IRP
   +0x028 Timer            : Ptr64 _IO_TIMER
   +0x030 Flags            : Uint4B
   +0x034 Characteristics  : Uint4B
   +0x038 Vpb              : Ptr64 _VPB
   +0x040 DeviceExtension  : Ptr64 Void
   +0x048 DeviceType       : Uint4B
   +0x04c StackSize        : Char
   +0x050 Queue            : <anonymous-tag>
   +0x098 AlignmentRequirement : Uint4B
   +0x0a0 DeviceQueue      : _KDEVICE_QUEUE
   +0x0c8 Dpc              : _KDPC
   +0x108 ActiveThreadCount : Uint4B
   +0x110 SecurityDescriptor : Ptr64 Void
   +0x118 DeviceLock       : _KEVENT
   +0x130 SectorSize       : Uint2B
   +0x132 Spare1           : Uint2B
   +0x138 DeviceObjectExtension : Ptr64 _DEVOBJ_EXTENSION
   +0x140 Reserved         : Ptr64 Void

這里的這個+0x028 Timer定時器是一個結構體_IO_TIMER其就是IO定時器的所需結構體。

lyshark.com: 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

C語言驅動開發內核枚舉IoTimer定時器怎么實現

如上方的基礎知識有了也就夠了,接著就是實際開發部分,首先我們需要編寫一個GetIoInitializeTimerAddress()函數,讓該函數可以定位到IoInitializeTimer所在內核中的基地址上面,具體實現調用代碼如下所示。

GetIoInitializeTimerAddress()函數

#include <ntifs.h>
// 得到IoInitializeTimer基址
// By: LyShark 內核開發系列教程
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(("Uninstall Driver Is OK \n"));
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	DbgPrint(("hello lyshark.com \n"));
	// 得到基址
	PUCHAR IoInitializeTimer = GetIoInitializeTimerAddress();
	DbgPrint("IoInitializeTimer Address = %p \n", IoInitializeTimer);
	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

運行這個驅動程序,然后對比下是否一致:

C語言驅動開發內核枚舉IoTimer定時器怎么實現

nt!IoInitializeTimer+0x5d 輸出位置

接著我們在反匯編代碼中尋找IoTimerQueueHead,此處在LyShark系統內這個偏移位置是nt!IoInitializeTimer+0x5d 具體輸出位置如下。

lyshark.com: kd> uf IoInitializeTimer
nt!IoInitializeTimer+0x5d:
fffff805`74b85bed 488d5008        lea     rdx,[rax+8]
fffff805`74b85bf1 48897018        mov     qword ptr [rax+18h],rsi
fffff805`74b85bf5 4c8d054475e0ff  lea     r8,[nt!IopTimerLock (fffff805`7498d140)]
fffff805`74b85bfc 48897820        mov     qword ptr [rax+20h],rdi
fffff805`74b85c00 488d0dd9ddcdff  lea     rcx,[nt!IopTimerQueueHead (fffff805`748639e0)]
fffff805`74b85c07 e8141e98ff      call    nt!ExInterlockedInsertTailList (fffff805`74507a20)
fffff805`74b85c0c 33c0            xor     eax,eax

在WinDBG中標注出顏色lea rcx,[nt!IopTimerQueueHead (fffff805748639e0)]更容易看到。

C語言驅動開發內核枚舉IoTimer定時器怎么實現

接著就是通過代碼實現對此處的定位,定位我們就采用特征碼搜索的方式,如下代碼是特征搜索部分。

特征搜索部分

  • StartSearchAddress 代表開始位置

  • EndSearchAddress 代表結束位置,粗略計算0xff就可以定位到了。

#include <ntifs.h>
// 得到IoInitializeTimer基址
// By: LyShark 內核開發系列教程
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(("Uninstall Driver Is OK \n"));
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	DbgPrint(("hello lyshark.com \n"));
	// 得到基址
	PUCHAR IoInitializeTimer = GetIoInitializeTimerAddress();
	DbgPrint("IoInitializeTimer Address = %p \n", IoInitializeTimer);
	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);
			// 三個特征碼
			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;
			}
		}
	}
	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

搜索三個特征碼v1 == 0x48 && v2 == 0x8d && v3 == 0x0d從而得到內存位置,運行驅動對比下。

  • 運行代碼會取出lea指令后面的操作數,而不是取出lea指令的內存地址。

C語言驅動開發內核枚舉IoTimer定時器怎么實現

IO_TIMER結構體定義

最后一步就是枚舉部分,我們需要前面提到的IO_TIMER結構體定義。

  • PIO_TIMER Timer = CONTAINING_RECORD(NextEntry, IO_TIMER, TimerList) 得到結構體,循環輸出即可。

// By: LyShark 內核開發系列教程
// https://www.cnblogs.com/LyShark/articles/16784393.html
#include <ntddk.h>
#include <ntstrsafe.h>
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;
}

運行這段源代碼,并可得到以下輸出,由于沒有IO定時器所以輸出結果是空的:

C語言驅動開發內核枚舉IoTimer定時器怎么實現

到此,相信大家對“C語言驅動開發內核枚舉IoTimer定時器怎么實現”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

大渡口区| 建阳市| 满洲里市| 临城县| 嘉黎县| 磐安县| 大理市| 信丰县| 墨脱县| 金坛市| 沾化县| 宁河县| 武义县| 连江县| 宜丰县| 沈丘县| 资兴市| 黄冈市| 府谷县| 应城市| 肇庆市| 南汇区| 北宁市| 陕西省| 苍山县| 长宁区| 沽源县| 新和县| 周宁县| 探索| 德保县| 海盐县| 师宗县| 五大连池市| 敦煌市| 平江县| 林芝县| 武乡县| 本溪市| 白山市| 灵宝市|