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函数。

代码:
  1. ULONG FindPsActiveProcessHead1()
  2. {
  3.   //1.从KdEnableDebugger地址找到KdInitSystem地址
  4.   //nt!KdEnableDebugger   804f7810
  5.   
  6.   //804f7837 6a00            push    0
  7.   //804f7839 6a00            push    0
  8.   //804f783b c605ecab558001  mov     byte ptr [nt!PoHiberInProgress (8055abec)],1
  9.   //804f7842 e8f7951600      call    nt!KdInitSystem (80660e3e)
  10.   //804f7847 e8649a1600      call    nt!KdpRestoreAllBreakpoints (806612b0)
  11.  
  12.   ULONG i;
  13.   PCALL_CODE pCall;
  14.   PUCHAR pKdInitSystem=NULL;
  15.   PUCHAR p=(PUCHAR)GetExportFuncAddress(L"KdEnableDebugger");
  16.   KdPrint(("KdEnableDebugger地址=%x\n",p));
  17.   if (!p)
  18.   {
  19.     KdPrint(("获取KdEnableDebugger地址失败\n"));
  20.     return 0;
  21.   }
  22.  
  23.   for (i=0;i<100;i++,p++)
  24.   {
  25.     if ((*p==0x6a)&&
  26.       (*(p+1)==0x00)&&
  27.       (*(p+2)==0x6a)&&
  28.       (*(p+3)==0x00)&&
  29.       (*(p+4)==0xc6)&&
  30.       (*(p+5)==0x05)&&
  31.       (*(p+0xb)==0xe8)&&
  32.       (*(p+0x10)==0xe8)  )
  33.     {
  34.       pCall=(PCALL_CODE)(p+0xb);
  35.       pKdInitSystem=p+0xb+pCall->address+5;
  36.       KdPrint(("KdInitSystem地址=%x\n",pKdInitSystem));
  37.       break;
  38.     }
  39.   }
  40.   
  41.   if (!pKdInitSystem)
  42.   {
  43.     KdPrint(("获取KdInitSystem地址失败\n"));
  44.     return 0;
  45.   }
  46.  
  47.   //2.从KdInitSystem地址找到KdDebuggerDataBlock地址
  48.   //nt!KdInitSystem 80660e3e
  49.  
  50.   //80660e8e 6890020000      push    290h
  51.   //80660e93 68606b5480      push    offset nt!KdDebuggerDataBlock (80546b60)
  52.   //80660e98 be74926780      mov     esi,offset nt!KdpDebuggerDataListHead (80679274)
  53.  
  54.   p=pKdInitSystem;
  55.   for (i=0;i<100;i++,p++)
  56.   {
  57.     if ((*p==0x68)&&
  58.       (*(p+5)==0x68)&&
  59.       (*(p+0xA)==0xbe))
  60.     {
  61.       pCall=(PCALL_CODE)(p+5);
  62.       KdPrint(("KdDebuggerDataBlock地址=%x\n",pCall->address));
  63.       KdPrint(("PsActiveProcessHead地址=%x\n",((PKDDEBUGGER_DATA64)pCall->address)->PsActiveProcessHead));
  64.       return ((PKDDEBUGGER_DATA64)pCall->address)->PsActiveProcessHead;
  65.     }
  66.   }
  67.   KdPrint(("获取KdDebuggerDataBlock地址失败\n"));
  68.   return 0;
  69. }

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

代码:
  1. NTSTATUS FindPsActiveProcessHead(ULONG *pPsActiveProcessHead)
  2. {
  3.   PEPROCESS process;
  4.   PLIST_ENTRY pList=NULL;
  5.   NTSTATUS status=PsLookupProcessByProcessId((HANDLE)4,&process);
  6.   if (!NT_SUCCESS(status))
  7.   {
  8.     KdPrint(("获取process失败\n"));
  9.     return status;
  10.   }
  11.   //xp _EPROCESS +0x088 ActiveProcessLinks : _LIST_ENTRY
  12.   pList=(PLIST_ENTRY)((PUCHAR)process+0x88);
  13.   KdPrint(("PsActiveProcessHead地址=%x\n",pList->Blink));
  14.   *pPsActiveProcessHead=(ULONG)pList->Blink;
  15.   ObDereferenceObject(process);
  16.   return status;
  17. }

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

代码:
  1. ULONG FindPsActiveProcessHead3()
  2. {
  3.   ULONG addr=*(PULONG)PsInitialSystemProcess;
  4.   //xp _EPROCESS +0x088 ActiveProcessLinks : _LIST_ENTRY
  5.   PLIST_ENTRY pList=(PLIST_ENTRY)(addr+0x88);
  6.   KdPrint(("PsActiveProcessHead地址=%x\n",pList->Blink));
  7.   return (ULONG)pList->Blink;
  8. }

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


