挂钩KeUsermodeCallback函数来实现自己的“财产保镖“
作 者: liukeblue通过挂钩KeUserModeCallback这个未公开的函数可以实现对Ke_LoadLibrary、WH_KEYBOARD_LL等进行拦截,这个函数也可以用来在Ring0下调用Ring3代码,如果需要更进一步了解,可以去黑月教主的百度blog上去看看。下面我们来实现拦截dll注入的功能,解决两个问题:
一、 如何挂钩KeUserModeCallback函数,有两种方式IAT HOOK(QQ电脑管家)、inline HOOK(360保险箱)。
二、 如何拦截DLL注入,这个功能在KeUserModeCallback挂钩函数里实现。
实现的代码主要来源于对QQ电脑管家驱动文件TCSafeBox.sys的逆向分析,所以我尽量试着去还原TCSafeBox.sys的代码,核心代码如下:
ULONG StartHook(IN PVOID fake_funcaddrss,OUT PULONG Original_funcaddrss)
{
ULONG win32k_base;
ULONG result;
if (fake_funcaddrss && Original_funcaddrss)
{
win32k_base = GetModuleBase("win32k.sys");
if ( win32k_base>0 )
result = IATHook((PVOID)win32k_base,"ntoskrnl.exe", "KeUserModeCallback",fake_funcaddrss,Original_funcaddrss);
}
else
result = 0;
return result;
}
ULONG GetModuleBase(IN PCHAR ModuleName)
{
ULONG result;
ULONG dwNeedSize=0;
NTSTATUS status;
PMODULES pModules;
int i;
char imagename[255]={0};
ZwQuerySystemInformation(SystemModuleInformation,NULL,0,&dwNeedSize);
pModules = ExAllocatePoolWithTag(NonPagedPool,dwNeedSize,0);
if (pModules)
{
memset(pModules,0,dwNeedSize);
status = ZwQuerySystemInformation(SystemModuleInformation,pModules,dwNeedSize,NULL);
if (NT_SUCCESS(status))
{
i = 0;
while ( i<pModules->dwNumberOfModules )
{
strcpy(imagename,pModules->smi[i].ImageName + pModules->smi[i].ModuleNameOffset);
if (!strncmp(imagename,ModuleName,strlen(ModuleName)))
{
result = (ULONG)pModules->smi[i].Base;
break;
}
i++;
}
}
ExFreePoolWithTag(pModules,0);
}
return result;
}
ULONG IATHook(IN PVOID ModlueBase,IN PCHAR ImportName,IN PCHAR ApiName,IN ULONG fakeFunctionAddr,OUT PULONG originalFuncAddr)
{
ULONG reslut;
ULONG size;
PIMAGE_IMPORT_DESCRIPTOR pImportModuleDirectory;
DWORD dwRVAModuleName;
PCHAR ModuleName;
CHAR RvAModuleNameIsZory;
ULONG *OriginalFirstThunk;
ULONG *FirstThunk;
int i;
PIMAGE_IMPORT_BY_NAME Imageimportbyname;
ULONG result;
result = 0;
if (ModlueBase && ImportName && ApiName && fakeFunctionAddr && originalFuncAddr && !KeGetCurrentIrql())
{
__try
{
size = 0;
pImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(ModlueBase,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&size);
if (pImportModuleDirectory)
{
while (pImportModuleDirectory && pImportModuleDirectory->Name)
{
dwRVAModuleName = pImportModuleDirectory->Name; //模块的dll名称
RvAModuleNameIsZory = ((CHAR *)ModlueBase + dwRVAModuleName) == 0;
ModuleName = (CHAR *)ModlueBase + dwRVAModuleName;
//先找到模块,再在模块里查找函数
if (!RvAModuleNameIsZory && !_strnicmp(ModuleName,ImportName,sizeof(ImportName)))
{
//得到输入表结构里指向INT和IAT的VA
OriginalFirstThunk = (ULONG *)((CHAR *)ModlueBase + pImportModuleDirectory->OriginalFirstThunk);
FirstThunk = (ULONG *)((CHAR *)ModlueBase + pImportModuleDirectory->FirstThunk);
for (i=0;FirstThunk[i];i++)
{
Imageimportbyname = OriginalFirstThunk[i];
if ( Imageimportbyname < (ULONG)ModlueBase )
Imageimportbyname += (ULONG)ModlueBase;
if (Imageimportbyname)
{
//以函数名称方式输入
if ( !_strnicmp((PCHAR)&Imageimportbyname->Name[0],ApiName,strlen(ApiName))
&& MmIsAddressValid(FirstThunk[i]))
{
/* DbgPrint("i=%d,funcname=[%s]----hookfunc=[%s]\n",i,(PCHAR)&Imageimportbyname->Name[0],ApiName);
这里请注意Imageimportbyname->Name得到的是函数名称的首字母*/
&nb
补充:综合编程 , 安全编程 ,