一丶简介
主要是讲解.内核中如何拦截模块加载的. 需要熟悉.内核回调的设置
PE知识. ShellCode
二丶原理
1.原理
原理是通过回调函数. 回调函数中有 ImageBase. 使用PE解析ImageBase 得到OEP. OEP位置写入 ret等ShellCode
如何判断 是加载DLL 还是加载Sys. 可以看回调的第二个参数.(ProcessId) 如果ProcessId == 0. 则是加载Sys
PS: 在内核中解析PE需要用到 ntImage.h头文件来进行解析.
2.代码实现
#include <ntimage.h>
#include <ntddk.h>
#include <wdm.h>
ULONG_PTR g_LoadPtr = 0;
void WPONx64(KIRQL irql)
{
UINT64 cr0 = __readcr0();
cr0 |= 0x10000;
_enable();
__writecr0(cr0);
KeLowerIrql(irql);
}
KIRQL WPOFFx64()
{
KIRQL irql = KeRaiseIrqlToDpcLevel();
UINT64 cr0 = __readcr0();
cr0 &= 0xfffffffffffeffff;
__writecr0(cr0);
_disable();
return irql;
}
BOOLEAN Fuck(PVOID pOep)
{
KIRQL kirql;
if (NULL == pOep)
return FALSE;
//写入字节.
UCHAR FuckCode[] = { "xB8x22x00x00xC0xC3" };
kirql = WPOFFx64();
KdBreakPoint();
memcpy(pOep, FuckCode, sizeof(FuckCode) / sizeof(FuckCode[0])); //开头写入拒绝访问错误码让其无法加载即可.
WPONx64(kirql);
return TRUE;
}
//根据ImageBase来获取加载模块的入口点
PVOID GetImageOep(PVOID ImageBase)
{
PVOID pAddressOfEntryPoint = NULL;
PIMAGE_DOS_HEADER pDosHead = NULL;
PIMAGE_NT_HEADERS pNtHead = NULL;
PIMAGE_FILE_HEADER pFileHead = NULL;
PIMAGE_OPTIONAL_HEADER pOptHead = NULL;
//开始解析
if (ImageBase == NULL)
return NULL;
pDosHead = (PIMAGE_DOS_HEADER)ImageBase;
pNtHead = (PIMAGE_NT_HEADERS)(pDosHead->e_lfanew + (char *)ImageBase);
pFileHead = (PIMAGE_FILE_HEADER)&pNtHead->FileHeader;
pOptHead = (PIMAGE_OPTIONAL_HEADER)&pNtHead->OptionalHeader;
//判断是否是PE头
if (pDosHead->e_magic != 0x5A4D && pNtHead->Signature != 0x5045)
return NULL;
pAddressOfEntryPoint = pOptHead->AddressOfEntryPoint + (char *)ImageBase;
return pAddressOfEntryPoint;
}
char * MyWideUnicodeStringToMutilString(PUNICODE_STRING uString)
{
ANSI_STRING asStr;
char *Buffer = NULL; ;
RtlUnicodeStringToAnsiString(&asStr, uString, TRUE);
Buffer = ExAllocatePoolWithTag(NonPagedPool, uString->MaximumLength * sizeof(wchar_t), 0);
if (Buffer == NULL)
return NULL;
RtlCopyMemory(Buffer, asStr.Buffer, asStr.Length);
return Buffer;
}
VOID pSfFilterModule(
_In_opt_ PUNICODE_STRING FullImageName,
_In_ HANDLE ProcessId, // pid into which image is being mapped
_In_ PIMAGE_INFO ImageInfo
)
{
/*
模块拦截思路:
1.通过 PIMAGE_INFO->ImageBase 得到模块的ImageBase
2.解析PE头.
3.可选头的OEP + ImageBase = 程序运行位置
4.在程序开头写入 ret.
5.通过参数一,判断是不是我们想要拦截的模块.然后进行1 2 3 4步
6.如何判断加载驱动模块还是DLL 根据参数2.ProcessId高低位判断即可. == 0加载驱动模块.否则加载DLL
*/
PVOID pDriverOep = NULL;
char *ComPareString = NULL;
if (MmIsAddressValid(FullImageName))
{
if (ProcessId == 0)
{
//代表拦截驱动模块
//判断名字是否是你想要拦截的.
KdBreakPoint();
ComPareString = MyWideUnicodeStringToMutilString(FullImageName);
if (ComPareString == NULL)
return;
if (strstr(ComPareString,"1.sys"))
{
KdBreakPoint();
KdPrint(("你要拦截的驱动模块名字为: %wZ
", FullImageName));
pDriverOep = GetImageOep(ImageInfo->ImageBase);
//判断拦截的名字是否是你想要拦截的
if (pDriverOep != NULL)
{
Fuck(pDriverOep);
}
}
}
//输出调试
}
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegPath)
{
ULONG iCount = 0;
NTSTATUS ntStatus;
pDriverObj->DriverUnload = DriverUnLoad;
ntStatus = InitDeviceAnSybolicLinkName(pDriverObj);
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
ntStatus = InitDisPatchFunction(pDriverObj);
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
PsSetLoadImageNotifyRoutine(pSfFilterModule);
return STATUS_SUCCESS;
}
3.效果
win7 64 sp1 下测试.