代码:
  1. ULONG FindPsActiveProcessHead4()
  2. {
  3.   PLIST_ENTRY pList;
  4.   PKDDEBUGGER_DATA64 pKdDebuggerData;
  5.   PDBGKD_GET_VERSION64 pKdVersionBlock=(PDBGKD_GET_VERSION64)(*(PULONG)(0xffdff000+0x34));
  6.   KdPrint(("获取到DebuggerDataList地址=%x\n",pKdVersionBlock->DebuggerDataList));
  7.   pList=(PLIST_ENTRY)pKdVersionBlock->DebuggerDataList;
  8.   KdPrint(("pList->Flink=%x,pList->Blink地址=%x\n",pList->Flink,pList->Blink));
  9.   pKdDebuggerData=(PKDDEBUGGER_DATA64)pList->Flink;
  10.   KdPrint(("PsActiveProcessHead地址=%x\n",pKdDebuggerData->PsActiveProcessHead));
  11.   return pKdDebuggerData->PsActiveProcessHead;
  12. }

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

代码:
  1. ULONG FindPsActiveProcessHead5()
  2. {
  3.   PLIST_ENTRY pList;
  4.   DBGKD_GET_VERSION64 KdVersionBlock;
  5.   PKDDEBUGGER_DATA64 pKdDebuggerData;
  6.   ZwSystemDebugControl NtSystemDebugControl;
  7.   
  8.   NtSystemDebugControl=(ZwSystemDebugControl)GetSSDTAddrFromIndex(255);
  9.   KdPrint(("NtSystemDebugControl函数地址=%x\n",NtSystemDebugControl));
  10.   
  11.   NtSystemDebugControl(SysDbgSysGetVersion,NULL,0,&KdVersionBlock,sizeof(DBGKD_GET_VERSION64),NULL);
  12.   KdPrint(("DebuggerDataList=%x\n",KdVersionBlock.DebuggerDataList));
  13.   
  14.   pList=(PLIST_ENTRY)KdVersionBlock.DebuggerDataList;
  15.   KdPrint(("获取到KdDebuggerDataBlock地址=%x\n",pList->Flink));
  16.  
  17.   pKdDebuggerData=(PKDDEBUGGER_DATA64)pList->Flink;
  18.   KdPrint(("PsActiveProcessHead地址=%x\n",pKdDebuggerData->PsActiveProcessHead));
  19.  
  20.   return pKdDebuggerData->PsActiveProcessHead;
  21. }

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. android studio Error:java.lang.OutOfMemoryError: GC overhead limit exceeded

    android studio Error:java.lang.OutOfMemoryError: GC overhead limit exceeded 在app下的build.gradle中找到and ...

  2. iOS 目录的使用

    Table 1-1  Commonly used directories of an iOS app  Directory Description AppName.app This is the ap ...

  3. iOS 关于UIWindow的理解

    Every iOS app has a window that handles the presentation of the app’s user interface. Although the w ...

  4. Dnsmasq安装与配置-搭建本地DNS服务器 更干净更快无广告DNS解析

    默认的情况下,我们平时上网用的本地DNS服务器都是使用电信或者联通的,但是这样也导致了不少的问题,首当其冲的就是上网时经常莫名地弹出广告,或者莫名的流量被消耗掉导致网速变慢.其次是部分网站域名不能正常 ...

  5. 通过syslog接收远程日志

    通过syslog接收远程日志   通过syslog接收远程主机的日志,需要做一些环境配置.   客户机A通过syslog将日志信息发送到服务主机B(或称日志采集服务器).以下说明配置过程(我的实验环境 ...

  6. Debian 配置apt-get源

    1.配置apt-get源 cp  /etc/apt/sources.list  /etc/apt/sources.listbak   #备份原有配置文件       nano  /etc/apt/so ...

  7. DP:Cow Exhibition(POJ 2184)(二维问题转01背包)

        牛的展览会 题目大意:Bessie要选一些牛参加展览,这些牛有两个属性,funness和smartness,现在要你求出怎么选,可以使所有牛的smartness和funness的最大,并且这两 ...

  8. 针对SYN洪水攻击的防御措施

    可以运用sysctl命令进行配置,由于本命令参数较多,这里只简单记录几个比较常用的参数: 1.tcp_max_syn_backlog 这个参数指定了后备队列可维持的TCP半开连接的数目,如果该值设定很 ...

  9. webclient 和httpclient 应用

    //webclient应用 MyImageServerEntities db = new MyImageServerEntities(); public ActionResult Index() { ...

  10. java操作数据库出错

    "无效的列索引"其实是个低级的错误 出错原因:1.sql串的?号数目和提供的变量数目不一致:例如:jdbcTemplate.update(sql, new Object[] {ne ...