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

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

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

2、ZwQuerySystemInformation大法

3、搜索内存

4、利用KPCR结构

存在的问题:

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

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

环境:虚拟机VMWare:WIN 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");

}

时间: 2024-11-19 04:37:03

总结一下得到内核模块地址的方法的相关文章

虚拟机上静态地址配置方法

虚拟机上静态地址配置方法 虚拟机要与其他东西进行连接时,由于IP地址总会变动,故设置为静态地址. 方法如下,留作备用. 1. 确保虚拟机网络连接方式是桥接模式 2.启动Ubuntu虚拟机,修改/etc/network/interfaces 网络接口文件,配置ip.掩码.网关等信息: 1 auto lo 2 iface lo inet loopback 3 4 auto eth4 5 iface eth4 inet static 6 address 192.168.1.233 7 netmask

用派克斯出现651 查看&修改mac地址的方法

1.winxp查看mac地址的方法 2.winxp修改mac地址的方法 电脑MAC地址是网卡适配器在出厂时就已经被固定了的,也叫物理地址,每块网卡适配器有全球唯一的MAC地址,一般情况是不需要修改MAC地址的,但有些特殊情况需要更改MAC地址来实现一些特殊的要求,修改之前大家先知道如何查看 第一种方法 1.在开始菜单栏选择"运行" 2.在运行中输入"cmd" 3.我们会看到有一个黑色窗口弹出,在里边输入"ipconfig /all"然后按回车键

Flask框架获取用户IP地址的方法

本文实例讲述了python使用Flask框架获取用户IP地址的方法.分享给大家供大家参考.具体如下: 下面的代码包含了html页面和python代码,非常详细,如果你正使用Flask,也可以学习一下最基本的Flask使用方法. python代码如下: from flask import Flask, render_template, request # Initialize the Flask application app = Flask(__name__) # Default route,

更灵活的定位内存地址的方法(学习汇编)

1.and指令:逻辑与指令,按位进行与运算.与1不变,与0变0,可将对象相应位设为0. 2.or指令:逻辑或指令,按为进行或运算.或1变1,或0变0,可将对象位设为1. 3.[BX+idata]的几种表现形式: mov ax,[200+bx] mov ax,200[bx] mov ax,[bx].200 4.SI和DI是8086CPU中和Bx功能相似的寄存器,只是不能分成两个8位的寄存器来用. 5.[BX+SI]进行内存地址定位的几种形式: mov ax,[bx][si] mov ax,[bx+

3D Mesh详细介绍免费下载地址使用方法

3D Mesh 是基于对象的软件开发工具包,提供了完全可配置的曲面和实体网格划分能力.该组件针对大部分计算机辅助工程(CAE)前处理的需求进行了优化,包括结构分析.热传递.计算流体动力学和电磁设计自动化(EDA).3D Mes其他h 提供了曲线.曲面(三角形和四边形)和实体(四面体)自动网格生成.线程安全组件使多线程应用程序可以利用多核硬件平台的优势,提供卓越的性能. 3D Mesh 包括一个与 3D AC其他IS Modeler 和 HOOPS 3D Application Framework

#获取本机IP地址时排除IPv6类型,只返回IPv4地址的方法

public static string GetLocalIP(){try{string HostName = Dns.GetHostName(); //得到主机名IPHostEntry IpEntry = Dns.GetHostEntry(HostName); for (int i=0; i < IpEntry.AddressList.Length; i++){//从IP地址列表中筛选出IPv4类型的IP地址//AddressFamily.InterNetwork表示此IP为IPv4,//Ad

js获取IP地址多种方法实例教程

js获取IP地址方法总结 js代码获取IP地址的方法,如何在js中取得客户端的IP地址.原文地址:js获取IP地址的三种方法 http://www.jbxue.com/article/11338.html 1,js取得IP地址的方法一 <script src="http://pv.sohu.com/cityjson?ie=utf-8"></script><script type="text/<A class="infotextke

几种C#程序读取MAC地址的方法

以下是收集的几种C#程序读取MAC地址的方法,示例中是读取所有网卡的MAC地址,如果仅需要读取其中一个,稍作修改即可. 1 通过IPConfig命令读取MAC地址 ///<summary>/// 根据截取ipconfig /all命令的输出流获取网卡Mac///</summary>///<returns></returns>publicstatic List<string> GetMacByIPConfig(){  List<string&

PHP转换IP地址到真实地址的方法详解

本篇文章是对PHP转换IP地址到真实地址的方法进行了详细的分析介绍,需要的朋友参考下 想要把IPv4地址转为真实的地址,肯定要参考IP数据库,商业的IP数据库存储在关系型数据库中,查询和使用都非常方便,但是成本不是个人和小公 司愿意承受的,所以简单应用的思路就是利用一些免费的IP数据库或者一些大网站提供的查询API,他们的数据量足够我们使用了.1. 利用纯真IP数据库利用本地的QQWry.Dat文件,优点是查询速度非常快,缺点是数据库文件要放在自己的空间内并且要偶尔更新数据库.时间关系废话不多说