您的位置:首页 > 其它

揭秘灰色产业链中掖着藏着的底层技术(初级篇)

2012-08-14 22:42 741 查看
    今天就来一段现在比较流行的,也算是有人藏着掖着的,能反反调试的一种手段之一,重载内核。一共两个函数,放在驱动程序里直接调用即可。废话不多说,上代码。

////////////////////////////////////////////////////////////////////////////////////////////////////
//
//      函数名称:   LoadKernel
//      函数作用:   将内核文件载入内存
//      参数:     newKernelBasePtrPtr[OUT]:   接收新内核基址的指针
//                  oldKernelBasePtrPtr[OUT]:   接收旧内核基址的指针
//      作者:     葛世超
//      时间:     2012年8月14日22:37
//
////////////////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS LoadKernel(OUT PUCHAR * newKernelBasePtrPtr, OUT PUCHAR * oldKernelBasePtrPtr)
{
ULONG rtlProcessModulesSize = 0;

//获取枚举系统模块所需内存尺寸
NTSTATUS status = ZwQuerySystemInformation(SystemModuleInformation, NULL, 0, &rtlProcessModulesSize);

//以获取的内存尺寸作为判断函数成功的依据是由于rtlProcessModulesSize为0时函数一定不能返回STATUS_SUCCESS
if (!rtlProcessModulesSize)
{
return status;
}

//为系统模块分配内存空间
PRTL_PROCESS_MODULES rtlProcessModulesPtr = (PRTL_PROCESS_MODULES)ExAllocatePoolWithTag(PagedPool, rtlProcessModulesSize, 'NIMS');

if (!rtlProcessModulesPtr)
{
return STATUS_NO_MEMORY;
}

RtlZeroMemory(rtlProcessModulesPtr, rtlProcessModulesSize);

//第二次调用该函数且rtlProcessModulesSize不为0时可返回有效内核模块信息
status = ZwQuerySystemInformation(SystemModuleInformation, rtlProcessModulesPtr, rtlProcessModulesSize, &rtlProcessModulesSize);

//因rtlProcessModulesSize足够大且rtlProcessModulesPtr有效, 则可以使用函数返回值判断函数执行结果
if (!NT_SUCCESS(status))
{
ExFreePoolWithTag(rtlProcessModulesPtr, 'NIMS');
return status;
}

UNICODE_STRING kernelFilePath;

RtlZeroMemory(&kernelFilePath, sizeof(kernelFilePath));

PUCHAR oldKernelBasePtr = NULL;

for (int i = 0; i < rtlProcessModulesPtr->NumberOfModules; ++i)
{
if (strstr(rtlProcessModulesPtr->Modules[i].FullPathName, "ntoskrnl.exe"))
{
RtlInitUnicodeString(&kernelFilePath, L"\\SystemRoot\\System32\\ntoskrnl.exe");
oldKernelBasePtr = (PUCHAR)rtlProcessModulesPtr->Modules[i].ImageBase;
break;
}

if (strstr(rtlProcessModulesPtr->Modules[i].FullPathName, "ntkrnlpa.exe"))
{
RtlInitUnicodeString(&kernelFilePath, L"\\SystemRoot\\System32\\ntkrnlpa.exe");
oldKernelBasePtr = (PUCHAR)rtlProcessModulesPtr->Modules[i].ImageBase;
break;
}

if (strstr(rtlProcessModulesPtr->Modules[i].FullPathName, "ntkrnlmp.exe"))
{
RtlInitUnicodeString(&kernelFilePath, L"\\SystemRoot\\System32\\ntkrnlmp.exe");
oldKernelBasePtr = (PUCHAR)rtlProcessModulesPtr->Modules[i].ImageBase;
break;
}

if (strstr(rtlProcessModulesPtr->Modules[i].FullPathName, "ntkrpamp.exe"))
{
RtlInitUnicodeString(&kernelFilePath, L"\\SystemRoot\\System32\\ntkrpamp.exe");
oldKernelBasePtr = (PUCHAR)rtlProcessModulesPtr->Modules[i].ImageBase;
break;
}
}

ExFreePoolWithTag(rtlProcessModulesPtr, 'NIMS');

//oldKernelBasePtr等于NULL时没有找到内核文件路径
if (!oldKernelBasePtr)
{
return STATUS_NOT_FOUND;
}

//将内核文件内容读入内存
OBJECT_ATTRIBUTES objectAttributes;

RtlZeroMemory(&objectAttributes, sizeof(objectAttributes));

InitializeObjectAttributes
(
&objectAttributes,
&kernelFilePath,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL,
NULL
);

IO_STATUS_BLOCK ioStatusBlock;

RtlZeroMemory(&ioStatusBlock, sizeof(ioStatusBlock));

HANDLE kernelFileHandle = NULL;

status = ZwOpenFile
(
&kernelFileHandle,
GENERIC_READ,
&objectAttributes,
&ioStatusBlock,
FILE_SHARE_READ,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
);

if (!NT_SUCCESS(status))
{
return status;
}

FILE_STANDARD_INFORMATION fileStandardInformation;

RtlZeroMemory(&fileStandardInformation, sizeof(fileStandardInformation));

status = ZwQueryInformationFile
(kernelFileHandle,
&ioStatusBlock,
&fileStandardInformation,
sizeof(fileStandardInformation),
FileStandardInformation
);

if (!NT_SUCCESS(status))
{
ZwClose(kernelFileHandle);

return status;
}

ULONG kernelFileSize = fileStandardInformation.EndOfFile.QuadPart;

PUCHAR kernelFileContentPtr = (PUCHAR)ExAllocatePoolWithTag(PagedPool, kernelFileSize, 'TNTC');

if (!kernelFileContentPtr)
{
ZwClose(kernelFileHandle);

return STATUS_NO_MEMORY;
}

RtlZeroMemory(kernelFileContentPtr, kernelFileSize);

status = ZwReadFile(
kernelFileHandle,
NULL,
NULL,
NULL,
&ioStatusBlock,
kernelFileContentPtr,
kernelFileSize,
NULL,
NULL
);

ZwClose(kernelFileHandle);

if (!NT_SUCCESS(status))
{
ExFreePoolWithTag(kernelFileContentPtr, 'TNTC');

return status;
}

//IMAGE_DOS_HEADER
PIMAGE_DOS_HEADER imageDosHeaderPtr = (PIMAGE_DOS_HEADER)kernelFileContentPtr;

if (imageDosHeaderPtr->e_magic != IMAGE_DOS_SIGNATURE)
{
ExFreePoolWithTag(kernelFileContentPtr, 'TNTC');

return STATUS_INVALID_IMAGE_FORMAT;
}

//IMAGE_NT_HEADER
PIMAGE_NT_HEADERS imageNtHeadersPtr = (PIMAGE_NT_HEADERS)(kernelFileContentPtr + imageDosHeaderPtr->e_lfanew);

if (imageNtHeadersPtr->Signature != IMAGE_NT_SIGNATURE)
{
ExFreePoolWithTag(kernelFileContentPtr, 'TNTC');

return STATUS_INVALID_IMAGE_FORMAT;
}

ULONG kernelMemorySize = imageNtHeadersPtr->OptionalHeader.SizeOfImage;

//为新内核分配内存空间(非分页内存)
PUCHAR newKernelBasePtr = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, kernelMemorySize, 'LNRK');

