驱动中获取PsActiveProcessHead变量地址的五种方法也可以获取KdpDebuggerDataListHead

PsActiveProcessHead的定义:

在windows系统中,所有的活动进程都是连在一起的,构成一个双链表,表头是全局变量PsActiveProcessHead,当一个进程被创建时,其ActiveProcessList域将被作为节点加入到此链表中;当进程被删除时,则从此链表中移除,如果windows需要枚举所有的进程,直接操纵此链表即可。

方法一:从KdInitSystem函数地址处硬编码搜索
方法二:从System进程(pid=4)的PEPROCESS地址获取
方法三:从ntoskrnl.exe的导出变量PsInitialSystemProcess中获取
方法四:从KPCR中获取
方法五:调用NtSystemDebugControl函数获取

注:操作系统 Windows XP SP3

方法一:
系统内核变量KdDebuggerDataBlock是一个KDDEBUGGER_DATA64类型的结构体,结构成员PsActiveProcessHead正是我们所找的地址。可在WinDDK的\inc\api\WDBGEXTS.H文件中查看到此结构的定义。

KdInitSystem函数中引用了KdDebuggerDataBlock,而ntoskrnl.exe的导出函数KdEnableDebugger调用了KdInitSystem函数。

代码:

ULONG FindPsActiveProcessHead1()
{
  //1.从KdEnableDebugger地址找到KdInitSystem地址
  //nt!KdEnableDebugger   804f7810
  
  //804f7837 6a00            push    0
  //804f7839 6a00            push    0
  //804f783b c605ecab558001  mov     byte ptr [nt!PoHiberInProgress (8055abec)],1
  //804f7842 e8f7951600      call    nt!KdInitSystem (80660e3e)
  //804f7847 e8649a1600      call    nt!KdpRestoreAllBreakpoints (806612b0)

  ULONG i;
  PCALL_CODE pCall;
  PUCHAR pKdInitSystem=NULL;
  PUCHAR p=(PUCHAR)GetExportFuncAddress(L"KdEnableDebugger");
  KdPrint(("KdEnableDebugger地址=%x\n",p));
  if (!p)
  {
    KdPrint(("获取KdEnableDebugger地址失败\n"));
    return 0;
  }

  for (i=0;i<100;i++,p++)
  {
    if ((*p==0x6a)&&
      (*(p+1)==0x00)&&
      (*(p+2)==0x6a)&&
      (*(p+3)==0x00)&&
      (*(p+4)==0xc6)&&
      (*(p+5)==0x05)&&
      (*(p+0xb)==0xe8)&&
      (*(p+0x10)==0xe8)  )
    {
      pCall=(PCALL_CODE)(p+0xb);
      pKdInitSystem=p+0xb+pCall->address+5;
      KdPrint(("KdInitSystem地址=%x\n",pKdInitSystem));
      break;
    }
  }
  
  if (!pKdInitSystem)
  {
    KdPrint(("获取KdInitSystem地址失败\n"));
    return 0;
  }

  //2.从KdInitSystem地址找到KdDebuggerDataBlock地址
  //nt!KdInitSystem 80660e3e

  //80660e8e 6890020000      push    290h
  //80660e93 68606b5480      push    offset nt!KdDebuggerDataBlock (80546b60)
  //80660e98 be74926780      mov     esi,offset nt!KdpDebuggerDataListHead (80679274)

  p=pKdInitSystem;
  for (i=0;i<100;i++,p++)
  {
    if ((*p==0x68)&&
      (*(p+5)==0x68)&&
      (*(p+0xA)==0xbe))
    {
      pCall=(PCALL_CODE)(p+5);
      KdPrint(("KdDebuggerDataBlock地址=%x\n",pCall->address));
      KdPrint(("PsActiveProcessHead地址=%x\n",((PKDDEBUGGER_DATA64)pCall->address)->PsActiveProcessHead));
      return ((PKDDEBUGGER_DATA64)pCall->address)->PsActiveProcessHead;
    }
  }
  KdPrint(("获取KdDebuggerDataBlock地址失败\n"));
  return 0;
}

方法二:PsActiveProcessHead是活动进程链表头,理论上是第二个进程的EPROCESS结构成员ActiveProcessLinks的Blink,最后一个进程的EPROCESS结构成员ActiveProcessLinks的Flink。第二个进程即System进程,进程ID等于4。

