得到内核模块基地址

 
//参考:combojiang:   http://hi.baidu.com/combojiang/blog/item/bfa7a6d9f1c913ee38012f28.html
//      combojiang:   http://hi.baidu.com/hu3167343/blog/item/3fb1cc91e9582507d31b7023.html
//      combojiang:   http://bbs.pediy.com/showthread.php?t=58447
//      莫灰灰:       http://hi.baidu.com/hu3167343/blog/item/3fb1cc91e9582507d31b7023.html
//      还有一些,忘了出处了,一并感谢,此次只是做个总结

#include <ntddk.h>
//---------------------------------//
//下面的结构包含了一些重要信息。如:PsLoadedModuleList ,它是Windows加载的所有内核模块构成的链表的表头。
//PsLoadedModuleList就是如下这个结构体中InLoadOrderLinks。即为LDR_DATA_TABLE_ENTRY结构的第一项。
#pragma pack(push)//结构定义
#pragma pack(1)                  
typedef struct _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;
#pragma pack(pop)
//---------------------------------------------------------------------------------------------------//变量、常量、结构定义
UNICODE_STRING BaseName;

#define SystemModuleInformation 11  //Method2要用到11功能号

#define IMAGE_DOS_SIGNATURE                 0x5a4d      // MZ           见winnt.h
#define IMAGE_NT_SIGNATURE                  0x00004550  // PE00

typedef struct _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;

typedef struct _SYSTEM_MODULE_INFORMATION
{
   ULONG Count;//内核中以加载的模块的个数
   SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
}SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

//---------------------------------------------------------------------------------------------------//函数声明
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegistryPath);
NTSTATUS DriverUnload();
//Method3用到,指定当前线程运行在那个处理器
NTKERNELAPI VOID KeSetSystemAffinityThread ( KAFFINITY Affinity );
NTKERNELAPI VOID KeRevertToUserAffinityThread ( VOID );

NTKERNELAPI NTSTATUS ZwQuerySystemInformation(
                                           IN ULONG SystemInformationClass,
                                              IN OUT PVOID SystemInformation,
                                              IN ULONG SystemInformationLength,
                                              IN PULONG ReturnLength OPTIONAL 
             );
//------------------------------------------------------------------------------------------------//

PIMAGE_NT_HEADERS NTAPI RtlImageNtHeader(IN PVOID BaseAddress);
//-----------------------------------------------------------------------------------------------//
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, DriverUnload)

/*
    用到了DriverObject域的InLoadOrderLinks链表

注意:
   下面的代码会用到一个宏:
---------------------------------------------------------------------------------------------------------------------
CONTAINING_RECORD 这样的一个宏,它的定义如下:
#define CONTAINING_RECORD(address, type, field) ((type *)( (PCHAR)(address) - (ULONG_PTR)(&((type*)0)->field)))

根据网上资料:就是address -(field在type中的偏移)
----------------------------------------------------------------------------------------------------------------------
*/
VOID Method1(IN PDRIVER_OBJECT DriverObject)//遍历链表
{
 ULONG Base=0;//模块基地址
 LDR_DATA_TABLE_ENTRY* SectionBase=NULL;
 LIST_ENTRY* Entry=NULL;
    LIST_ENTRY InLoadOrderLinks;
    ULONG num=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);
}

void Method2()//ZwQuerySystemInformation大法
{
 PVOID pBuffer=0;//缓冲区
 NTSTATUS Result;//查询结果
 ULONG NeedSize;
 PSYSTEM_MODULE_INFORMATION pSystemModuleInformation;//将结果强制转换为该类型
 ULONG BufferSize = 0x5000;//初始分配内存大小,没有采用查询再分配的循环方法
 ULONG ModuleCount;//模块总数
 ULONG i;
 do
 {
  pBuffer=ExAllocatePool(NonPagedPool,BufferSize);
  if(pBuffer==NULL)
  {
   DbgPrint("分配内存失败!\n");
   return FALSE;
  }
  Result=ZwQuerySystemInformation(SystemModuleInformation,pBuffer,BufferSize,&NeedSize);
  if(Result==STATUS_INFO_LENGTH_MISMATCH )//分配不够
  {
   ExFreePool(pBuffer);
   //大小乘以2,重新分配
   BufferSize*=2;
  }
  else if(!NT_SUCCESS(Result))//失败,放弃吧
  {
   DbgPrint( "查询失败,错误码:%8X\n", Result );
   ExFreePool(pBuffer);
   return FALSE;
  }
  }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[i].ImageName, pSystemModuleInformation->Module[i].Base );
 }
 DbgPrint("方法二得到模块总数:%d\n",ModuleCount);
 ExFreePool(pBuffer);
 return TRUE;
}

void Method3(ULONG Base)//,OUT PVOID* BaseAddress,OUT PVOID* ImageSize)//搜索内存,从0x80000000-----0xa0000000
{
 for(Base&=0xfffff000;;Base-=PAGE_SIZE)
 {
  if(MmIsAddressValid((PVOID)Base)&&*(USHORT*)Base==IMAGE_DOS_SIGNATURE )  //MZ标识
  {
   PVOID NTHeader=RtlImageNtHeader((PVOID)Base);//获得NT头指针  RtlImageNtHeader()函数返回一个指向给定映像文件 PE 头部的指针
            if(MmIsAddressValid((PVOID)NTHeader)&&*(ULONG*)NTHeader==IMAGE_NT_SIGNATURE)     //PE文件标识
   {
    //MSDN:The ARGUMENT_PRESENT macro takes an argument pointer and returns FALSE if the pointer is NULL, TRUE otherwise.
    /*if (ARGUMENT_PRESENT (BaseAddress))
     *BaseAddress = (PVOID)SomeAddress;

                if (ARGUMENT_PRESENT (ImageSize))
                    *ImageSize = ((IMAGE_NT_HEADERS*)NtHeader)->OptionalHeader.SizeOfImage;*/
    DbgPrint("地址:%8X\n",Base);
    break;
   }
  }
  DbgPrint("搜索%8X中...\n",Base);
  if(Base<0x80000000)
  {
   DbgPrint("搜索失败!\n");
    break;
  }
   
 }
}
//内核中FS寄存器指向KPCR结构,每个处理器都有一个,使用第一个处理器即可其中比较重要的是KdVersionBlock这个指针, 它指向一个DBGKD_GET_VERSION64这个结构.

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

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

//-------------------------------------仔细观察定义会发现,这个跟使用DriverObject方法达到的链表示一样的!
void Method4()                              
{
 ULONG Addr;//内核地址

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

    ULONG num=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);
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegistryPath)
{
 ULONG EntryAddr;
 _asm
 {
  push ecx;
  lea ecx,[ebp][4];//得到DriverEntry返回地址
  mov EntryAddr,ecx;
  pop ecx;
 }
 EntryAddr=*(ULONG*)EntryAddr;
 DbgPrint("驱动返回地址:%8X\n",EntryAddr);
 RtlInitUnicodeString(&BaseName,L"ntoskrnl.exe");
 DbgPrint("驱动加载成功!\n");
 //-------------------------------//
 //Method1(pDriverObject);
 //-------------------------------//
 Method2();
    //-------------------------------//
 //Method4();
 //-------------------------------//
 Method3(EntryAddr);//,NULL,NULL);
 //-------------------------------//
 pDriverObject->DriverUnload=DriverUnload;
 return STATUS_SUCCESS;
}
NTSTATUS DriverUnload()
{
 DbgPrint("驱动卸载成功\n");
}

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值