软件工程内核级HOOK的几种实现与应用.docx
《软件工程内核级HOOK的几种实现与应用.docx》由会员分享,可在线阅读,更多相关《软件工程内核级HOOK的几种实现与应用.docx(36页珍藏版)》请在冰豆网上搜索。
软件工程内核级HOOK的几种实现与应用
内核级HOOK的几种实现与应用
实现内核级HOOK对于拦截、分析、跟踪系统内核起着致关重要的作用。
实现的方法不同意味着应用侧重点的不同。
如想要拦截NATIVEAPI那么可能常用的就是HOOKSERVICETABLE的方法。
如果要分析一些系统调用,那么可能想到用HOOKINT2E中断来实现。
如果想要拦截或跟踪其他内核DRIVER的调用,那么就要用到HOOKPE的方法来实现。
这里我们更注重的是实现,原理方面已有不少高手在网上发表过文章。
大家可以结合起来读。
下面以我写的几个实例程序来讲解一下各种方法的实现。
错误之处还望各位指正。
1、HOOKSERVICETABLE方法:
这种方法对于拦截NATIVEAPI来说用的比较多。
原理就是通过替换系统导
出的一个SERVICETABLE中相应的NATIVEAPI的地址来达到拦截的目的。
因为此方法较为简单,网上也有不少资料来介绍。
所以这里就不给出实例程序了。
SERVICETABLE的结构如下:
typedefstructServiceDescriptorEntry{
unsignedint*ServiceTableBase;
unsignedint*ServiceCounterTableBase;
unsignedintNumberOfServices;
unsignedchar*ParamTableBase;
}ServiceDescriptorTableEntry_t,*PServiceDescriptorTableEntry_t;
2、HOOKINT2E方法:
这种方法对于跟踪、分析系统调用来说用的比较多。
原理是通过替换IDT
表中的INT2E中断,使之指向我们自己的中断服务处理例程来实现的。
掌握
此方法需要你对保护模式有一定的基础。
下面的程序演示了这一过程。
/*****************************************************************
文件名:
WssHookInt2e.c
描述:
系统调用跟踪
作者:
sinister
最后修改日期:
2002-11-02
*****************************************************************/
#include"ntddk.h"
#include"string.h"
#defineDWORDunsigned__int32
#defineWORDunsigned__int16
#defineBYTEunsigned__int8
#defineBOOL__int32
#defineLOWORD(l)((WORD)(l))
#defineHIWORD(l)((WORD)(((DWORD)(l)>>16)&0xFFFF))
#defineLOBYTE(w)((BYTE)(w))
#defineHIBYTE(w)((BYTE)(((WORD)(w)>>8)&0xFF))
#defineMAKELONG(a,b)((LONG)(((WORD)(a))|((DWORD)((WORD)(b)))<<16))
#defineSYSTEMCALL0x2e
#defineSYSNAME"System"
#definePROCESSNAMELEN16
#pragmapack
(1)
//定义IDTR
typedefstructtagIDTR{
WORDIDTLimit;
WORDLowIDTbase;
WORDHiIDTbase;
}IDTR,*PIDTR;
//定义IDT
typedefstructtagIDTENTRY{
WORDOffsetLow;
WORDselector;
BYTEunused_lo;
unsignedcharunused_hi:
5;
unsignedcharDPL:
2;
unsignedcharP:
1;
WORDOffsetHigh;
}IDTENTRY,*PIDTENTRY;
#pragmapack()
DWORDOldInt2eService;
ULONGProcessNameOffset;
TCHARProcessName[PROCESSNAMELEN];
staticNTSTATUSMydrvDispatch(INPDEVICE_OBJECTDeviceObject,INPIRPIrp);
VOIDDriverUnload(INPDRIVER_OBJECTpDriverObject);
ULONGGetProcessNameOffset();
VOIDGetProcessName(PCHARName);
VOIDInstallNewInt2e();
VOIDUninstallNewInt2e();
VOID__fastcallNativeApiCall()
{
KIRQLOldIrql;
DWORDServiceID;
DWORDProcessId;
__asmmovServiceID,eax;
ProcessId=(DWORD)PsGetCurrentProcessId();
GetProcessName(ProcessName);
KeRaiseIrql(HIGH_LEVEL,&OldIrql);//提升当前的IRQL级别防止被中断
switch(ServiceID)
{
case0x20:
DbgPrint("NEWINT2E:
ProcessName:
%s;ProcessID:
%d;NativeApi:
NtCreateFile()\n",ProcessName,ProcessId);
break;
case0x2b:
DbgPrint("NEWINT2E:
ProcessName:
%s;ProcessID:
%d;NativeApi:
NtCreateSection()\n",ProcessName,ProcessId);
break;
case0x30:
DbgPrint("NEWINT2E:
ProcessName:
%s;ProcessID:
%d;NativeApi:
NtCreateToken()\n",ProcessName,ProcessId);
break;
}
KeLowerIrql(OldIrql);//恢复原始IRQL
}
__declspec(naked)NewInt2eService()
{
__asm{
pushad
pushfd
pushfs
movbx,0x30
movfs,bx
pushds
pushes
sti
callNativeApiCall;//调用记录函数
cli
popes
popds
popfs
popfd
popad
jmpOldInt2eService;//跳到原始INT2E继续工作
}
}
VOIDInstallNewInt2e()
{
IDTRidtr;
PIDTENTRYOIdt;
PIDTENTRYNIdt;
//得到IDTR中得段界限与基地址
__asm{
sidtidtr;
}
//得到IDT基地址
OIdt=(PIDTENTRY)MAKELONG(idtr.LowIDTbase,idtr.HiIDTbase);
//保存原来的INT2E服务例程
OldInt2eService=MAKELONG(OIdt[SYSTEMCALL].OffsetLow,OIdt[SYSTEMCALL].OffsetHigh);
NIdt=&(OIdt[SYSTEMCALL]);
__asm{
cli
leaeax,NewInt2eService;//得到新的INT2E服务例程偏移
movebx,NIdt;
mov[ebx],ax;//INT2E服务例程低16位
shreax,16//INT2E服务例程高16位
mov[ebx+6],ax;
lidtidtr//装入新的IDT
sti
}
}
VOIDUninstallNewInt2e()
{
IDTRidtr;
PIDTENTRYOIdt;
PIDTENTRYNIdt;
__asm{
sidtidtr;
}
OIdt=(PIDTENTRY)MAKELONG(idtr.LowIDTbase,idtr.HiIDTbase);
NIdt=&(OIdt[SYSTEMCALL]);
_asm{
cli
leaeax,OldInt2eService;
movebx,NIdt;
mov[ebx],ax;
shreax,16
mov[ebx+6],ax;
lidtidtr
sti
}
}
//驱动入口
NTSTATUSDriverEntry(INPDRIVER_OBJECTDriverObject,INPUNICODE_STRINGRegistryPath)
{
UNICODE_STRINGnameString,linkString;
PDEVICE_OBJECTdeviceObject;
NTSTATUSstatus;
HANDLEhHandle;
inti;
//卸载驱动
DriverObject->DriverUnload=DriverUnload;
//建立设备
RtlInitUnicodeString(&nameString,L"\\Device\\WssHookInt2e");
status=IoCreateDevice(DriverObject,
0,
&nameString,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&deviceObject
);
if(!
NT_SUCCESS(status))
returnstatus;
RtlInitUnicodeString(&linkString,L"\\DosDevices\\WssHookInt2e");
status=IoCreateSymbolicLink(&linkString,&nameString);
if(!
NT_SUCCESS(status))
{
IoDeleteDevice(DriverObject->DeviceObject);
returnstatus;
}
for(i=0;iDriverObject->MajorFunction[i]=MydrvDispatch;
}
DriverObject->DriverUnload=DriverUnload;
ProcessNameOffset=GetProcessNameOffset();
InstallNewInt2e();
returnSTATUS_SUCCESS;
}
//处理设备对象操作
staticNTSTATUSMydrvDispatch(INPDEVICE_OBJECTDeviceObject,INPIRPIrp)
{
Irp->IoStatus.Status=STATUS_SUCCESS;
Irp->IoStatus.Information=0L;
IoCompleteRequest(Irp,0);
returnIrp->IoStatus.Status;
}
VOIDDriverUnload(INPDRIVER_OBJECTpDriverObject)
{
UNICODE_STRINGnameString;
UninstallNewInt2e();
RtlInitUnicodeString(&nameString,L"\\DosDevices\\WssHookInt2e");
IoDeleteSymbolicLink(&nameString);
IoDeleteDevice(pDriverObject->DeviceObject);
return;
}
ULONGGetProcessNameOffset()
{
PEPROCESScurproc;
inti;
curproc=PsGetCurrentProcess();
//
//Scanfor12KB,hoppingtheKPEBnevergrowsthatbig!
//
for(i=0;i<3*PAGE_SIZE;i++){
if(!
strncmp(SYSNAME,(PCHAR)curproc+i,strlen(SYSNAME))){
returni;
}
}
//
//Namenotfound-oh,well
//
return0;
}
VOIDGetProcessName(PCHARName)
{
PEPROCESScurproc;
char*nameptr;
ULONGi;
if(ProcessNameOffset){
curproc=PsGetCurrentProcess();
nameptr=(PCHAR)curproc+ProcessNameOffset;
strncpy(Name,nameptr,16);
}else{
strcpy(Name,"?
?
?
");
}
}
3、HOOKPE方法
这种方法对于拦截、分析其他内核驱动的函数调用来说用的比较多。
原理
是根据替换PE格式导出表中的相应函数来实现的。
此方法中需要用到一些小
技巧。
如内核模式并没有直接提供类似应用层的GetModuleHandl()、GetProcAddress()等函数来获得模块的地址。
那么我们就需要自己来编写,这
里用到了一个未公开的函数与结构。
ZwQuerySystemInformation与SYSTEM_MODULE_INFORMATION来实现得到模块的基地址。
这样我们就可以根据
PE格式来枚举导出表中的函数来替换了。
但这又引出了一个问题,那就是从
WINDOWS2000后内核数据的页属性都是只读的,不能更改。
内核模式也没有
提供类似应用层的VirtualProtectEx()等函数来修改页面属性。
那么也需要
我们自己来编写。
因为我们是在内核模式所以我们可以通过修改cr0寄存器的
的写保护位来达到我们的目的。
这样我们所期望的拦截内核模式函数的功能便
得以实现。
此方法需要你对PE格式有一定的基础。
下面的程序演示了这一过程。
/*****************************************************************
文件名:
WssHookPE.c
描述:
拦截内核函数
作者:
sinister
最后修改日期:
2002-11-02
*****************************************************************/
#include"ntddk.h"
#include"windef.h"
typedefenum_SYSTEM_INFORMATION_CLASS{
SystemBasicInformation,
SystemProcessorInformation,
SystemPerformanceInformation,
SystemTimeOfDayInformation,
SystemNotImplemented1,
SystemProcessesAndThreadsInformation,
SystemCallCounts,
SystemConfigurationInformation,
SystemProcessorTimes,
SystemGlobalFlag,
SystemNotImplemented2,
SystemModuleInformation,
SystemLockInformation,
SystemNotImplemented3,
SystemNotImplemented4,
SystemNotImplemented5,
SystemHandleInformation,
SystemObjectInformation,
SystemPagefileInformation,
SystemInstructionEmulationCounts,
SystemInvalidInfoClass1,
SystemCacheInformation,
SystemPoolTagInformation,
SystemProcessorStatistics,
SystemDpcInformation,
SystemNotImplemented6,
SystemLoadImage,
SystemUnloadImage,
SystemTimeAdjustment,
SystemNotImplemented7,
SystemNotImplemented8,
SystemNotImplemented9,
SystemCrashDumpInformation,
SystemExceptionInformation,
SystemCrashDumpStateInformation,
SystemKernelDebuggerInformation,
SystemContextSwitchInformation,
SystemRegistryQuotaInformation,
SystemLoadAndCallImage,
SystemPrioritySeparation,
SystemNotImplemented10,
SystemNotImplemented11,
SystemInvalidInfoClass2,
SystemInvalidInfoClass3,
SystemTimeZoneInformation,
SystemLookasideInformation,
SystemSetTimeSlipEvent,
SystemCreateSession,
SystemDeleteSession,
SystemInvalidInfoClass4,
SystemRangeStartInformation,
SystemVerifierInformation,
SystemAddVerifier,
SystemSessionProcessesInformation
}SYSTEM_INFORMATION_CLASS;
typedefstructtagSYSTEM_MODULE_INFORMATION{
ULONGReserved[2];
PVOIDBase;
ULONGSize;
ULONGFlags;
USHORTIndex;
USHORTUnknown;
USHORTLoadCount;
USHORTModuleNameOffset;
CHARImageName[256];
}SYSTEM_MODULE_INFORMATION,*PSYSTEM_MODULE_INFORMATION;
#defineIMAGE_DOS_SIGNATURE0x5A4D//MZ
#defineIMAGE_NT_SIGNATURE0x50450000//PE00
#defineIMAGE_NT_SIGNATURE10x00004550//00EP
typedefstruct_IMAGE_DOS_HEADER{//DOS.EXEheader
WORDe_magic;//Magicnumber
WORDe_cblp;//Bytesonlastpageoffile
WORDe_cp;//Pagesinfile
WORDe_crlc;//Relocations
WORDe_cparhdr;//Sizeofheaderinparagraphs
WORDe_minalloc;//Minimumextraparagraphsneeded
WORDe_maxalloc;//Maximumextraparagraphsneeded
WORDe_ss;//Initial(relative)SSvalue
WORDe_sp;//InitialSPvalue
WORDe_csum;//Checksum
WORDe_ip;//InitialIPvalue
WORDe_cs;//Initial(relative)CSvalue
WORDe_lfarlc;//Fileaddressofrelocationtable
WORDe_ovno;//Overlaynumber
WORDe_res[4];//Reservedwords
WORDe_oemid;//OEMidentifier(fore_oeminfo)
WORDe_oeminfo;//OEMinformation;e_oemidspecific
WORDe_res2[10];//Reservedwords
LONGe_lfanew;//Fileaddressofnewexeheader
}IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER;
typedefstruct_IMAGE_FILE_HEADER{
WORDMachine;
WORDNumberOfSections;
DWORDTimeDateSta