網上說的比較常見的4種方法:

1、通過DriverEntry傳入的DriverObject參數的DriverSection成員指向LDR_DATA_TABLE_ENTRY結構,通過遍歷這張表得到ntoskrnl的基址和大小

2ZwQuerySystemInformation大法

3、搜索記憶體 

4、利用KPCR結構

存在的問題:

1、第1種方法和第4種方法得到的結果比ZwQuerySystemInformation少一個

2、第1種方法如果輸出BaseDllNamentoskrnl.exe,如果輸出FullDllName則是:\WINDOWS\system32\ntkrnlpa.exe,位址都是:804d8000,不明白為何

環境:虛擬機器VMWareWIN XP SP3  + WDK ---- WINXP Check方式編譯


 

#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)

 

//---------------------------------------------------------------------------------------------------//函式宣告

 

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

 

                        );

 

 

 

#pragma alloc_text(INIT, DriverEntry)

 

#pragma alloc_text(PAGE, DriverUnload)

 

//---------------------------------------------------------------------------------------------------//變數、常量、結構定義

 

UNICODE_STRING BaseName;

 

 

 

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

 

 

 

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;

 

 

 

 

 

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

 

/*

 

    用到了DriverObject域的InLoadOrderLinks鏈表

 

 

 

注意:

 

   下面的代碼會用到一個宏:

 

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

 

CONTAINING_RECORD 這樣的一個宏,它的定義如下:

 

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

 

 

 

根據網上資料:就是address -(fieldtype中的偏移)

 

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

 

*/

 

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.ImageName, pSystemModuleInformation->Module.Base );

 

  }

 

  DbgPrint("方法二得到模組總數:%d\n",ModuleCount);

 

  ExFreePool(pBuffer);

 

  return TRUE;

 

}

 

VOID Method3(ULONG Base)//搜索記憶體,從0x80000000-----0xa0000000

 

{

 

  ;

 

}

 

//內核中FS寄存器指向KPCR結構,每個處理器都有一個,使用第一個處理器即可其中比較重要的是KdVersionBlock這個指標, 它指向一個DBGKD_GET_VERSION64這個結構.

 

 

 

//這個結構體裡面包含了一些重要資訊。如:PsLoadedModuleList ,它是Windows載入的所有內核模組構成的鏈表的表頭

 

 

 

//兩個處理器對應的KPCR結構是有區別的, 只有第一個處理器的KPCRKdVersionBlock才指向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();

 

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

 

  Method3();

 

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

 

  Method4();

 

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

 

  pDriverObject->DriverUnload=DriverUnload;

 

  return STATUS_SUCCESS;

 

}

 

NTSTATUS DriverUnload()

 

{

 

  DbgPrint("驅動卸載成功\n");

 

}


arrow
arrow
    全站熱搜

    殘月影 發表在 痞客邦 留言(0) 人氣()