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

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

2
ZwQuerySystemInformation大法

3
、搜索内存 

4
、利用KPCR结构

存在的问题:

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

2
、第1种方法如果输出BaseDllNamentoskrnl.exe,如果输出FullDllName则是:\WINDOWS\system32\ntkrnlpa.exe,地址都是:804d8000,不明白为何
来源泉贸软件工作室:http://www.qmboy.com


环境:虚拟机VMWareWIN XP SP3  +WDK ---- WINXP Check方式编译

 

#include<ntddk.h>

 

//---------------------------------//

 

//下面的结构包含了一些重要信息。如:PsLoadedModuleList,它是Windows加载的所有内核模块构成的链表的表头。

 

//PsLoadedModuleList就是如下这个结构体中InLoadOrderLinks。即为LDR_DATA_TABLE_ENTRY结构的第一项。

 泉贸软件工作室|软件逆向|软件破解|手机协议分析|营销软件|移动开发|抢购软件|秒杀工具|批量注册|脱机外挂|纸尿裤预约|协议定位

#pragmapack(push)//结构定义

 

#pragmapack(1)                  

 

typedefstruct _LDR_DATA_TABLE_ENTRY

 

{

 

    LIST_ENTRY        InLoadOrderLinks;

 

    LIST_ENTRY        InMemoryOrderLinks;

 

    LIST_ENTRY        InInitializationOrderLinks;

 

    PVOID              DllBase;

 

    PVOID              EntryPoint;

 

    ULONG              SizeOfImage;

 

    UNICODE_STRING    FullDllName;

 

    UNICODE_STRING    BaseDllName;

 

    ULONG              Flags;

 

    USHORT            LoadCount;

 

    USHORT            TlsIndex;

 

    union

 

    {

 

        LIST_ENTRY    HashLinks;

 

        struct

 

        {

 

            PVOID      SectionPointer;

 

            ULONG      CheckSum;

 

        };

 

    };

 

    union

 

    {

 

        ULONG          TimeDateStamp;

 

        PVOID          LoadedImports;

 

    };

 

    PVOID              EntryPointActivationContext;

 

    PVOID              PatchInformation;

 

}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

 

#pragmapack(pop)

来源:泉贸软件工作室:http://www.qtech.org

//---------------------------------------------------------------------------------------------------//函数声明

 

NTSTATUSDriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegistryPath);

 

NTSTATUSDriverUnload();

 

//Method3用到,指定当前线程运行在那个处理器

 

NTKERNELAPIVOID KeSetSystemAffinityThread ( KAFFINITY Affinity );

 

NTKERNELAPIVOID KeRevertToUserAffinityThread ( VOID );

 

NTKERNELAPINTSTATUS ZwQuerySystemInformation(

 

                                            INULONG SystemInformationClass,

 

                                              INOUT PVOID SystemInformation,

 

                                              INULONG SystemInformationLength,

 

                                              INPULONG ReturnLength OPTIONAL

 

                        );

 

#pragmaalloc_text(INIT, DriverEntry)

 

#pragmaalloc_text(PAGE, DriverUnload)

 

//---------------------------------------------------------------------------------------------------//变量、常量、结构定义

 

UNICODE_STRINGBaseName;

 

#defineSystemModuleInformation 11  //Method2要用到11功能号

 

typedefstruct _SYSTEM_MODULE_INFORMATION_ENTRY

 

{

 

  ULONG  Unknow1;

 

  ULONG  Unknow2;

 

  #ifdef  _WIN64

 

  ULONG  Unknow3;

 

  ULONG  Unknow4:

 

  #endif

 

  PVOID  Base;

 

  ULONG  Size;

 

  ULONG  Flags;

 

  USHORT  Index;

 

  USHORT  NameLength;

 

  USHORT  LoadCount;

 

  USHORT  ModuleNameOffset;

 

  char    ImageName[256];

 

}SYSTEM_MODULE_INFORMATION_ENTRY,*PSYSTEM_MODULE_INFORMATION_ENTRY;

 

typedefstruct _SYSTEM_MODULE_INFORMATION

 

{

 

  ULONG Count;//内核中以加载的模块的个数

 

  SYSTEM_MODULE_INFORMATION_ENTRY Module[1];

 

}SYSTEM_MODULE_INFORMATION,*PSYSTEM_MODULE_INFORMATION;

 

