您的位置:首页 > 其它

检测内核已加载模块的所有导出函数是否被inlinehook

2012-09-26 17:26 816 查看
转自看雪:http://bbs.pediy.com/showthread.php?t=110216

好像此论坛还没有谁发过吧,在其他论坛见过,但是有下载限制的。无奈,只好自己写,发出来供像偶这样起步较晚的朋友们参考参考,高手就略过吧,哈哈

主要功能:检测内核已加载模块的所有导出函数是否被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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息