网站已经改版为Wordpress版本,这里是旧版本的快照,请不要在页面中留言.

手把手教你R0下通过EPROCESS获取进程加载模块


本文出自悠然品鉴小悠原创,转载请注明出处http://www.youranshare.com/codeorg/sid/137.html,如有错误欢迎大家指出.

在R3下获取一个进程加载的相关模块儿还是比较简单的,直接通过ToolHelp32库API就能够获取到进程关联的模块儿了,但是既然已经在R0下混了再去使用R3层的东西就没什么意义了,所以这里小悠在这里将会一部一部的介绍如何在R0下通过EPROCESS结构获取到进程加载的模块.

首先这里我们先介绍一下我们通过EPROCESS查询的大概思路

  通过EPROCESS 获取到对应的PEB 结构

  通过PEB找到 _PEB_LDR_DATA这货

  _PEB_LDR_DATA内部有3LIST_ENTRY,这也就是进程加载的模块儿信息的链表头,_PEB_LDR_DATA内部的3个链表其实只是模块儿的排列顺序不一样而已,里面的内容是一致的,本文中采用的是LoadOrder这个按照加载顺序排列的链表.

  知道了链表头,只需要知道链表的结点的就够就行了,这里我们遍历的链表结点是_LDR_DATA_TABLE_ENTRY结构,在这个结构内部有一个FullDllName,也就是模块儿的路径,就是我们要找的东西,只要遍历链表我们就能枚举出所有的加载模块儿.

我用一幅图来描述我们的过程

                                             

从图中可以看出,只需要找到最终的那个链表遍历一下就OK了。

 

知道了上面的基本思路,现在我们开始动手操作了,首先准备好你的Windbg调试工具,先通过Windbg正确查找一个进程的模块儿链表,后面我在介绍使用代码的方式。

 

      我的虚拟机是Win7 x86的,这里以进程dwm.exe为例.

  命令 !process 0 0 dwm.exe 先获取到dwm.exeEPROCESS的地址,如图我们可以看到EPROCESS的地址为:0x87ede940  ,PEB的地址为:0x7ffdf000 

  注意PEB的地址小于0x80000000,属于用户地址空间,是不能够直接访问的,要是直接访问的话就只能看到???????,所以我们需要切换到这个应用程序后才能够访问用户地址空间,使用下面的命令 .process /p /r 87ede940 切换到dwm.exe这个进程,如图所示:

  已经切换到dwm.exe,我们开始按照步骤来操作吧,命令dt _EPROCESS 87ede940 查看EPROCESS,如图所示在偏移0x1a8的位置找到了_PEB,地址为0x7ffdf000

  跟进_PEB,使用命令 dt _PEB 0x7ffdf000 查看PEB的信息,如图所示在偏移0x0c的位置找到了_PEB_LDR_DATA,地址为: 0x77307880

  继续跟进_PEB_LDR_DATA,使用命令dt _PEB_LDR_DATA 0x77307880  查看_PEB_LDR_DATA的信息,如图所示,一共有3_LIST_ENTRY,前面我已经说过这三个链表只是结点的顺序不一样,我采用的是第一个InLoadOrderModuleList按照加载顺序的这个链表.

从途中可以看到InLoadOrderModuleList Flink保存的地址为: 0x3017b8Blink保存的地址为: 0x30ebe8

  我们已经找到了链表的头部,但是我们现在可不知道_LDR_DATA_TABLE_ENTRY这货的结构是神马,所以我们使用命令dt _LDR_DATA_TABLE_ENTRY 来看一下_LDR_DATA_TABLE_ENTRY的结构,如图所示:

从结构中可以看到InLoadOrderModuleList位于结构体的首部,所以我们获取到的_LIST_ENTRY地址就直接指向了_LDR_DATA_TABLE_ENTRY,无需再次转换了

   回到⑤看一下了链表的第一个结点的地址(FLink方向遍历),第一个地址为0x3017b8OK我们使用命令dt _LDR_DATA_TABLE_ENTRY 0x3017b8 跟进看一下,如图所示

是不是看到dwm.exe这个进程本身的路径了? 那就对了,我们是按照模块儿加载的顺序遍历的,第一个模块儿就是本身嘛,不信的话那我们再往后看一个,命令dt _LDR_DATA_TABLE_ENTRY 0x301838 自己看下面的图吧,我就不多说了~~

 



通过上面的操作,我想你应该已经了解到查找模块儿的基本操作顺序了吧,那么下面就开始用代码搞出来吧!

上面我说的那几个结构体,基本上都可以在http://msdn.microsoft.com/zh-SG微软MSDN上查得到,但是小悠太懒了,毕竟结构体内部的成员又不是全用,所以小悠在代码中就简化了上面用到的一些结构体,如下所示是我简化后的结构体:

 

//_PEB_LDR_DATA的完全体
typedef struct _PEB_LDR_DATA
{
     ULONG Length;
     ULONG Initialized;
     ULONG SsHandle;
     _LIST_ENTRY InLoadOrderModuleList;
     _LIST_ENTRY InMemoryOrderModuleList;
     _LIST_ENTRY InInitializationOrderModuleList;
     PVOID EntryInProgress;
     PVOID ShutdownInProgress;
     ULONG ShutdownThreadId;
}PEB_LDR_DATA,*PPEB_LDR_DATA;
 
//PEB 的部分
typedef struct _PEB
{
     char nouse1[0xc];
     PPEB_LDR_DATA pLdrData;
}PEB,*PPEB;
 
//LDR_DATA_TABLE_ENTRY 表结构的部分
typedef struct LDR_DATA_TABLE_ENTRY
{
     _LIST_ENTRY InLoadOrderLinks;
     _LIST_ENTRY InMemoryOrderLinks;
     _LIST_ENTRY InInitializationOrderLinks;
 
     PVOID pDllBase;
     PVOID pEntryPoint;
     ULONG SizeOfImage;
 
     UNICODE_STRING fullPath;
     UNICODE_STRING basename;
}*PLDR_DATA_TABLE_ENTRY;

然后我写了一个函数,

//函数,传入进程PID,列举出当前进程所加载的模块儿
NTSTATUS EnmuProcessModuleByPID(ULONG pid);


函数的具体解释都在代码中写的很清楚了,你直接下载下来看看就明白了~~

附加,R0通过EPROCESS获取加载模块儿VS2010工程:

解压密码yscode

百度网盘下载地址:http://pan.baidu.com/s/1jGDVpn4


  • 标签:
  • EPROCESS获取进程加载模块
  • _PEB_LDR_DATA
  • _LDR_DATA_TABLE_ENTR
网站已经改版为Wordpress版本,这里是旧版本的快照,请不要在页面中留言.