王者至尊 发表于 2011-8-16 13:16:29

总结一下得到内核模块地址的方法

网上说的比较常见的4种方法:

1、通过DriverEntry传入的DriverObject参数的DriverSection成员指向LDR_DATA_TABLE_ENTRY结构,通过遍历这张表得到ntoskrnl的基址和大小

2、ZwQuerySystemInformation大法

3、搜索内存

4、利用KPCR结构

存在的问题:
1、第3种方法还没搞定,combojiangn牛的汇编看不太懂,基础不行啊,之后补上C的

2、第1种方法和第4种方法得到的结果比ZwQuerySystemInformation少一个

3、第1种方法如果输出BaseDllName是ntoskrnl.exe,如果输出FullDllName则是:\WINDOWS\system32\ntkrnlpa.exe,地址都是:804d8000,不明白为何

环境:虚拟机VMWare:WIN XP SP3+ WDK ---- WINXP Check方式编译
**** Hidden Message *****

gcjb 发表于 2011-8-16 13:16:44

搜内存原理是这样的。
在DriverEntry内取得返回地址。
(为什么可以取返回地址,想一想驱动的加载过程具体说就nt!IopLoadDriver内那句Call dword ptr )而这个返回地址就在内核文件内部。然后以返回地址为起点,按页对齐(对齐只是为了加快搜索速度,不对齐也行)向前搜。直到匹配了PE特征。而第一个匹配PE特征的地址就是内核文件基地址。

明白了原理相信C代码就很容易了。我顺带贴一个。

BOOLEAN
FindBaseAndSize(
IN PVOID SomePtr,
OUT PVOID *BaseAddress OPTIONAL,
OUT ULONG *ImageSize OPTIONAL
)
{
ULONG SomeAddress = (ULONG) SomePtr;

for ( SomeAddress &= 0xFFFFF000 ; ; SomeAddress -= PAGE_SIZE )
{
    if(MmIsAddressValid ((PVOID)SomeAddress) && *(USHORT*)SomeAddress == IMAGE_DOS_SIGNATURE ) // MZ signature?
    {
      PVOID NtHeader = RtlImageNtHeader ((PVOID)SomeAddress);// + ((IMAGE_DOS_HEADER*)SomeAddress)->e_lfanew;

      if (MmIsAddressValid ((PVOID)NtHeader) && *(ULONG*)NtHeader == IMAGE_NT_SIGNATURE) // PE signature?
      {
      if (ARGUMENT_PRESENT (BaseAddress))
          *BaseAddress = (PVOID)SomeAddress;

      if (ARGUMENT_PRESENT (ImageSize))
          *ImageSize = ((IMAGE_NT_HEADERS*)NtHeader)->OptionalHeader.SizeOfImage;

      return TRUE;
      }
    }
}

return FALSE;
}

在DriverEntry内调用的时候FindBaseAndSize(DriverEntry返回地址,XXX,XXX)。

备注:
一、实际上也不一定非取得返回地址,内核内任意一个函数的地址都可以作为起点。
二、我顺手贴的这个代码不支持X64.

cooby 发表于 2013-9-28 17:07:58

真是汗啊我的帖子好少啊加油!

yanbo8806 发表于 2013-10-1 17:23:57

帖子不错,顶一个

yanbo8806 发表于 2013-10-1 18:17:12

灌水喽,哇哈哈,

yanbo8806 发表于 2013-10-2 00:21:12

看流星社区总规则 Ver 2.0

xlsqwg 发表于 2019-2-9 02:19:50

支持楼主,支持看流星社区,以后我会经常来!

qq412158094 发表于 2019-3-28 13:53:31

支持楼主,支持看流星社区,以后我会经常来!
页: [1]
查看完整版本: 总结一下得到内核模块地址的方法