//---------------------------------------------------------------------------------------------------//

 

/*

 

    用到了DriverObject域的InLoadOrderLinks链表

 

注意:

 

  下面的代码会用到一个宏:

 

---------------------------------------------------------------------------------------------------------------------

 

CONTAINING_RECORD这样的一个宏,它的定义如下:

 

#defineCONTAINING_RECORD(address, type, field) ((type *)( (PCHAR)(address) -(ULONG_PTR)(&((type*)0)->field)))

 

根据网上资料:就是address-(fieldtype中的偏移)

 

----------------------------------------------------------------------------------------------------------------------

 

*/

 

VOIDMethod1(IN PDRIVER_OBJECT DriverObject)//遍历链表

 

{

 

  ULONGBase=0;//模块基地址

 

  LDR_DATA_TABLE_ENTRY*SectionBase=NULL;

 

  LIST_ENTRY*Entry=NULL;

 

    LIST_ENTRYInLoadOrderLinks;

 

    ULONGnum=0;

 

  Entry=((LIST_ENTRY*)DriverObject->DriverSection)->Flink;

 

  do

 

  {

 

    SectionBase=CONTAINING_RECORD(Entry,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks);//得到这个Entry所属的Section的地址,此方法经过验证可行

 

      if(SectionBase->EntryPoint &&

 

            SectionBase->BaseDllName.Buffer&&

 

            SectionBase->FullDllName.Buffer&&

 

            SectionBase->LoadCount

 

            )

 

    {

 

      DbgPrint("方法一遍历模块名称:%wZ,地址:%x\n",&(SectionBase->FullDllName),SectionBase->DllBase);

 

      //DbgPrint("方法一遍历模块名称:%wZ,地址:%8X\n",&(SectionBase->BaseDllName),SectionBase->DllBase);

 

      num++;

 

      /*if(!RtlCompareUnicodeString(&(SectionBase->BaseDllName),&BaseName,FALSE))

 

      {

 

        DbgPrint("方法一模块名称:%wZ,地址:%x\n",&(SectionBase->BaseDllName),SectionBase->DllBase);

 

      }*/

 

    }

 

    Entry=Entry->Flink;

 

  }while(Entry!=((LIST_ENTRY*)DriverObject->DriverSection)->Flink);//直到遍历回来

 

  DbgPrint("方法一得到模块总数:%d\n",num);

 

}

 

voidMethod2()//ZwQuerySystemInformation大法

 

{

 

  PVOIDpBuffer=0;//缓冲区

 

  NTSTATUSResult;//查询结果

 

  ULONGNeedSize;

 

  PSYSTEM_MODULE_INFORMATIONpSystemModuleInformation;//将结果强制转换为该类型

 

  ULONGBufferSize = 0x5000;//初始分配内存大小,没有采用查询再分配的循环方法

 

  ULONGModuleCount;//模块总数

 

  ULONGi;

 

  do

 

  {

 

    pBuffer=ExAllocatePool(NonPagedPool,BufferSize);

 

    if(pBuffer==NULL)

 

    {

 

      DbgPrint("分配内存失败!\n");

 

      returnFALSE;

 

    }

 

    Result=ZwQuerySystemInformation(SystemModuleInformation,pBuffer,BufferSize,&NeedSize);

 

    if(Result==STATUS_INFO_LENGTH_MISMATCH)//分配不够

 

    {

 

      ExFreePool(pBuffer);

 

      //大小乘以2,重新分配

 

      BufferSize*=2;

 

    }

 

    elseif(!NT_SUCCESS(Result))//失败,放弃吧

 

    {

 

      DbgPrint("查询失败,错误码:%8X\n",Result );

 

      ExFreePool(pBuffer);

 

      returnFALSE;

 

    }

 

  }while( Result == STATUS_INFO_LENGTH_MISMATCH );

 

  pSystemModuleInformation= (PSYSTEM_MODULE_INFORMATION)pBuffer;//类型转换

 

  ModuleCount=pSystemModuleInformation->Count;//模块总数

 

  for(i=0;i<ModuleCount;i++)

 

  {

 

    DbgPrint("方法二遍历模块名称:%s,地址:%8X\n",pSystemModuleInformation->Module.ImageName,pSystemModuleInformation->Module.Base );

 

  }

 

  DbgPrint("方法二得到模块总数:%d\n",ModuleCount);

 

  ExFreePool(pBuffer);

 

  returnTRUE;

 

}

 

