重载重点,其实就是自己实现一个山寨版的Windows PELoader ,重载其实就是将一个模块自己重新加载一份到别的内存,运行它。
所谓内核重载,则是将内核文件即:ntkrnlpa.exe 自己加载一份到内存,并运行它,这样的好处可以避免一切HOOK,如SSDT ,InLineHook 等等,原理就是HOOK继续
HOOK主原来内核,但是实际上Windows走的是我们自己的内核。
废话不多说,开始干起来,首先查找内核模块,遍历内核模块的方式很多种,这里我使用的是通过LDR链表:
// 查找内核模块
PLDR_DATA_TABLE_ENTRY SearchDriver(PDRIVER_OBJECT pDriverObject, wchar_t *strDriverName)
{
LDR_DATA_TABLE_ENTRY *pDataTableEntry, *pTempDataTableEntry;
PLIST_ENTRY pList;
UNICODE_STRING usModuleName;
RtlInitUnicodeString(&usModuleName, strDriverName);
pDataTableEntry = (LDR_DATA_TABLE_ENTRY*)pDriverObject->DriverSection;
if (!pDataTableEntry)
{
return 0;
}
pList = pDataTableEntry->InLoadOrderLinks.Flink;
while (pList != &pDataTableEntry->InLoadOrderLinks)
{
pTempDataTableEntry = (LDR_DATA_TABLE_ENTRY *)pList;
if (0 == RtlCompareUnicodeString(&pTempDataTableEntry->BaseDllName, &usModuleName, FALSE))
{
return pTempDataTableEntry;
}
pList = pList->Flink;
}
return 0;
}
找到内核模块,就开始读文件到内存~
NTSTATUS ReadFileToMemory(LPWSTR lpFileName, PVOID* lpVirtualPoint, PVOID pOriImage)
{
NTSTATUS Status;
HANDLE hFile;
OBJECT_ATTRIBUTES ObjAttr;
UNICODE_STRING usFileName;
IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER FileOffset;
PVOID pVirtualAddress;
ULONG uIndex;
ULONG uSizeOfSection;
ULONG uSectionAddress;
IMAGE_DOS_HEADER ImageDosHeader;
IMAGE_NT_HEADERS ImageNtHeader;
PIMAGE_SECTION_HEADER pImageSectionHeader;
RtlInitUnicodeString(&usFileName, lpFileName);
InitializeObjectAttributes(
&ObjAttr,
&usFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwCreateFile(
&hFile,
FILE_ALL_ACCESS,
&ObjAttr,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE,
NULL,
0);
if (!NT_SUCCESS(Status))
{
DbgPrint("ZwCreateFile faild\n");
return Status;
}
FileOffset.QuadPart = 0;
Status = ZwReadFile(
hFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
&ImageDosHeader,
sizeof(IMAGE_DOS_HEADER),
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DbgPrint("ZwReadFile ImageDosHeader faild\n");
ZwClose(hFile);
return Status;
}
FileOffset.QuadPart = ImageDosHeader.e_lfanew;
Status = ZwReadFile(
hFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
&ImageNtHeader,
sizeof(IMAGE_NT_HEADERS),
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DbgPrint("ZwReadFile ImageNtHeader faild\n");
ZwClose(hFile);
return Status;
}
// 读节段
pImageSectionHeader = (PIMAGE_SECTION_HEADER)ExAllocatePool(NonPagedPool,
sizeof(IMAGE_SECTION_HEADER)*ImageNtHeader.FileHeader.NumberOfSections);
if (NULL == pImageSectionHeader)
{
DbgPrint("ExAllocatePool pImageSectionHeader faild\n");
ZwClose(hFile);
return STATUS_UNSUCCESSFUL;
}
FileOffset.QuadPart += sizeof(IMAGE_NT_HEADERS);
Status = ZwReadFile(
hFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
pImageSectionHeader,
sizeof(IMAGE_SECTION_HEADER)*ImageNtHeader.FileHeader.NumberOfSections,
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DbgPrint("ZwReadFile pImageSectionHeader faild\n");
ExFreePool(pImageSectionHeader);
ZwClose(hFile);
return Status;
}
// 复制内存
pVirtualAddress = ExAllocatePool(NonPagedPool, ImageNtHeader.OptionalHeader.SizeOfImage);
if (NULL == pVirtualAddress)
{
DbgPrint("ExAllocatePool pVirtualAddress faild\n");
ExFreePool(pImageSectionHeader);
ZwClose(hFile);
return STATUS_UNSUCCESSFUL;
}
RtlZeroMemory(pVirtualAddress, ImageNtHeader.OptionalHeader.SizeOfImage);
RtlCopyMemory(pVirtualAddress, &ImageDosHeader, sizeof(IMAGE_DOS_HEADER));
RtlCopyMemory(
(PVOID)((ULONG)pVirtualAddress + ImageDosHeader.e_lfanew),
&ImageNtHeader,
sizeof(IMAGE_NT_HEADERS));
RtlCopyMemory(
(PVOID)((ULONG)pVirtualAddress + ImageDosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS)),
pImageSectionHeader,
sizeof(IMAGE_SECTION_HEADER)*ImageNtHeader.FileHeader.NumberOfSections);
for (uIndex = 0; uIndex < ImageNtHeader.FileHeader.NumberOfSections; uIndex++)
{
uSectionAddress = pImageSectionHeader[uIndex].VirtualAddress;
if (pImageSectionHeader[uIndex].Misc.VirtualSize > pImageSectionHeader[uIndex].SizeOfRawData)
uSizeOfSection = pImageSectionHeader[uIndex].Misc.VirtualSize;
else
uSizeOfSection = pImageSectionHeader[uIndex].SizeOfRawData;
FileOffset.QuadPart = pImageSectionHeader[uIndex].PointerToRawData;
Status = ZwReadFile(
hFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
(PVOID)((ULONG)pVirtualAddress + uSectionAddress),
uSizeOfSection,
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DbgPrint("ZwReadFile ImageSectionHeader faild\n");
ExFreePool(pImageSectionHeader);
ExFreePool(pVirtualAddress);
ZwClose(hFile);
return Status;
}
}
FixRelocTable(pVirtualAddress, pOriImage);
DbgPrint("OK\n");
ExFreePool(pImageSectionHeader);
*lpVirtualPoint = pVirtualAddress;
ZwClose(hFile);
return Status;
}
接下来这步也是最关键一步,就是修复重定位表:
void FixRelocTable(PVOID pNewImage, PVOID pOriImage)
{
PIMAGE_DOS_HEADER pImageDosHeader;
PIMAGE_NT_HEADERS pImageNtHeadaers;
IMAGE_DATA_DIRECTORY ImageDataDirectory;
PIMAGE_BASE_RELOCATION pImageBaseRelocation;
ULONG uRelocTableSize;
ULONG uCount;
ULONG uIndex;
USHORT *pwOffsetAddress;
USHORT uTypeValue;
ULONG uRelocOffset;
ULONG uRelocAddress;
pImageDosHeader = (PIMAGE_DOS_HEADER)pNewImage;
pImageNtHeadaers = (PIMAGE_NT_HEADERS)(pImageDosHeader->e_lfanew + (ULONG)pNewImage);
uRelocOffset = (ULONG)pOriImage - pImageNtHeadaers->OptionalHeader.ImageBase;
ImageDataDirectory = pImageNtHeadaers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
pImageBaseRelocation = (PIMAGE_BASE_RELOCATION)(ImageDataDirectory.VirtualAddress + (ULONG)pNewImage);
uRelocTableSize = ImageDataDirectory.Size;
while (uRelocTableSize)
{
uCount = (pImageBaseRelocation->SizeOfBlock - sizeof(ULONG)* 2) / sizeof(USHORT);
pwOffsetAddress = pImageBaseRelocation->TypeOffset;
for (uIndex = 0; uIndex < uCount; uIndex++)
{
uTypeValue = pwOffsetAddress[uIndex];
if ((uTypeValue >> 12) == IMAGE_REL_BASED_HIGHLOW)
{
uRelocAddress = (uTypeValue & 0xfff) + pImageBaseRelocation->VirtualAddress + (ULONG)pNewImage;
if (!MmIsAddressValid((PVOID)uRelocAddress))
{
continue;
}
*(PULONG)uRelocAddress += uRelocOffset;
}
}
uRelocTableSize -= pImageBaseRelocation->SizeOfBlock;
pImageBaseRelocation = (PIMAGE_BASE_RELOCATION)((ULONG)pImageBaseRelocation + pImageBaseRelocation->SizeOfBlock);
}
}
通过上面步骤,我们成功的将内核文件完全复制了一遍。
之后就是如何让相关黑科技走我们的内核了,明天再继续!