if (!newKernelBasePtr)
{
ExFreePoolWithTag(kernelFileContentPtr, 'TNTC');

return STATUS_NO_MEMORY;
}

RtlZeroMemory(newKernelBasePtr, kernelFileSize);

//将文件内容中PE头复制到内存区
RtlCopyMemory(newKernelBasePtr, kernelFileContentPtr, imageNtHeadersPtr->OptionalHeader.SizeOfHeaders);

//按顺序装载各节
PIMAGE_SECTION_HEADER imageSectionHeaderPtr = (PIMAGE_SECTION_HEADER)(kernelFileContentPtr + imageDosHeaderPtr->e_lfanew + sizeof(IMAGE_NT_HEADERS));

for (int i = 0; i < imageNtHeadersPtr->FileHeader.NumberOfSections; ++i)
{
ULONG sectionVirtualAddress = imageSectionHeaderPtr[i].VirtualAddress;
ULONG sectionFileOffset = imageSectionHeaderPtr[i].PointerToRawData;

//只映射有效区域
ULONG sectionSize = imageSectionHeaderPtr[i].SizeOfRawData <= imageSectionHeaderPtr[i].Misc.VirtualSize ? imageSectionHeaderPtr[i].SizeOfRawData : imageSectionHeaderPtr[i].Misc.VirtualSize;

if (sectionSize)
{
RtlCopyMemory(newKernelBasePtr + sectionVirtualAddress, kernelFileContentPtr + sectionFileOffset, sectionSize);
}
}

