通过挂钩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 ( idwNumberOfModules )
{
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得到的是函数名称的首字母*/
DbgPrint("IAT ENTRY=0x%x,IatAddress=0x%X,funcname=[%s]----hookfunc=[%s]\n",(ULONG *)((CHAR *)ModlueBase + pImportModuleDirectory->FirstThunk+i*4),FirstThunk[i],(PCHAR)&Imageimportbyname->Name[0],ApiName);
*originalFuncAddr = (ULONG)FirstThunk[i];
reslut = HookFunc(&FirstThunk[i],fakeFunctionAddr);
goto Exit;
}
}
}
break;
}
pImportModuleDirectory++;
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
reslut =0;
}
}
else
reslut =0;
Exit:
return result;
}
ULONG HookFunc(IN PVOID ImportFuncVA,IN ULONG fake_func)
{
PMDL ImportFuncThunkEntry_MDL;
PVOID ImportFuncMapAddress;
PVOID ImportFuncThunkEntry; //导入表函数的THUNK地址--指针地址
ULONG result;
BOOL IsMapped;
IsMapped = 0;
if (ImportFuncVA && fake_func)
{
ImportFuncThunkEntry = (PVOID)ImportFuncVA;
ImportFuncThunkEntry_MDL = IoAllocateMdl(ImportFuncThunkEntry,sizeof(ULONG),FALSE,FALSE,NULL);
if (ImportFuncThunkEntry_MDL)
{
MmProbeAndLockPages(ImportFuncThunkEntry_MDL,KernelMode,IoWriteAccess);
IsMapped =1;
if (ImportFuncThunkEntry_MDL->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA|MDL_SOURCE_IS_NONPAGED_POOL))
ImportFuncMapAddress = ImportFuncThunkEntry_MDL->MappedSystemVa;
else
ImportFuncMapAddress = MmMapLockedPagesSpecifyCache(ImportFuncThunkEntry_MDL,KernelMode,MmCached,NULL,NULL,NormalPagePriority);
if ( MmIsAddressValid(ImportFuncMapAddress) )
{
InterlockedExchangePointer(ImportFuncMapAddress,fake_func);
result = 1;
}
}
if (IsMapped)
MmUnlockPages(ImportFuncThunkEntry_MDL);
}else
result = 0;
return result;
}
NTSTATUS fake_KeUserModeCallback(IN ULONG ApiNumber,IN PVOID InputBuffer,IN ULONG InputLength,OUT ULONG OutputBuffer,IN PULONG OutputLength)
{
UNICODE_STRING uniDllPath={0};
STRING aniDLLPath={0};
CHAR outDllPath[MAX_PATH]={0};
ULONG PID;
CHAR FullPath[MAX_PATH]={0}; //被注入DLL的进程全路径
if (g_IsDLLDefendMon &&
!KeGetCurrentIrql() &&
ApiNumber == LOAD_IMAGE_API_NUM &&
InputLength >= LOAD_IMAGE_APINAME_OFFSET &&
MmIsAddressValid(InputBuffer) &&
InputBuffer
)
{
PID = (ULONG)PsGetCurrentProcessId();
uniDllPath.Length = *(WORD *)((CHAR *)InputBuffer + LOAD_IMAGE_APINAMELENGTH_OFFSET);
uniDllPath.MaximumLength = *(WORD *)((CHAR *)InputBuffer + LOAD_IMAGE_APINAMEMAXLENGTH_OFFSET);
uniDllPath.Buffer = (PWSTR)((CHAR *)InputBuffer + LOAD_IMAGE_APINAME_OFFSET); //这里得到加载的dll的符号全路径
aniDLLPath.Buffer = (PCHAR)&outDllPath;
aniDLLPath.Length = 256;
aniDLLPath.MaximumLength = 256;
RtlUnicodeStringToAnsiString(&aniDLLPath, &uniDllPath, FALSE);
GetFullPathFromPID(PID,&FullPath,256);
if (VoteModule(FullPath,outDllPath)==1)
return STATUS_UNSUCCESSFUL;
}
return g_KeUserModeCallback(ApiNumber,InputBuffer,InputLength,OutputBuffer,OutputLength);
}
[注意]看雪招聘,专注安全领域的专业人才平台!