好像此论坛还没有谁发过吧,在其他论坛见过,但是有下载限制的。无奈,只好自己写,发出来供像偶这样起步较晚的朋友们参考参考,高手就略过吧,哈哈
主要功能:检测内核已加载模块的所有导出函数是否被inlinehook。
实现方法:将内存中的模块与原始磁盘文件来做比对,若不同,则此函数被inlinehook。所以各种狡诈的inlinehook伎俩(mov eax ,xxxx add eax,xxxx,call eax)是逃不过检测的,除非它修改原始磁盘文件。不过可惜,在比较之前是可以进行md5验证的。若原始磁盘文件被修改,显然是昭然若揭了。
相对其他较复杂检测技术,这个法子最简单而且同样有效。
主体函数实现如下:
代码:
void HookCheckAllModuleExportRoutine (PVOID sysInfo) { int i,j,k,len,length; PSYSMODULELIST List = NULL; char image[256], Name[256],sysDir[256]; ANSI_STRING FullPath; UNICODE_STRING uFullPath; ANSI_STRING Temp1,Temp2,Temp3,Temp4,Temp5; HANDLE hFile = NULL, hSection = NULL; PVOID BaseAddress = NULL; IO_STATUS_BLOCK IoStatusBlock; CLIENT_ID ClientID; PVOID SysInfo; PIMAGE_DOS_HEADER DosHead = NULL; PIMAGE_NT_HEADERS NtHeads = NULL; PIMAGE_SECTION_HEADER Section = NULL; PIMAGE_EXPORT_DIRECTORY ExportDir = NULL; PIMAGE_BASE_RELOCATION RelocDir = NULL; ULONG kBase = 0, mBase = 0, kNameBase = 0, kOrdinalBase = 0, kFunctionBase = 0; ULONG ByteEqual, Address = 0, index, NameNumbers, FixAddr = 0, FixAddrBase = 0,RelocSize; ULONG DataSecVA[24], DataSecSize[24], DataSec; USHORT Temp = 0; PUCHAR SystemFunName; PKPROCESS Eprocess; KAPC_STATE ApcState; HANDLE ProcessHandle; UNICODE_STRING ProcessName; PSYSTEM_PROCESSES pSysinfo; PKUSER_SHARED_DATA kShareData = USER_SHARED_DATA; size_t size = 0; NTSTATUS status; OBJECT_ATTRIBUTES oa, ob = {sizeof (ob), NULL, NULL,NULL, NULL}; RtlInitAnsiString (&Temp2, "sys"); RtlInitAnsiString (&Temp3, "dll"); RtlInitAnsiString (&Temp4, "exe"); RtlInitAnsiString (&Temp5, "win32k.sys"); RtlInitUnicodeString (&ProcessName, L"winlogon.exe"); w2ascll (Name, kShareData->NtSystemRoot); strcpy (sysDir, "\\??\\"); strcat (sysDir, Name); List = (PSYSMODULELIST)sysInfo; for (j = 0; j < List->ulCount; j++) { if (StringCompare ("\\??\\", List->smi[j].ImageName, 4)) { DbgPrint ("Skip %s\n", List->smi[j].ImageName); continue; } mBase = NULL; hFile = NULL; hSection = NULL; BaseAddress = NULL; memset (Name, 0, sizeof (Name)); memset (image,0, sizeof (image)); strcpy (Name, sysDir); strcpy(image, List->smi[j].ImageName + List->smi[j].ModuleNameOffset); len = strlen (image); RtlInitAnsiString (&Temp1, image + len - 3); if (!RtlCompareString (&Temp1, &Temp2, TRUE)) { if (strstr (image, "watchdog")) { strcat (Name, "\\System32\\"); }else { strcat (Name, "\\System32\\Drivers\\"); } strcat (Name, image); } else if (!RtlCompareString (&Temp1, &Temp3, TRUE) || !RtlCompareString (&Temp1, &Temp4, TRUE)) { strcat (Name, "\\System32\\"); strcat (Name, image); } else { continue; } RtlInitAnsiString (&Temp1, image); if (!RtlCompareString (&Temp5, &Temp1, TRUE)) { //win32.sys模块的空间必须挂靠进程才能读取 status = ZwQuerySystemInformation(5,NULL,0,&length); if (status == STATUS_INFO_LENGTH_MISMATCH) { SysInfo = ExAllocatePool(NonPagedPool,length); if (NULL == SysInfo) { goto Error; } } pSysinfo = (PSYSTEM_PROCESSES)SysInfo; status = ZwQuerySystemInformation(SystemProcessesAndThreadsInformation, pSysinfo, length, &length); if(!NT_SUCCESS(status)) { goto Error; } //找到winlogon.exe进程,挂靠空间 do { if (!RtlCompareString (&(pSysinfo->ProcessName), &ProcessName, TRUE)) { ClientID = pSysinfo->Threads[0].ClientId; ZwOpenProcess (&ProcessHandle, PROCESS_ALL_ACCESS, &ob, &ClientID); ObReferenceObjectByHandle (ProcessHandle, PROCESS_ALL_ACCESS, *PsProcessType, KernelMode, &Eprocess, NULL); KeStackAttachProcess (Eprocess, &ApcState); break; } if (pSysinfo->NextEntryDelta == 0) break; pSysinfo = (ULONG)pSysinfo + pSysinfo->NextEntryDelta; }while (1); ExFreePool(SysInfo); memset (Name, 0, sizeof(Name)); strcpy (Name, "\\Device\\HarddiskVolume1\\Windows\\System32\\"); strcat (Name, image); } RtlInitAnsiString (&FullPath, Name); RtlAnsiStringToUnicodeString (&uFullPath, &FullPath, TRUE); //获得模块在内核中的相关参数 kBase = List->smi[j].Base; if (!MmIsAddressValid (kBase)) { DbgPrint ("%s 'base is not valid!\n", image); goto Error; } DosHead = (PIMAGE_DOS_HEADER)kBase; NtHeads = (PIMAGE_NT_HEADERS)((ULONG)DosHead + DosHead->e_lfanew); Section = (PIMAGE_SECTION_HEADER) ((ULONG)NtHeads + sizeof(IMAGE_NT_HEADERS)); if (NULL == NtHeads->OptionalHeader.DataDirectory[0].VirtualAddress) { DbgPrint ("%s doesnt has valid export table!\n", image); continue; } DataSec = 0; for (i = 0; i < NtHeads->FileHeader.NumberOfSections; i++) { if (strstr (Section->Name, "text") ||strstr (Section->Name, "PAGE")||strstr (Section->Name, "INIT")) { DataSecVA[i] = Section->Misc.VirtualSize; DataSecSize[i] = Section->VirtualAddress; DataSec++; } Section ++; } if (i == NtHeads->FileHeader.NumberOfSections && DataSec == 0) { DbgPrint ("%wZ doesnt find the text section!\n", &FullPath); } ExportDir = (PIMAGE_EXPORT_DIRECTORY)((ULONG)kBase + NtHeads->OptionalHeader.DataDirectory[0].VirtualAddress); NameNumbers = ExportDir->NumberOfNames; kNameBase = kBase + ExportDir->AddressOfNames; kOrdinalBase = kBase + ExportDir->AddressOfNameOrdinals; kFunctionBase = kBase + ExportDir->AddressOfFunctions; //获得模块加载后的相关参数 InitializeObjectAttributes ( &oa, &uFullPath, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = ZwOpenFile( &hFile, FILE_READ_ACCESS, &oa, &IoStatusBlock, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT ); if (!NT_SUCCESS(status)) { KdPrint (("OpenFile %wZ error\n", &uFullPath)); goto Error; } oa.ObjectName = NULL; status = ZwCreateSection( &hSection, SECTION_MAP_EXECUTE, &oa, 0, PAGE_EXECUTE, SEC_IMAGE, hFile ); if (!NT_SUCCESS(status)) { KdPrint (("CreateSection for %wZ error", &uFullPath)); goto Error; } size = 0; status = ZwMapViewOfSection( hSection, NtCurrentProcess(), &BaseAddress, 0, 1000, 0, &size, (SECTION_INHERIT)1, MEM_TOP_DOWN, PAGE_READWRITE ); if (!NT_SUCCESS(status)) { KdPrint (("MapViewSection for %wZ error", &uFullPath)); goto Error; } mBase = ExAllocatePool (NonPagedPool, size); if (NULL == mBase) { goto Error; } if (BaseAddress != NULL) { RtlCopyMemory (mBase, BaseAddress, size); } DosHead = (PIMAGE_DOS_HEADER)mBase; NtHeads = (PIMAGE_NT_HEADERS)((ULONG)DosHead + DosHead->e_lfanew); RelocDir = (PIMAGE_BASE_RELOCATION)((ULONG)mBase + NtHeads->OptionalHeader.DataDirectory[5].VirtualAddress); if (RelocDir != NULL) { while (RelocDir->VirtualAddress != 0 || RelocDir->SizeOfBlock != 0) { FixAddrBase = RelocDir->VirtualAddress + (ULONG)mBase; RelocSize = (RelocDir->SizeOfBlock - 8)/2; for ( i = 0; i < RelocSize; i++) { Temp = *(PUSHORT)((ULONG)RelocDir + sizeof (IMAGE_BASE_RELOCATION) + i * 2); if ( (Temp & 0xF000) == 0x3000) { Temp &= 0x0FFF; FixAddr = FixAddrBase + (ULONG)Temp; *(PULONG)FixAddr = *(PULONG)FixAddr + (ULONG)kBase - (ULONG)NtHeads->OptionalHeader.ImageBase; } } RelocDir = (ULONG)RelocDir + RelocDir->SizeOfBlock; } } /* if (j == 0) { KernelCheck (kBase, mBase, sysInfo); } */ for (i = 0; i < NameNumbers; i++) { SystemFunName = (PUCHAR)(*(PULONG)(kNameBase + i * 4) + (ULONG)kBase); index = *((PUSHORT)(kOrdinalBase + i * 2)); Address = *(PULONG)(kFunctionBase + index * 4); for (k = 0; k < DataSec; k++) { if ( (Address >= DataSecVA[k]) && (Address <= DataSecVA[k] + DataSecSize[k])) { length = GetFunctionLength(kBase + Address); if (length) { ByteEqual = RtlCompareMemory (kBase + Address, mBase + Address, length); if (ByteEqual != length) { KdPrint (("%s:%s:%x has been inline-hooked!\n", image, SystemFunName, kBase + Address)); } } break; } } } Error: RtlFreeUnicodeString (&uFullPath); if (!RtlCompareString (&Temp5, &Temp1, TRUE)) { KeUnstackDetachProcess (&ApcState); } if (mBase != NULL) { ExFreePool (mBase); mBase = NULL; } if (hFile != NULL) { ZwClose(hFile); hFile = NULL; } if (hSection != NULL) { ZwClose(hSection); hSection = NULL; } if (BaseAddress != NULL) { ZwUnmapViewOfSection(NtCurrentProcess(),BaseAddress); BaseAddress = NULL; } } return; } ULONG GetFunctionLength(ULONG FAddress) { ULONG i = 0, Flag = 0; PUCHAR Temp = NULL; Temp = FAddress; while (!Flag && MmIsAddressValid(Temp) && MmIsAddressValid (Temp + 1) && MmIsAddressValid(Temp + 2) && MmIsAddressValid (Temp + 3)&& MmIsAddressValid (Temp + 4)) { switch (*Temp) { case 0xc3: case 0xcf: case 0xcb: if ( (*(Temp+1) == 0xcc) || (*(Temp+1) == 0x8b && *(Temp+1) == 0xFF)) { Flag = 1; } break; case 0xc2: case 0xca: if ( (*(Temp+3) == 0xcc) || (*(Temp+3) == 0x8b && *(Temp+4) == 0xFF)) { Flag = 1; } break; default: break; } if (!Flag) { if (*((PULONG)Temp) == 0 && *(Temp + 4) == 0) return 0; } Temp ++; i++; } return i; }