VOIDMethod3(ULONG Base)//搜索内存,从0x80000000-----0xa0000000

 

{

 

  ;

 

}

 

//内核中FS寄存器指向KPCR结构,每个处理器都有一个,使用第一个处理器即可其中比较重要的是KdVersionBlock这个指标, 它指向一个DBGKD_GET_VERSION64这个结构.

 

//这个结构体里面包含了一些重要信息。如:PsLoadedModuleList,它是Windows加载的所有内核模块构成的链表的表头

 

//两个处理器对应的KPCR结构是有区别的, 只有第一个处理器的KPCRKdVersionBlock才指向DBGKD_GET_VERSION64这个结构.

 

//-------------------------------------仔细观察定义会发现,这个跟使用DriverObject方法达到的链表示一样的!

 

voidMethod4()                              

 

{

 

  ULONGAddr;//内核地址

 

  LIST_ENTRY*Entry=NULL;

 

    LIST_ENTRYInLoadOrderLinks;

 

  LDR_DATA_TABLE_ENTRY*SectionBase=NULL;//LdrData->DllBase,LdrData->FullDllNme

 

    ULONGnum=0;

 

    //-----------------------------------------------------------------------------//在莫灰灰基础上修改一小部分

 

    KeSetSystemAffinityThread(1);//使当前线程运行在第一个处理器上

 

  _asm

 

  {

 

    push  eax

 

    mov  eax,FS:[0x34]                    ;指向KdVersionBlock的指标

 

    add  eax,18h                          ;得到指向PsLoadedModuleList的地址,即该指针的地址,指针里存有PsLoadedModuleList的地址

 

    mov  eax,[eax]                        ;得到PsLoadedModuleList的地址

 

        mov  eax,[eax]                        ;得到PsLoadedModuleList的内容

 

    //mov  eax,[eax+18h]                    ;取出DllBase, ntoskrnl.exe的基地址

 

        mov  Addr,eax

 

        pop  eax

 

  }

 

  KeRevertToUserAffinityThread();//恢复线程运行的处理器

 

  //----------------------------------------------------------------------//以下跟方法一重复

 

    Entry=(LIST_ENTRY*)Addr;

 

  do

 

  {

 

    SectionBase=CONTAINING_RECORD(Entry,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks);//得到这个Entry所属的Section的地址,此方法经过验证可行

 

      if(SectionBase->EntryPoint &&

 

            SectionBase->BaseDllName.Buffer&&

 

            SectionBase->FullDllName.Buffer&&

 

            SectionBase->LoadCount

 

            )

 

    {

 

      DbgPrint("方法四遍历模块名称:%wZ,地址:%8X\n",&(SectionBase->FullDllName),SectionBase->DllBase);

 

      num++;

 

    }

 

    Entry=Entry->Flink;

 

  }while(Entry!=(LIST_ENTRY*)Addr);//直到遍历回来

 

  DbgPrint("方法四得到模块总数:%d\n",num);

 

}

 

NTSTATUSDriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegistryPath)

 

{

 

  ULONGEntryAddr;

 

  _asm

 

  {

 

    pushecx;

 

    leaecx,[ebp][4];//得到DriverEntry返回地址

 

    movEntryAddr,ecx;

 

    popecx;

 

  }

 

  EntryAddr=*(ULONG*)EntryAddr;

 

  DbgPrint("驱动返回地址:%8X\n",EntryAddr);

 

  RtlInitUnicodeString(&BaseName,L"ntoskrnl.exe");

 

  DbgPrint("驱动加载成功!\n");

 

  //-------------------------------//

 

  Method1(pDriverObject);

 

  //-------------------------------//

 

  Method2();

 

      //-------------------------------//

 

  Method3();

 

        //-------------------------------//

 

  Method4();

 

  //-------------------------------//

 

  pDriverObject->DriverUnload=DriverUnload;

 

  returnSTATUS_SUCCESS;

 

}

 

NTSTATUSDriverUnload()

 

{

 

  DbgPrint("驱动卸除成功\n");

 

}