代码:

NTSTATUS FindPsActiveProcessHead(ULONG *pPsActiveProcessHead)
{
  PEPROCESS process;
  PLIST_ENTRY pList=NULL;
  NTSTATUS status=PsLookupProcessByProcessId((HANDLE)4,&process);
  if (!NT_SUCCESS(status))
  {
    KdPrint(("获取process失败\n"));
    return status;
  }
  //xp _EPROCESS +0x088 ActiveProcessLinks : _LIST_ENTRY
  pList=(PLIST_ENTRY)((PUCHAR)process+0x88);
  KdPrint(("PsActiveProcessHead地址=%x\n",pList->Blink));
  *pPsActiveProcessHead=(ULONG)pList->Blink;
  ObDereferenceObject(process);
  return status;
}

方法三:ntoskrnl.exe导出了一个类型为PEPROCESS结构的变量PsInitialSystemProcess,它指向system进程(PID=4)的EPROCESS。这个方法与上一个方法类似。使用PsInitialSystemProcess在WinDDK中编译的话有链接ntoskrnl.lib。

代码:

ULONG FindPsActiveProcessHead3()
{
  ULONG addr=*(PULONG)PsInitialSystemProcess;
  //xp _EPROCESS +0x088 ActiveProcessLinks : _LIST_ENTRY
  PLIST_ENTRY pList=(PLIST_ENTRY)(addr+0x88);
  KdPrint(("PsActiveProcessHead地址=%x\n",pList->Blink));
  return (ULONG)pList->Blink;
}

方法四:每个CPU都有个KPCR结构,第一个KPCR结构的地址是固定的0xffdff000。KPCR结构偏移0x034位置的结构成员KdVersionBlock是一个DBGKD_GET_VERSION64类型的指针。此结构同样在WDBGEXTS.H中有定义。DBGKD_GET_VERSION64结构成员DebuggerDataList其实是KdpDebuggerDataListHead。而KdpDebuggerDataListHead.Flink=KdpDebuggerDataListHead.Blink=KdDebuggerDataBlock。


代码:

ULONG FindPsActiveProcessHead4()
{
  PLIST_ENTRY pList;
  PKDDEBUGGER_DATA64 pKdDebuggerData;
  PDBGKD_GET_VERSION64 pKdVersionBlock=(PDBGKD_GET_VERSION64)(*(PULONG)(0xffdff000+0x34));
  KdPrint(("获取到DebuggerDataList地址=%x\n",pKdVersionBlock->DebuggerDataList));
  pList=(PLIST_ENTRY)pKdVersionBlock->DebuggerDataList;
  KdPrint(("pList->Flink=%x,pList->Blink地址=%x\n",pList->Flink,pList->Blink));
  pKdDebuggerData=(PKDDEBUGGER_DATA64)pList->Flink;
  KdPrint(("PsActiveProcessHead地址=%x\n",pKdDebuggerData->PsActiveProcessHead));
  return pKdDebuggerData->PsActiveProcessHead;
}

方法五:调用SSDT表中的NtSystemDebugControl函数。

代码:

ULONG FindPsActiveProcessHead5()
{
  PLIST_ENTRY pList;
  DBGKD_GET_VERSION64 KdVersionBlock;
  PKDDEBUGGER_DATA64 pKdDebuggerData;
  ZwSystemDebugControl NtSystemDebugControl;
  
  NtSystemDebugControl=(ZwSystemDebugControl)GetSSDTAddrFromIndex(255);
  KdPrint(("NtSystemDebugControl函数地址=%x\n",NtSystemDebugControl));
  
  NtSystemDebugControl(SysDbgSysGetVersion,NULL,0,&KdVersionBlock,sizeof(DBGKD_GET_VERSION64),NULL);
  KdPrint(("DebuggerDataList=%x\n",KdVersionBlock.DebuggerDataList));
  
  pList=(PLIST_ENTRY)KdVersionBlock.DebuggerDataList;
  KdPrint(("获取到KdDebuggerDataBlock地址=%x\n",pList->Flink));

  pKdDebuggerData=(PKDDEBUGGER_DATA64)pList->Flink;
  KdPrint(("PsActiveProcessHead地址=%x\n",pKdDebuggerData->PsActiveProcessHead));

  return pKdDebuggerData->PsActiveProcessHead;
}

jpg 改 rar