//以旧内核基址为参考基址对新内核进行基址重定位
PIMAGE_BASE_RELOCATION imageBaseRelocationPtr = (PIMAGE_BASE_RELOCATION)(newKernelBasePtr + imageNtHeadersPtr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

while (imageBaseRelocationPtr->SizeOfBlock)
{
PUSHORT relocationDataPtr = (PUSHORT)((PUCHAR)imageBaseRelocationPtr + sizeof(IMAGE_BASE_RELOCATION));

for (int i = 0; i < (imageBaseRelocationPtr->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT); ++i)
{
if (relocationDataPtr[i] >> 12 == IMAGE_REL_BASED_HIGHLOW)
{
PULONG relocationAddressPtr = (PULONG)(newKernelBasePtr + imageBaseRelocationPtr->VirtualAddress + (relocationDataPtr[i] & 0x0fff));
*relocationAddressPtr = *relocationAddressPtr - imageNtHeadersPtr->OptionalHeader.ImageBase + (ULONG)oldKernelBasePtr;
}
}

imageBaseRelocationPtr = (PIMAGE_BASE_RELOCATION)((PUCHAR)imageBaseRelocationPtr + imageBaseRelocationPtr->SizeOfBlock);
}

//修复被重定位过的系统服务分发表(SSDT), 将其指回新内核对应分发函数入口
PSYSTEM_SERVICE_DESCRIPTOR_TABLE systemServiceDescriptorTable = (PSYSTEM_SERVICE_DESCRIPTOR_TABLE)(newKernelBasePtr + (ULONG)KeServiceDescriptorTable - (ULONG)oldKernelBasePtr);

systemServiceDescriptorTable->NTOSKRNL.NumberOfService = KeServiceDescriptorTable->NTOSKRNL.NumberOfService;

if (KeServiceDescriptorTable->NTOSKRNL.CounterTableBase)
{
systemServiceDescriptorTable->NTOSKRNL.CounterTableBase = (PULONG)(newKernelBasePtr + (ULONG)KeServiceDescriptorTable->NTOSKRNL.CounterTableBase - (ULONG)oldKernelBasePtr);
}

if (KeServiceDescriptorTable->NTOSKRNL.ParameterTableBase)
{
systemServiceDescriptorTable->NTOSKRNL.ParameterTableBase = (PUCHAR)(newKernelBasePtr + (ULONG)KeServiceDescriptorTable->NTOSKRNL.ParameterTableBase - (ULONG)oldKernelBasePtr);
}

if (KeServiceDescriptorTable->NTOSKRNL.ServiceTableBase)
{
systemServiceDescriptorTable->NTOSKRNL.ServiceTableBase = (PULONG)(newKernelBasePtr + (ULONG)KeServiceDescriptorTable->NTOSKRNL.ServiceTableBase - (ULONG)oldKernelBasePtr);

for (int i = 0; i < systemServiceDescriptorTable->NTOSKRNL.NumberOfService; ++i)
{
systemServiceDescriptorTable->NTOSKRNL.ServiceTableBase[i] += (ULONG)newKernelBasePtr - (ULONG)oldKernelBasePtr;
}
}

ExFreePoolWithTag(kernelFileContentPtr, 'TNTC');

*newKernelBasePtrPtr = newKernelBasePtr;
*oldKernelBasePtrPtr = oldKernelBasePtr;

return STATUS_SUCCESS;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//
//      函数名称:   FreeKernel
//      函数作用:   释放加载的内核
//      参数:     kernelBasePtr[IN]:      新内核基址
//
////////////////////////////////////////////////////////////////////////////////////////////////////
VOID FreeKernel(IN PUCHAR kernelBasePtr)
{
ExFreePoolWithTag(kernelBasePtr, 'LNRK');
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: