SoftICE可以本地调试,但现在开发商已经不再更新了,没法调试新的系统环境;WinDbg不能本地调试,现在流行用虚拟机来双机调试;dbgview我不了解。
用管理员启动driver Monitor ,如果不行看一下vs编译的时候driver setting->general ->target os version 是不是windows7,stampinfo和inf2cat禁用没禁用网上说的比较常见的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,不明白为何
环境:虚拟机VMWare:WIN 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 -(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=0i<ModuleCounti++)
{
DbgPrint( "方法二遍历模块名称:%s,地址:%8X\n", pSystemModuleInformation->Module[i].ImageName, pSystemModuleInformation->Module[i].Base )
}
DbgPrint("方法二得到模块总数:%d\n",ModuleCount)
ExFreePool(pBuffer)
return TRUE
}
VOID Method3(ULONG Base)//搜索内存,从0x80000000-----0xa0000000
{
}
//内核中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()
//-------------------------------//
Method3()
//-------------------------------//
Method4()
//-------------------------------//
pDriverObject->DriverUnload=DriverUnload
return STATUS_SUCCESS
}
NTSTATUS DriverUnload()
{
DbgPrint("驱动卸载成功\n")
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)