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

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

  1. php获取客户端IP地址的几种方法(转)

    [php] view plain copy php获取客户端IP地址的几种方法 方法一 <?php $iipp=$_SERVER["REMOTE_ADDR"]; echo $ ...

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

    问题来源: http://www.cnblogs.com/del/archive/2008/07/30/1039045.html#1272783 在编译器看来, 重载函数根本就是完全不同的几个函数, ...

  3. 总结C++中取成员函数地址的几种方法

    这里, 我整理了4种C++中取成员函数地址的方法, 第1,2,4种整理于网上的方法, 第3种cdecl_cast是我自己想到的. 其中, 第4种(汇编)的方法不能在VC6上编译通过. 推荐使用第1,2 ...

  4. 【转】总结C++中取成员函数地址的几种方法

    转自:“http://www.cnblogs.com/nbsofer/p/get_member_function_address_cpp.html” 这里, 我整理了4种C++中取成员函数地址的方法, ...

  5. 让块元素在div中水平居中,并且垂直居中的五种方法

    在写代码前,先做下准备工作,写两个div,设置下div的大小,把小的div放在大的div里面.可以给小的div设置下颜色,方便观看. 方法一:写一个伪元素,将它设置为行内块元素,高度与父元素相同,写一 ...

  6. C#程序读取MAC地址的五种方法(转)

    public class GetMac { ///<summary> /// 根据截取ipconfig /all命令的输出流获取网卡Mac ///</summary> ///& ...

  7. 转载:(Mac)在bash和zsh配置环境变量path的几种方法

    参考文献 老习惯,列出本文参考或引用或转载的文档和博客,致以崇高的敬意,感兴趣的可以去看看 1.http://postgresapp.com/ 2.http://postgresapp.com/doc ...

  8. html table表格导出excel的方法 html5 table导出Excel HTML用JS导出Excel的五种方法 html中table导出Excel 前端开发 将table内容导出到excel HTML table导出到Excel中的解决办法 js实现table导出Excel,保留table样式

    先上代码   <script type="text/javascript" language="javascript">   var idTmr; ...

  9. windows下获取IP地址的两种方法

    windows下获取IP地址的两种方法: 一种可以获取IPv4和IPv6,但是需要WSAStartup: 一种只能取到IPv4,但是不需要WSAStartup: 如下: 方法一:(可以获取IPv4和I ...

随机推荐

  1. 在Py文件中引入django环境

    复制manage.py中的相关代码即可并将文件置于Project文件夹(与manage.py同位置)下 示例: #! /usr/bin/env python # -*- coding:utf- -*- ...

  2. Unity3d《Shader篇》绘制圆角图片

    Pass { CGPROGRAM // Upgrade NOTE: excluded shader from OpenGL ES 2.0 because it does not contain a s ...

  3. iOS CLLocationManager 定位

    今天写个定位,本来很简单,但是在填写plist时,通过系统提示,只能看到NSLocationUsageDescription项目,根本不提示 (1)NSLocationAlwaysUsageDescr ...

  4. 算法手记 之 数据结构(线段树详解)(POJ 3468)

    依然延续第一篇读书笔记,这一篇是基于<ACM/ICPC 算法训练教程>上关于线段树的讲解的总结和修改(这本书在线段树这里Error非常多),但是总体来说这本书关于具体算法的讲解和案例都是不 ...

  5. 构建web应用示例

    1.1 请求方法的判断 var http = require('http'); var server = http.createServer(function(request,response){ s ...

  6. Python 开发轻量级爬虫03

    Python 开发轻量级爬虫 (imooc总结03--简单的爬虫架构) 现在来看一下一个简单的爬虫架构. 要实现一个简单的爬虫,有哪些方面需要考虑呢? 首先需要一个爬虫调度端,来启动爬虫.停止爬虫.监 ...

  7. 数据结构顺序表删除所有特定元素x

    顺序表类定义: template<class T> class SeqList : { public: SeqList(int mSize); ~SeqList() { delete[] ...

  8. form、iframe实现异步上传文件

    转载自:http://blog.csdn.net/sunjing21/article/details/4779321 实现主要功能: 页面提供一个上传图片的input file选择框,用于上传某一类型 ...

  9. September 19th 2016 Week 39th Monday

    We come nearest to the great when we are great in humility. 我们最为谦逊的时候越接近伟大. When you are powerful en ...

  10. ALT+数字直接取得字符的原理

    字符 字节码 utf-8编码 机器二进制码 之间的联系 byte数组与二进制码关系参考文献 例如:字符“我” byte字节码是 [-26, -120, -111] 绝对值源码 [00011010, 0 ...