时间: 2024-10-13 06:03:21

驱动中获取PsActiveProcessHead变量地址的五种方法也可以获取KdpDebuggerDataListHead的相关文章

获取函数的地址(三种方法,分别是@,Addr,MethodAddress)

问题来源: http://www.cnblogs.com/del/archive/2008/07/30/1039045.html#1272783 在编译器看来, 重载函数根本就是完全不同的几个函数, 当然就会有不同的函数地址; 我们用常规方法获取的地址只是第一种重载的地址. 代码文件: unit Unit1; interface uses   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  

【Linux】shell编程之给变量赋值的五种方法

1.  Shell中的变量类型 Shell中的变量可以分为环境变量.位置变量.预定义的特殊变量以及用户自定义变量. <!--[if !supportLists]-->2.  <!--[endif]-->环境变量 Shell中的环境变量是一类Shell预定义变量,是用于设置系统运行环境的变量,环境变量由系统统一命名.部分系统变量的值由系统设定,部分环境变量的值可以由用户给定. 环境变量的名称由大写字母组成,常用的Shell环境变量如下所示: HOME: 用户主目录的全路径名,cd $

C-循环,获取数组地址的几种方法

程序的调试的作用: 跟踪CPU执行代码的步骤 监视变量的值在程序执行的时候是如何变化的 do-while 和 while 在实际的开发中, do-while比较少用 因为就算循环无论如何要至少执行一次的时候,while也可以搞定 循环的情况一共就两种: 1.循环次数确定的循环 2.循环次数不确定的循环,但是确定了循环继续活着结束的条件 对于一个一位数组来说 1.获取 a[i]的地址的几种方法 1 &a[i] // 取地址符 1 a+i // 数组名就是数组首地址 1 int *p = a; 2

QT中获取选中的radioButton的两种方法(动态取得控件的objectName之后,对名字进行比较)

QT中获取选中的radioButton的两种方法 QT中要获取radioButton组中被选中的那个按钮,可以采用两种如下两种办法进行: 方法一:采用对象名称进行获取 代码: 1 QRadioButton* pbtn = qobject_cast<QRadioButton*>(ui->BG->checkedButton()); 2 QString name = pbtn->objectName(); 3 if(!QString::compare(name, "rad

C#获取MAC地址的几种方法

首先需要用到的一些方法和类: public enum NCBCONST { NCBNAMSZ = 16, MAX_LANA = 254, NCBENUM = 0x37, NRC_GOODRET = 0x00, NCBRESET = 0x32, NCBASTAT = 0x33, NUM_NAMEBUF = 30, } [StructLayout(LayoutKind.Sequential)] public struct ADAPTER_STATUS { [MarshalAs(UnmanagedTy

【转载】取得系统中网卡MAC地址的三种方法

From:http://blog.csdn.net/zhangting1987/article/details/2732135 网卡地址这个概念有点混淆不清.因为实际上有两个地址,mac地址和物理地址,一般说网卡地址我是指物理地址,不知道别人怎么看?物理地址指的是网卡上的存放地址的ROM里的地址,mac地址是这块卡工作的时候用的地址,一般情况下这两个地址是一样的,所以很多人都混用了,甚至不知道有区别  -_-# 网卡工作的时候,一个以太网帧60到1514(不包括crc),帧的crc是网卡自动加的

PHP中获取文件扩展名的N种方法

PHP中获取文件扩展名的N种方法 从网上收罗的,基本上就以下这几种方式: 第1种方法: function get_extension($file) { substr(strrchr($file, '.'), 1); } 第2种方法: function get_extension($file) { return substr($file, strrpos($file, '.')+1); } 第3种方法: function get_extension($file) { return end(expl

Knockout获取数组元素索引的2种方法,在MVC中实现

在遍历数组.集合的时候,通常要获取元素的索引,本篇体验使用Knockout获取索引的2种方法. 假设有这样的一个模型: namespace UseIndex.Models { public class Student { public int Id { get; set; } public string Name { get; set; } } } 在HomeController中,先模拟一个Student的集合,在投影出Name属性的集合,最后以Json返回给前台视图. using Syste

获取IP地址的几种方法

根据ip获取地址的几种方法 1.调用新浪IP地址库 <script type="text/javascript" src="js/jquery.js"> </script> <script type="text/javascript" src="js/jquery.cityselect.js"> </script> <script type="text/javas