`

Hook过滤架构搭建,仿照360(转)

阅读更多
http://bbs.pediy.com/archive/index.php?t-116033.html
仿照了下360 的过滤架构,搭建了个Hook 框架,360的Hook架构的确很优秀,我觉得很值得我们学习与研究。这里我按照大牛们已经逆向出来的思路实现了下代码(都逆向出来了坐下代码工作不会怎么样吧?….只是学习架构)。不要鄙视我等代码工………,好吧大牛们想BS就BS吧,我表示毫无压力~~~~,我是菜鸟我怕谁!

废话不多说发代码,如果有错误和白痴的地方请指出,我水平有限…….
搭建这个架构大致需要以下几个模块,一是安装KiFastCallEntry的Hook模块,二是FakeKiFastCallEntry代理模块,三是SysCallFilter系统调用是否过滤的判断模块。其余的模块主要是过滤函数了,还有个获取KiFastCallEntry的patch地址的模块,最后是释放模块和初始化模块,这样大致的架构就搭建起来了。
接下来看看每个模块是怎么工作的。



首先是安装KiFastCallEntry的Hook模块,这个原理我就不多说了,大家都懂的

/************************************************************************


* 函数名称:HookKiFastCallEntry


* 功能描述:安装KiFastCallEntry钩子


* 参数列表:





* 返回值:状态


*************************************************************************/


NTSTATUS HookKiFastCallEntry()


{


NTSTATUS status=STATUS_SUCCESS;


if (!GetKiFastCallEntryPatchAddr())


{


KdPrint(("(HookKiFastCallEntry) GetKiFastCallEntryPatchAddr failed"));


return STATUS_UNSUCCESSFUL;


}


RtlCopyMemory(OriginalHead2,(PVOID)PatchAddr,5);


*(ULONG *)(ReplaceHead2+1)=(ULONG)FakeKiFastCallEntry-(PatchAddr+5);


KIRQL Irql;


Irql=WOFF();


//写入新的函数头


RtlCopyMemory((BYTE *)PatchAddr,ReplaceHead2,5);


WON(Irql);


return status;




}
这个模块有个地方就是GetKiFastCallEntryPatchAddr()获取KiFastCallEntry的Patch点这个有点小技巧,大家可以学习下,360是用SetEvent钩子栈回朔实现的,这个大家听了应该都能明白,就是调用函数时候会PUSH 返回到的EIP,这个EIP就是KiFastCallEntry中的了。
要patch的地方是按特征码搜索的,这个是xp sp3的

BOOL GetKiFastCallEntryPatchAddr()


{


ULONG ulCallNum;


PULONG pHookAddr;


PBYTE pCode;


ULONG i;


BOOL bRet=true;


KIRQL Irql;


hFakeEvent=(HANDLE)FakeHandle;


ulCallNum=*(PULONG)((PBYTE)ZwSetEvent+1);


pHookAddr=(PULONG)(pSysCallFilterInfo->ulSSDTAddr+ulCallNum*4);


RealNtSetEvent=*pHookAddr;//保存真实地址


Irql=WOFF();


*pHookAddr=(ULONG)FakeNtSetEvent; // 写入代理地址


WON(Irql);


ZwSetEvent(hFakeEvent,NULL);


Irql=WOFF();


*pHookAddr=RealNtSetEvent; // 写回真实地址


WON(Irql);


if (MmIsAddressValid((PVOID)BackTrackingAddr))


{


pCode=(PBYTE)BackTrackingAddr;


for (i=0;i<SearchByte;i++)


{


if (*(pCode-i)==0xe1&&*(pCode-i-1)==0x2b)


{


PatchAddr=(ULONG)(pCode-i-1);


break;


}


if (*(pCode-i)==0xfc&&*(pCode-i-1)==0x8b)


{


RetAddress=(ULONG)(pCode-i-1);


}





}


}


if (!PatchAddr||!RetAddress)


{


bRet=false;


}


return bRet;

}





这个代理函数里面获取EIP


NTSTATUS FakeNtSetEvent (


__in HANDLE EventHandle,


__out_opt PLONG PreviousState


)


{


NTSTATUS status=STATUS_SUCCESS;


if (EventHandle!=hFakeEvent||ExGetPreviousMode()==UserMode)// 不是自己调用,或者调用来自UserMode,直接调用原函数


{


status=((NTSETEVENT)RealNtSetEvent)(&EventHandle, PreviousState);


}


else


{


_asm


{


mov eax,dword ptr [ebp+4h]


mov BackTrackingAddr,eax


}


}


return status;

}


安装好Hook后就是Hook的代理函数了


这段代码 ……..好吧被BS咱也莫有办法,代理函数传入三个参数,这三个参数的含义可以参考内核情景分析一书中有详细介绍,给SysCallFileter来判断是否过滤。


_declspec (naked) NTSTATUS FakeKiFastCallEntry()


{


_asm


{


mov edi,edi


pushfd


pushad


push edi


push ebx


push eax


call SysCallfilter


mov dword ptr [esp+10h],eax


popad


popfd


sub esp, ecx


shr ecx, 2


push RetAddress


retn





}

}


接下来就是判断过滤的函数了,这里我略去了SHADOW SSDT,这段代码也……


/************************************************************************


* 函数名称:SysCallfilter


* 功能描述:过滤系统调用


* 参数列表:


ULONG SysCallNum:系统调用号


ULONG FunAddr:系统调用函数入口地址


ULONG ServiceBase:系统调用表指针


* 返回值:过滤则返回代理函数地址,否则返回真实地址


*************************************************************************/


ULONG SysCallfilter(ULONG SysCallNum,ULONG FunAddr,ULONG ServiceBase)


{





if( ServiceBase==pSysCallFilterInfo->ulSSDTAddr&&SysCallNum<=pSysCallFilterInfo->ulSSDTNum)


{


if(pSysCallFilterInfo->SSDTSwitchTable[SysCallNum]&&HookOrNot(SysCallNum,FALSE))


{


return pSysCallFilterInfo->ProxySSDTTable[SysCallNum];//


}


}


return FunAddr;




}




这个模块可以考虑添加适当的过滤规则,但最好效率点,这里我没加什么过滤,主要是搭建框架。





/************************************************************************


* 函数名称:HookOrNot


* 功能描述:判断是否过滤系统调用


* 参数列表:


ULONG SysCallNum:系统调用号


BOOL Flags:SSDT还是SDOWSSDT标志


* 返回值:返回表示不过滤,表示过滤


*************************************************************************/


ULONG HookOrNot(ULONG SysCallNum,BOOL Flags)


{


if (ExGetPreviousMode()==KernelMode)


{


return 0;


}


if (Flags)


{


return 1;


}


else


return 1;

}




好了基本功能模块搭建好了,现在就要初始化这些模块内所要使用的数据结构,来运作起来。


初始化里面我直接把savessdttable原始函数表填充为文件获取的原始地址表了,这里大家可以不必这么做。


/************************************************************************


* 函数名称:InitSysCallFilter


* 功能描述:初始化系统调用过滤


* 参数列表:





* 返回值:状态


*************************************************************************/


NTSTATUS InitSysCallFilter()


{


NTSTATUS status=STATUS_SUCCESS;


PVOID FileBuffer,FunBuffer;


ULONG ulSSDTLimit;


PKSERVICE_TABLE_DESCRIPTOR pServiceDescriptor;


//init





//Init SysCallFilterInfo buffer


pSysCallFilterInfo=(PSYSCALL_FILTER_INFO_TABLE)ExAllocatePoolWithTag(


NonPagedPool,


sizeof(SYSCALL_FILTER_INFO_TABLE),


MM_TAG_FILT);


RtlZeroMemory(pSysCallFilterInfo,sizeof(SYSCALL_FILTER_INFO_TABLE));


//Init SSDT address


pServiceDescriptor=(PKSERVICE_TABLE_DESCRIPTOR)GetKeServiceDescriptorTable();


pSysCallFilterInfo->ulSSDTAddr=(ULONG)pServiceDescriptor->Base;


//Init SSDT Table





FileBuffer=ExAllocatePoolWithTag(NonPagedPool,(SSDT_MAX_NUM)*sizeof(ULONG),MM_TAG_FILT);


FunBuffer=ExAllocatePoolWithTag(NonPagedPool,(SSDT_MAX_NUM)*sizeof(ULONG),MM_TAG_FILT);


if (!FileBuffer||!FunBuffer)


{


KdPrint(("(InitSysCallFilter) MmBuffer FunBuffer failed"));


return STATUS_UNSUCCESSFUL;


}


status=EnumOriginalSSDT(FileBuffer,FunBuffer,&ulSSDTLimit);


if (!NT_SUCCESS(status))


{


KdPrint(("(InitSysCallFilter) EnumOriginalSSDT failed"));


ExFreePool(FileBuffer);


ExFreePool(FunBuffer);


return STATUS_UNSUCCESSFUL;


}


memcpy(pSysCallFilterInfo->SavedSSDTTable,FileBuffer,ulSSDTLimit*4);


ExFreePool(FileBuffer);


ExFreePool(FunBuffer);


pSysCallFilterInfo->ulSSDTNum=ulSSDTLimit;


//Init Proxy SSDT table


pSysCallFilterInfo->ProxySSDTTable[97]=(ULONG)FakeNtLoadDriver;


//这里就可以随意添加Hook,相当方便


//Init SSDT Swicth table


pSysCallFilterInfo->SSDTSwitchTable[97]=1;


//记得要开开关


return status;


}





最后是释放清理模块了。


void UnHookKiFastCallEntry()


{


KIRQL Irql;


if (*(PULONG)OriginalHead2)


{


Irql=WOFF();


//写回原来的函数头


RtlCopyMemory((BYTE *)PatchAddr,OriginalHead2,5);


WON(Irql);


}


};





NTSTATUS FreeSysCallFilter()


{


NTSTATUS status=STATUS_SUCCESS;


UnHookKiFastCallEntry();


if (pSysCallFilterInfo)


{


ExFreePool(pSysCallFilterInfo);


}


return status;


}


这里顺带发个过滤函数以及R3通信架构的搭建好了


这个过滤是NtLoadDriver的


NTSTATUS FakeNtLoadDriver( __in PUNICODE_STRING DriverServiceName)


{


PEPROCESS pCurProcess;


DRIVER_TRANS_INFO DriverTransInfo;


if (DriverServiceName==NULL)


{


return ((NTLOADDRIVER)pSysCallFilterInfo->SavedSSDTTable[97])(DriverServiceName);


}


DriverTransInfo.Size=sizeof(DRIVER_TRANS_INFO);


pCurProcess=PsGetCurrentProcess();


if (pCurProcess)


{


GetProcessFullPathW((ULONG)pCurProcess,DriverTransInfo.ProcessFullPath);


}


RtlStringCchCopyW(DriverTransInfo.WarmReason,MAX_REASON*sizeof(WCHAR),L"尝试加载驱动,一旦加载驱动进程将会获得最高权限,允许此操作将可能导致危险发生,驱动文件为:");


RtlStringCchCatW(DriverTransInfo.WarmReason,MAX_PATH*sizeof(WCHAR),DriverServiceName->Buffer);


if (!GoOrNot((PVOID)&DriverTransInfo,TYPE_DRIVER_MONITOR))


{


return STATUS_ACCESS_DENIED;


}


else


{


return ((NTLOADDRIVER)pSysCallFilterInfo->SavedSSDTTable[97])(DriverServiceName);


}




}




然后是GoOrNot与R3通信等待R3命令


BOOL GoOrNot(__in PVOID pMonitorInfo,__in ULONG Type)


{


BOOL bRet=false;


switch (Type)


{


case TYPE_DRIVER_MONITOR:


bRet=GetUserCommand(g_DeviceExtension->DriverMonitorInfo.pNotifyEvent,


g_DeviceExtension->DriverMonitorInfo.SharedMemInfo.pShareMemory,


pMonitorInfo,

sizeof(DRIVER_TRANS_INFO));
break;

default:


;


}


return bRet;




}

BOOL GetUserCommand(__in PKEVENT pNotifyEvent,


__in PVOID pShareMemory,


__in PVOID pTransInfo,


__in ULONG pTransLen)


{


BOOL bRet;


PDRIVER_TRANS_INFO pDriverTransInfo;


memcpy(pShareMemory,pTransInfo,pTransLen);


KeSetEvent(pNotifyEvent,0,false);


KeWaitForSingleObject(


pNotifyEvent,


Executive,


KernelMode,


false,


NULL);


pDriverTransInfo=(PDRIVER_TRANS_INFO)pShareMemory;


if (pDriverTransInfo->Command==COMMAND_GO)


{


bRet=true;


}


else if (pDriverTransInfo->Command==COMMAND_STOP)


{


bRet=false;


}


return bRet;

}
这里发段R3和R0共享内存的,用的是内核创建pool在建MDL映射到用户空间的方法。

BOOL CreateSharedMemory(__out PSHARE_MEMORY_INFO pShareMemInfo,
__in ULONG MemorySize)
{
BOOL bRet=true;
PMDL pMdl;
PVOID UserVAToReturn;
PIO_STACK_LOCATION pIoStackLocation;
ULONG ulBufferLengthOut;
PVOID pSharedBuffer;
pSharedBuffer=ExAllocatePoolWithTag(NonPagedPool,MemorySize,MM_TAG_ANTI);
if (!pSharedBuffer)
{
KdPrint(("(IrpCreateSharedMemory) pSharedBuffer allocate failed"));
return false;
}
pMdl=IoAllocateMdl(pSharedBuffer,MemorySize,false,false,NULL);
if (!pMdl)
{
KdPrint(("(IrpCreateSharedMemory) IoAllocateMdl( failed"));
ExFreePool(pSharedBuffer);
return false;
}
MmBuildMdlForNonPagedPool(pMdl);
UserVAToReturn=MmMapLockedPagesSpecifyCache(pMdl,
UserMode,
MmCached,
NULL,
false,
NormalPagePriority);
if (!UserVAToReturn)
{
IoFreeMdl(pMdl);
ExFreePool(pSharedBuffer);
return false;
}
RtlZeroMemory(pSharedBuffer,MemorySize);
KdPrint(("UserVAToReturn:0x%08x",UserVAToReturn));
//输出
pShareMemInfo->pShareMemory=pSharedBuffer;
pShareMemInfo->pSharedMdl=pMdl;
pShareMemInfo->UserVA=(ULONG)UserVAToReturn;
return bRet;
}





R3的创建事件和开线程我就不发了,很简单大家可以自己尝试下。


最后附下整个架构的部分数据结构


//GoOrNot Type宏定义


#define TYPE_DRIVER_MONITOR 0x01


//GoOrNot Command宏定义


#define COMMAND_GO 0x01


#define COMMAND_STOP 0x02


//危险拦截提示语句


#define WARM_DRI_LOAD L"尝试加载驱动,一旦加载驱动进程将会获得系统最高权限,允许此操作将可能导致危险发生,驱动文件路径:"


//************数据定义***************************************************


typedef struct _SYSCALL_FILTER_INFO_TABLE


{


ULONG ulSSDTAddr;


ULONG ulSHADOWSSDTAddr;


ULONG ulSSDTNum;


ULONG ulSHADOWSSDTNum;


ULONG SavedSSDTTable[SSDT_FILTER_NUM]; //SSDT原始函数地址表


ULONG ProxySSDTTable[SHADOWSSDT_FILTER_NUM]; //SSDT代理函数地址表


ULONG SavedShadowSSDTTable[SSDT_FILTER_NUM]; //ShadowSSDT原始函数地址表


ULONG ProxyShadowSSDTTable[SHADOWSSDT_FILTER_NUM]; //ShadowSSDT代理函数地址表


ULONG SSDTSwitchTable[SSDT_FILTER_NUM]; //SSDT Hook开关表


ULONG ShadowSSDTSwitchTable[SHADOWSSDT_FILTER_NUM];//ShadowSSDT Hook开关表

}SYSCALL_FILTER_INFO_TABLE,*PSYSCALL_FILTER_INFO_TABLE;

好的宏定义也可以简化工程,这里大家可自行考虑。





这样差不多整个架构就搭建起来了,一个小型的监控系统就可以完成了。优秀的架构的确可以事半功倍,不过过滤函数的规则其实才是重中之重呀……………..。大家可以多讨论下,这个过滤规则是很需要仔细研究的。当然你要藏着咱也没办法呵…………


最后说下:


由于这个源代码是我一个大文件里面的一部分,所以整个也不好给出,其实也没必要给出来,毕竟没多少技术含量,大家都可以写得出的,这里只是就框架总结下而已。全部发了也没意思一大堆你也不想看,还不如发点核心的,然后你也可以尝试搭建下自己的更有乐趣呢!

第一次发这种贴,如果有不当之处敬请谅解。

游猎夕阳
2010-07-01, 13:49:49
这,第一次发怎么格式变了.........预览还好好的怎么发出来,间距这么大啊悲剧

kanxue
2010-07-01, 13:56:30
这,第一次发怎么格式变了.........预览还好好的怎么发出来,间距这么大啊悲剧

不用预览,你在记事本排好版,直接复制粘贴上来即可。

游猎夕阳
2010-07-01, 14:05:11
哦第一次发长段的没经验谢谢了!

游猎夕阳
2010-07-01, 14:11:54
补发下上面的太难看了

仿照了下360 的过滤架构,搭建了个Hook 框架,360的Hook架构的确很优秀,我觉得很值得我们学习与研究。这里我按照大牛们已经逆向出来的思路实现了下代码(都逆向出来了坐下代码工作不会怎么样吧?….只是学习架构)。不要鄙视我等代码工………,好吧大牛们想BS就BS吧,我表示毫无压力~~~~,我是菜鸟我怕谁!

废话不多说发代码,如果有错误和白痴的地方请指出,我水平有限…….
搭建这个架构大致需要以下几个模块,一是安装KiFastCallEntry的Hook模块,二是FakeKiFastCallEntry代理模块,三是SysCallFilter系统调用是否过滤的判断模块。其余的模块主要是过滤函数了,还有个获取KiFastCallEntry的patch地址的模块,最后是释放模块和初始化模块,这样大致的架构就搭建起来了。
接下来看看每个模块是怎么工作的。

首先是安装KiFastCallEntry的Hook模块,这个原理我就不多说了,大家都懂的
/************************************************************************
* 函数名称:HookKiFastCallEntry
* 功能描述:安装KiFastCallEntry钩子
* 参数列表:

* 返回值:状态
*************************************************************************/
NTSTATUS HookKiFastCallEntry()
{
NTSTATUS status=STATUS_SUCCESS;
if (!GetKiFastCallEntryPatchAddr())
{
KdPrint(("(HookKiFastCallEntry) GetKiFastCallEntryPatchAddr failed"));
return STATUS_UNSUCCESSFUL;
}
RtlCopyMemory(OriginalHead2,(PVOID)PatchAddr,5);
*(ULONG *)(ReplaceHead2+1)=(ULONG)FakeKiFastCallEntry-(PatchAddr+5);
KIRQL Irql;
Irql=WOFF();
//写入新的函数头
RtlCopyMemory((BYTE *)PatchAddr,ReplaceHead2,5);
WON(Irql);
return status;

}
这个模块有个地方就是GetKiFastCallEntryPatchAddr()获取KiFastCallEntry的Patch点这个有点小技巧,大家可以学习下,360是用SetEvent钩子栈回朔实现的,这个大家听了应该都能明白,就是调用函数时候会PUSH 返回到的EIP,这个EIP就是KiFastCallEntry中的了。
要patch的地方是按特征码搜索的,这个是xp sp3的
BOOL GetKiFastCallEntryPatchAddr()
{
ULONG ulCallNum;
PULONG pHookAddr;
PBYTE pCode;
ULONG i;
BOOL bRet=true;
KIRQL Irql;
hFakeEvent=(HANDLE)FakeHandle;
ulCallNum=*(PULONG)((PBYTE)ZwSetEvent+1);
pHookAddr=(PULONG)(pSysCallFilterInfo->ulSSDTAddr+ulCallNum*4);
RealNtSetEvent=*pHookAddr;//保存真实地址
Irql=WOFF();
*pHookAddr=(ULONG)FakeNtSetEvent; // 写入代理地址
WON(Irql);
ZwSetEvent(hFakeEvent,NULL);
Irql=WOFF();
*pHookAddr=RealNtSetEvent; // 写回真实地址
WON(Irql);
if (MmIsAddressValid((PVOID)BackTrackingAddr))
{
pCode=(PBYTE)BackTrackingAddr;
for (i=0;i<SearchByte;i++)
{
if (*(pCode-i)==0xe1&&*(pCode-i-1)==0x2b)
{
PatchAddr=(ULONG)(pCode-i-1);
break;
}
if (*(pCode-i)==0xfc&&*(pCode-i-1)==0x8b)
{
RetAddress=(ULONG)(pCode-i-1);
}

}
}
if (!PatchAddr||!RetAddress)
{
bRet=false;
}
return bRet;
}

这个代理函数里面获取EIP
NTSTATUS FakeNtSetEvent (
__in HANDLE EventHandle,
__out_opt PLONG PreviousState
)
{
NTSTATUS status=STATUS_SUCCESS;
if (EventHandle!=hFakeEvent||ExGetPreviousMode()==UserMode)// 不是自己调用,或者调用来自UserMode,直接调用原函数
{
status=((NTSETEVENT)RealNtSetEvent)(&EventHandle, PreviousState);
}
else
{
_asm
{
mov eax,dword ptr [ebp+4h]
mov BackTrackingAddr,eax
}
}
return status;
}

安装好Hook后就是Hook的代理函数了
这段代码 ……..好吧被BS咱也莫有办法,代理函数传入三个参数,这三个参数的含义可以参考内核情景分析一书中有详细介绍,给SysCallFileter来判断是否过滤。
_declspec (naked) NTSTATUS FakeKiFastCallEntry()
{
_asm
{
mov edi,edi
pushfd
pushad
push edi
push ebx
push eax
call SysCallfilter
mov dword ptr [esp+10h],eax
popad
popfd
sub esp, ecx
shr ecx, 2
push RetAddress
retn

}
}

接下来就是判断过滤的函数了,这里我略去了SHADOW SSDT,这段代码也……
/************************************************************************
* 函数名称:SysCallfilter
* 功能描述:过滤系统调用
* 参数列表:
ULONG SysCallNum:系统调用号
ULONG FunAddr:系统调用函数入口地址
ULONG ServiceBase:系统调用表指针
* 返回值:过滤则返回代理函数地址,否则返回真实地址
*************************************************************************/
ULONG SysCallfilter(ULONG SysCallNum,ULONG FunAddr,ULONG ServiceBase)
{

if( ServiceBase==pSysCallFilterInfo->ulSSDTAddr&&SysCallNum<=pSysCallFilterInfo->ulSSDTNum)
{
if(pSysCallFilterInfo->SSDTSwitchTable[SysCallNum]&&HookOrNot(SysCallNum,FALSE))
{
return pSysCallFilterInfo->ProxySSDTTable[SysCallNum];//
}
}
return FunAddr;

}

这个模块可以考虑添加适当的过滤规则,但最好效率点,这里我没加什么过滤,主要是搭建框架。

/************************************************************************
* 函数名称:HookOrNot
* 功能描述:判断是否过滤系统调用
* 参数列表:
ULONG SysCallNum:系统调用号
BOOL Flags:SSDT还是SDOWSSDT标志
* 返回值:返回表示不过滤,表示过滤
*************************************************************************/
ULONG HookOrNot(ULONG SysCallNum,BOOL Flags)
{
if (ExGetPreviousMode()==KernelMode)
{
return 0;
}
if (Flags)
{
return 1;
}
else
return 1;
}

好了基本功能模块搭建好了,现在就要初始化这些模块内所要使用的数据结构,来运作起来。
初始化里面我直接把savessdttable原始函数表填充为文件获取的原始地址表了,这里大家可以不必这么做。
/************************************************************************
* 函数名称:InitSysCallFilter
* 功能描述:初始化系统调用过滤
* 参数列表:

* 返回值:状态
*************************************************************************/
NTSTATUS InitSysCallFilter()
{
NTSTATUS status=STATUS_SUCCESS;
PVOID FileBuffer,FunBuffer;
ULONG ulSSDTLimit;
PKSERVICE_TABLE_DESCRIPTOR pServiceDescriptor;
//init

//Init SysCallFilterInfo buffer
pSysCallFilterInfo=(PSYSCALL_FILTER_INFO_TABLE)ExAllocatePoolWithTag(
NonPagedPool,
sizeof(SYSCALL_FILTER_INFO_TABLE),
MM_TAG_FILT);
RtlZeroMemory(pSysCallFilterInfo,sizeof(SYSCALL_FILTER_INFO_TABLE));
//Init SSDT address
pServiceDescriptor=(PKSERVICE_TABLE_DESCRIPTOR)GetKeServiceDescriptorTable();
pSysCallFilterInfo->ulSSDTAddr=(ULONG)pServiceDescriptor->Base;
//Init SSDT Table

FileBuffer=ExAllocatePoolWithTag(NonPagedPool,(SSDT_MAX_NUM)*sizeof(ULONG),MM_TAG_FILT);
FunBuffer=ExAllocatePoolWithTag(NonPagedPool,(SSDT_MAX_NUM)*sizeof(ULONG),MM_TAG_FILT);
if (!FileBuffer||!FunBuffer)
{
KdPrint(("(InitSysCallFilter) MmBuffer FunBuffer failed"));
return STATUS_UNSUCCESSFUL;
}
status=EnumOriginalSSDT(FileBuffer,FunBuffer,&ulSSDTLimit);
if (!NT_SUCCESS(status))
{
KdPrint(("(InitSysCallFilter) EnumOriginalSSDT failed"));
ExFreePool(FileBuffer);
ExFreePool(FunBuffer);
return STATUS_UNSUCCESSFUL;
}
memcpy(pSysCallFilterInfo->SavedSSDTTable,FileBuffer,ulSSDTLimit*4);
ExFreePool(FileBuffer);
ExFreePool(FunBuffer);
pSysCallFilterInfo->ulSSDTNum=ulSSDTLimit;
//Init Proxy SSDT table
pSysCallFilterInfo->ProxySSDTTable[97]=(ULONG)FakeNtLoadDriver;
//这里就可以随意添加Hook,相当方便
//Init SSDT Swicth table
pSysCallFilterInfo->SSDTSwitchTable[97]=1;
//记得要开开关
return status;
}

最后是释放清理模块了。
void UnHookKiFastCallEntry()
{
KIRQL Irql;
if (*(PULONG)OriginalHead2)
{
Irql=WOFF();
//写回原来的函数头
RtlCopyMemory((BYTE *)PatchAddr,OriginalHead2,5);
WON(Irql);
}
};

NTSTATUS FreeSysCallFilter()
{
NTSTATUS status=STATUS_SUCCESS;
UnHookKiFastCallEntry();
if (pSysCallFilterInfo)
{
ExFreePool(pSysCallFilterInfo);
}
return status;
}
这里顺带发个过滤函数以及R3通信架构的搭建好了
这个过滤是NtLoadDriver的
NTSTATUS FakeNtLoadDriver( __in PUNICODE_STRING DriverServiceName)
{
PEPROCESS pCurProcess;
DRIVER_TRANS_INFO DriverTransInfo;
if (DriverServiceName==NULL)
{
return ((NTLOADDRIVER)pSysCallFilterInfo->SavedSSDTTable[97])(DriverServiceName);
}
DriverTransInfo.Size=sizeof(DRIVER_TRANS_INFO);
pCurProcess=PsGetCurrentProcess();
if (pCurProcess)
{
GetProcessFullPathW((ULONG)pCurProcess,DriverTransInfo.ProcessFullPath);
}
RtlStringCchCopyW(DriverTransInfo.WarmReason,MAX_REASON*sizeof(WCHAR),L"尝试加载驱动,一旦加载驱动进程将会获得最高权限,允许此操作将可能导致危险发生,驱动文件为:");
RtlStringCchCatW(DriverTransInfo.WarmReason,MAX_PATH*sizeof(WCHAR),DriverServiceName->Buffer);
if (!GoOrNot((PVOID)&DriverTransInfo,TYPE_DRIVER_MONITOR))
{
return STATUS_ACCESS_DENIED;
}
else
{
return ((NTLOADDRIVER)pSysCallFilterInfo->SavedSSDTTable[97])(DriverServiceName);
}

}

然后是GoOrNot与R3通信等待R3命令
BOOL GoOrNot(__in PVOID pMonitorInfo,__in ULONG Type)
{
BOOL bRet=false;
switch (Type)
{
case TYPE_DRIVER_MONITOR:
bRet=GetUserCommand(g_DeviceExtension->DriverMonitorInfo.pNotifyEvent,
g_DeviceExtension->DriverMonitorInfo.SharedMemInfo.pShareMemory,
pMonitorInfo,
sizeof(DRIVER_TRANS_INFO));
break;
default:
;
}
return bRet;

}
//获取用户层命令
BOOL GetUserCommand(__in PKEVENT pNotifyEvent,
__in PVOID pShareMemory,
__in PVOID pTransInfo,
__in ULONG pTransLen)
{
BOOL bRet;
PDRIVER_TRANS_INFO pDriverTransInfo;
memcpy(pShareMemory,pTransInfo,pTransLen);
KeSetEvent(pNotifyEvent,0,false);
KeWaitForSingleObject(
pNotifyEvent,
Executive,
KernelMode,
false,
NULL);
pDriverTransInfo=(PDRIVER_TRANS_INFO)pShareMemory;
if (pDriverTransInfo->Command==COMMAND_GO)
{
bRet=true;
}
else if (pDriverTransInfo->Command==COMMAND_STOP)
{
bRet=false;
}
return bRet;
}

这里发段R3和R0共享内存的,用的是内核创建pool在建MDL映射到用户空间的方法。
BOOL CreateSharedMemory(__out PSHARE_MEMORY_INFO pShareMemInfo,
__in ULONG MemorySize)
{
BOOL bRet=true;
PMDL pMdl;
PVOID UserVAToReturn;
PIO_STACK_LOCATION pIoStackLocation;
ULONG ulBufferLengthOut;
PVOID pSharedBuffer;
pSharedBuffer=ExAllocatePoolWithTag(NonPagedPool,MemorySize,MM_TAG_ANTI);
if (!pSharedBuffer)
{
KdPrint(("(IrpCreateSharedMemory) pSharedBuffer allocate failed"));
return false;
}
pMdl=IoAllocateMdl(pSharedBuffer,MemorySize,false,false,NULL);
if (!pMdl)
{
KdPrint(("(IrpCreateSharedMemory) IoAllocateMdl( failed"));
ExFreePool(pSharedBuffer);
return false;
}
MmBuildMdlForNonPagedPool(pMdl);
UserVAToReturn=MmMapLockedPagesSpecifyCache(pMdl,
UserMode,
MmCached,
NULL,
false,
NormalPagePriority);
if (!UserVAToReturn)
{
IoFreeMdl(pMdl);
ExFreePool(pSharedBuffer);
return false;
}
RtlZeroMemory(pSharedBuffer,MemorySize);
KdPrint(("UserVAToReturn:0x%08x",UserVAToReturn));
//输出
pShareMemInfo->pShareMemory=pSharedBuffer;
pShareMemInfo->pSharedMdl=pMdl;
pShareMemInfo->UserVA=(ULONG)UserVAToReturn;
return bRet;
}
R3的创建事件和开线程我就不发了,很简单大家可以自己尝试下。
最后附下整个架构的部分数据结构

//GoOrNot Type宏定义
#define TYPE_DRIVER_MONITOR 0x01
//GoOrNot Command宏定义
#define COMMAND_GO 0x01
#define COMMAND_STOP 0x02
//危险拦截提示语句
#define WARM_DRI_LOAD L"尝试加载驱动,一旦加载驱动进程将会获得系统最高权限,允许此操作将可能导致危险发生,驱动文件路径:"
//************数据定义***************************************************
typedef struct _SYSCALL_FILTER_INFO_TABLE
{
ULONG ulSSDTAddr;
ULONG ulSHADOWSSDTAddr;
ULONG ulSSDTNum;
ULONG ulSHADOWSSDTNum;
ULONG SavedSSDTTable[SSDT_FILTER_NUM]; //SSDT原始函数地址表
ULONG ProxySSDTTable[SHADOWSSDT_FILTER_NUM]; //SSDT代理函数地址表
ULONG SavedShadowSSDTTable[SSDT_FILTER_NUM]; //ShadowSSDT原始函数地址表
ULONG ProxyShadowSSDTTable[SHADOWSSDT_FILTER_NUM]; //ShadowSSDT代理函数地址表
ULONG SSDTSwitchTable[SSDT_FILTER_NUM]; //SSDT Hook开关表
ULONG ShadowSSDTSwitchTable[SHADOWSSDT_FILTER_NUM];//ShadowSSDT Hook开关表
}SYSCALL_FILTER_INFO_TABLE,*PSYSCALL_FILTER_INFO_TABLE;
好的宏定义也可以简化工程,这里大家可自行考虑。

这样差不多整个架构就搭建起来了,一个小型的监控系统就可以完成了。优秀的架构的确可以事半功倍,不过过滤函数的规则其实才是重中之重呀……………..。大家可以多讨论下,这个过滤规则是很需要仔细研究的。当然你要藏着咱也没办法呵…………
最后说下:
由于这个源代码是我一个大文件里面的一部分,所以整个也不好给出,其实也没必要给出来,毕竟没多少技术含量,大家都可以写得出的,这里只是就框架总结下而已。全部发了也没意思一大堆你也不想看,还不如发点核心的,然后你也可以尝试搭建下自己的更有乐趣呢!
第一次发这种贴,如果有不当之处敬请谅解。
分享到:
评论

相关推荐

    Delphi LSP Hook 过滤广告

    **Delphi LSP Hook 过滤广告技术详解** 在IT领域,开发人员常常需要处理各种网络数据,其中包括可能存在的广告信息。"Delphi LSP Hook 过滤广告"是一种技术手段,利用Delphi编程环境来实现本地系统服务提供商...

    API HOOK易语言IP端口拦截转向源码

    API Hook是一种技术,它允许程序员拦截系统调用或者应用程序接口(API)的调用,以便在调用实际功能之前或之后执行自定义代码。在易语言中,API Hook的实现通常涉及创建一个动态链接库(DLL),并在目标进程中注入这...

    1.3.8.1版(18-04-02)360加固保Hook

    《1.3.8.1版(18-04-02)360加固保Hook:深入解析Xposed框架与360加固技术》 在移动应用开发领域,安全性和隐私保护至关重要,其中360加固保作为一款广受欢迎的安卓应用加固工具,为开发者提供了强大的安全防护。...

    Hook Api,hook ReadFile,hook WriteFile,hook LoadLibrary

    通过Hook它们,开发者可以实现诸如日志记录、数据过滤、性能分析等功能。例如,当其他程序尝试读取文件时,我们的Hook代码先执行,记录下读取操作的信息,甚至改变返回值,影响实际的读取结果。 同样,LoadLibrary...

    HookPHP基于C扩展搭建内置AI编程的架构系统支持微服务.zip

    HookPHP基于C扩展搭建内置AI编程的架构系统支持微服务

    Inline Hook_inlinehook_x86_x64_64位HOOK_

    x86架构通常使用JMP或CALL指令来跳转到Hook处理程序,而x64架构则更倾向于使用RIP相对寻址,因为x64指令集更倾向于减少绝对地址的使用。Inline Hook在x64上需要考虑到更大的指令长度和寄存器使用的变化。 提供的...

    APIHook例子 hook api

    APIHook是一种技术,用于在应用程序调用特定API(应用程序编程接口)时,插入自定义代码以拦截、修改或增强原始API的功能。这个例子是关于如何Hook Windows Socket API,即Winsock,来监控或改变网络通信行为。让...

    易语言x64-hook模块源码+实列

    在给定的资源中,"易语言x64-hook模块源码+实例"是关于易语言在x64架构下进行钩子(Hook)技术实现的资料包。钩子技术是Windows编程中的一种高级技巧,它允许程序监控并响应系统中的特定事件或行为。 1. **x64架构...

    Hook MessageBox 全局Hook

    全局Hook是一种技术,它允许一个程序监控或修改其他程序的行为,而无需修改这些程序的代码。在本场景中,我们关注的是Hook MessageBox,也就是对Windows系统中的消息框函数MessageBox进行拦截。MessageBox是Windows ...

    Hook经典分析 关于QQ Hook的应用 钩子

    QQ Hook是一种技术手段,主要涉及计算机程序中的钩子(Hook)机制。钩子在编程领域中,是指一种允许开发者在特定事件发生时插入自定义处理代码的机制。它允许程序拦截并处理系统或应用程序级别的事件,例如键盘输入...

    微信Hook教程(易语言)

    ### 微信Hook教程(易语言) #### 一、Hook技术概述 Hook技术在软件开发领域扮演着重要的角色,尤其在实现特定功能扩展或者调试分析时。本教程将重点介绍如何利用易语言进行微信Hook操作。 #### 二、Hook原理简述...

    EasyHook-2.7.6270.0.zip_c# easy hook_easyhook_easyhook 2.7_eas

    EasyHook是一款强大的、开源的.NET库,用于在托管代码中实现远程函数钩子(Remote Function Hooking)。在标题和描述中提到的"EasyHook-2.7.6270.0.zip"是一个包含EasyHook库版本2.7.6270.0的压缩包,适用于C#开发者...

    易语言 微信 hook 2.6

    《易语言微信hook 2.6技术解析及应用探索》 在信息技术日新月异的今天,编程语言的创新和应用不断推动着软件开发的进步。其中,“易语言”以其独特的汉字编程理念,降低了编程的门槛,让更多的人能够参与到程序设计...

    C#EasyHook_easyhook_

    【C# EasyHook】是一个强大的库,用于在.NET Framework中实现远程函数调用(RDI,Remote Function Invocation)和钩子技术。EasyHook为开发者提供了一种高效、稳定且易于使用的解决方案,允许他们在运行时拦截和修改...

    Hook自己的程序

    通过分析和学习这个示例,开发者可以了解如何在实际项目中对文本处理函数进行Hook,以实现特定的功能,如日志记录、文本内容过滤等。 总结,Hook技术是程序员的得力工具,能够灵活地扩展和控制程序的行为。理解和...

    EasyHook远程进程注入并hook api的实现

    本篇将详细讲解如何利用EasyHook库实现远程进程API Hook。 EasyHook是一个开源的.NET库,它提供了一种在Windows平台上进行远程钩子(Hook)的技术。Hook技术允许开发者拦截系统调用或特定函数的执行,以便在调用...

    HOOK系列实例实战班【无KEY版】

    12、HOOK 载入DLL命令,实现过滤DLL。13、HOOK 卸载DLL命令,实现过滤卸载。14、HOOK 游戏API 实现加速。15、游戏功能HOOK实现鼠标自动点击。16、HOOK植物大战僵尸实现无限小车。17、HOOK游戏功能技巧讲解。18、Hook...

    Hook函数任意地址 c++

    在IT行业中,Hook技术是一种非常重要的系统编程技巧,它允许开发者拦截和修改系统或应用程序的特定功能执行流程。本实例以"C++"为语言环境,实现了Hook函数在任意地址的功能,同时还提供了获取CPU寄存器内容的能力。...

    HOOK 系统注册表 HOOK API SYSTEM REGISTRY

    HOOK 系统注册表 HOOK API SYSTEM REGISTRY 文件清单: PHookRegistry.exe HOOK管理主程序 PNtHOOK.dll HOOK API DLL 功能描述: 1. 只针对用户级别的程序API陷井式HOOK, 这里只对以下API进行HOOK: ...

    HOOK API 完美支持 x86 x64

    《全面解析:HOOK API在x86与x64架构中的应用与实现》 HOOK API是一种在软件开发中广泛使用的技术,它允许开发者拦截并控制其他应用程序或系统函数的调用,以实现诸如日志记录、性能监测、功能增强等多种目的。在...

Global site tag (gtag.js) - Google Analytics