流沙团
[驱动开发] windows内核重载(xp3) 完整代码
2018-12-5 流沙团


1 了解PE结构



2 懂HOOK KiFastCallEntry



3 理解SSDT表 (需要修复SSDT表)







其实操作不算太复杂, 需要有一定的基础







完整测试的实例代码







#include <ntddk.h>
#include "ntimage.h"
#define __Max(a,b) a>b?a:b

#pragma pack(1)
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase; //仅适用于checked build版本
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()

__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;

typedef struct _LDR_DATA_TABLE_ENTRY{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union
{
LIST_ENTRY HashLinks;
struct
{
PVOID SectionPointer;
ULONG CheckSum;
};
};
union
{
ULONG TimeDateStamp;
PVOID LoadedImports;
};
PVOID EntryPointActivationContext;
PVOID PatchInformation;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;



typedef NTSTATUS
(*NTCREATEFILE) (
__out PHANDLE FileHandle,
__in ACCESS_MASK DesiredAccess,
__in POBJECT_ATTRIBUTES ObjectAttributes,
__out PIO_STATUS_BLOCK IoStatusBlock,
__in_opt PLARGE_INTEGER AllocationSize,
__in ULONG FileAttributes,
__in ULONG ShareAccess,
__in ULONG CreateDisposition,
__in ULONG CreateOptions,
__in_bcount_opt(EaLength) PVOID EaBuffer,
__in ULONG EaLength
);


//全局变量的定义
PVOID g_lpVirtualPointer = 0;
ULONG g_ntcreatefile;
ULONG g_fastcall_hookpointer;
ULONG g_goto_origfunc;
ULONG g_NewKernelInc;

ServiceDescriptorTableEntry_t *g_pNewSeviceTable;

void PageProtectOn()
{
__asm{//恢复内存保护
mov eax, cr0
or eax, 10000h
mov cr0, eax
sti
}
}

void PageProtectOff()
{
__asm{//去掉内存保护
cli
mov eax, cr0
and eax, not 10000h
mov cr0, eax
}
}

ULONG SearchHookPointer(ULONG StartAddress)
{
ULONG u_index;

UCHAR *p = (UCHAR*)StartAddress;

for (u_index = 0; u_index < 200; u_index++)
{
if (*p == 0x2B &&
*(p + 1) == 0xE1 &&
*(p + 2) == 0xC1 &&
*(p + 3) == 0xE9 &&
*(p + 4) == 0x02)
{
return (ULONG)p;
}

p--;
}

return 0;
}


ULONG FilterKiFastCallEntry(ULONG ServiceTableBase, ULONG FuncIndex, ULONG OrigFuncAddress)
{
if (ServiceTableBase == (ULONG)KeServiceDescriptorTable.ServiceTableBase)
{
if (strstr((char*)PsGetCurrentProcess() + 0x174, "Ollydbg") != 0)
{
//用新的NtCreateFile来处理
return g_pNewSeviceTable->ServiceTableBase[FuncIndex];

//针对inlineHook
//return (OrigFuncAddress+g_NewKernelInc);
}
}

return OrigFuncAddress;
}

__declspec(naked)
void NewKiFastCallEntry()
{
__asm{
pushad
pushfd

push edx
push eax
push edi
call FilterKiFastCallEntry

mov [esp + 0x18], eax

popfd
popad

sub esp, ecx
shr ecx, 2
jmp g_goto_origfunc
}
}

void UnHookKiFastCallEntry()
{
UCHAR str_origfuncode[5] = { 0x2B, 0xE1, 0xC1, 0xE9, 0x02 };

if (g_fastcall_hookpointer == 0)
{
return;
}

PageProtectOff();
RtlCopyMemory((PVOID)g_fastcall_hookpointer, str_origfuncode, 5);
PageProtectOn();
}

void HookKiFastCallEntry(ULONG HookPointer)
{
ULONG u_temp;
UCHAR str_jmp_code[5];

str_jmp_code[0] = 0xE9;

u_temp = (ULONG)NewKiFastCallEntry - HookPointer - 5;
*(ULONG*)&str_jmp_code[1] = u_temp;

PageProtectOff();

RtlCopyMemory((PVOID)HookPointer, str_jmp_code, 5);

PageProtectOn();

}

NTSTATUS NewNtCreateFile(
__out PHANDLE FileHandle,
__in ACCESS_MASK DesiredAccess,
__in POBJECT_ATTRIBUTES ObjectAttributes,
__out PIO_STATUS_BLOCK IoStatusBlock,
__in_opt PLARGE_INTEGER AllocationSize,
__in ULONG FileAttributes,
__in ULONG ShareAccess,
__in ULONG CreateDisposition,
__in ULONG CreateOptions,
__in_bcount_opt(EaLength) PVOID EaBuffer,
__in ULONG EaLength
)
{
ULONG u_call_retaddr;

__asm{
pushad
mov eax, [ebp + 0x4]
mov u_call_retaddr, eax
popad
}

g_fastcall_hookpointer = SearchHookPointer(u_call_retaddr);
if (g_fastcall_hookpointer == 0)
{
KdPrint(("search failed."));
}
else{
KdPrint(("search success."));
}

g_goto_origfunc = g_fastcall_hookpointer + 5;
HookKiFastCallEntry(g_fastcall_hookpointer);

PageProtectOff();
KeServiceDescriptorTable.ServiceTableBase[37] = (unsigned int)g_ntcreatefile;
PageProtectOn();

return ((NTCREATEFILE)g_ntcreatefile)(
FileHandle, \
DesiredAccess, \
ObjectAttributes, \
IoStatusBlock, \
AllocationSize, \
FileAttributes, \
ShareAccess, \
CreateDisposition, \
CreateOptions, \
EaBuffer, \
EaLength);
}


void SearchKiFastCallEntry()
{
HANDLE hFile;
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjAttr;
UNICODE_STRING usFileName;
IO_STATUS_BLOCK IoStatusBlock;

RtlInitUnicodeString(&usFileName, L"\\??\\C:\\Windows\\System32\\ntkrnlpa.exe");
InitializeObjectAttributes(\
&ObjAttr, \
&usFileName, \
OBJ_CASE_INSENSITIVE, \
NULL, \
NULL);

g_ntcreatefile = KeServiceDescriptorTable.ServiceTableBase[37];
PageProtectOff();
KeServiceDescriptorTable.ServiceTableBase[37] = (unsigned int)NewNtCreateFile;
PageProtectOn();

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))
{
ZwClose(hFile);
}
}


VOID SetNewSSDT(\
PVOID pNewImage, \
PVOID pOrigImage, \
ServiceDescriptorTableEntry_t **pNewSeviceTable)
{
ULONG uIndex;
ULONG uNewKernelInc, uOffset;
ServiceDescriptorTableEntry_t *pNewSSDT;


uNewKernelInc = (ULONG)pNewImage - (ULONG)pOrigImage;
pNewSSDT = (ServiceDescriptorTableEntry_t *)((ULONG)&KeServiceDescriptorTable + uNewKernelInc);

if (!MmIsAddressValid(pNewSSDT))
{
KdPrint(("pNewSSDT"));
return;
}

pNewSSDT->NumberOfServices = KeServiceDescriptorTable.NumberOfServices;

uOffset = (ULONG)KeServiceDescriptorTable.ServiceTableBase - (ULONG)pOrigImage;
pNewSSDT->ServiceTableBase = (unsigned int*)((ULONG)pNewImage + uOffset);
if (!MmIsAddressValid(pNewSSDT->ServiceTableBase))
{
KdPrint(("pNewSSDT->ServiceTableBase:%X", pNewSSDT->ServiceTableBase));
return;
}

for (uIndex = 0; uIndex < pNewSSDT->NumberOfServices; uIndex++)
{
pNewSSDT->ServiceTableBase[uIndex] += uNewKernelInc;
}

uOffset = (ULONG)KeServiceDescriptorTable.ParamTableBase - (ULONG)pOrigImage;
pNewSSDT->ParamTableBase = (unsigned char*)((ULONG)pNewImage + uOffset);
if (!MmIsAddressValid(pNewSSDT->ParamTableBase))
{
KdPrint(("pNewSSDT->ParamTableBase"));
return;
}
RtlCopyMemory(pNewSSDT->ParamTableBase, KeServiceDescriptorTable.ParamTableBase, pNewSSDT->NumberOfServices*sizeof(char));

*pNewSeviceTable = pNewSSDT;
KdPrint(("set new ssdt success."));
}


void RelocModule(PVOID pNewImage, PVOID pOrigImage)
{
ULONG uIndex;
ULONG uRelocTableSize;
USHORT TypeValue;
USHORT *pwOffsetArrayAddress;
ULONG uTypeOffsetArraySize;
ULONG uRelocOffset;
ULONG uRelocAddress;

PIMAGE_DOS_HEADER pImageDosHeader;
PIMAGE_NT_HEADERS pImageNtHeader;
IMAGE_DATA_DIRECTORY ImageDataDirectory;
IMAGE_BASE_RELOCATION *pImageBaseRelocation;

pImageDosHeader = (PIMAGE_DOS_HEADER)pNewImage;
pImageNtHeader = (PIMAGE_NT_HEADERS)((ULONG)pNewImage + pImageDosHeader->e_lfanew);

uRelocOffset = (ULONG)pOrigImage - pImageNtHeader->OptionalHeader.ImageBase;
//DbgPrint("pOrigImage -- %x, uRelocOffset -- %x", pOrigImage, uRelocOffset);

ImageDataDirectory = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];

pImageBaseRelocation = (PIMAGE_BASE_RELOCATION)(ImageDataDirectory.VirtualAddress + (ULONG)pNewImage);
uRelocTableSize = ImageDataDirectory.Size;

while (uRelocTableSize)
{
uTypeOffsetArraySize = (pImageBaseRelocation->SizeOfBlock - sizeof(ULONG)* 2) / sizeof(USHORT);

pwOffsetArrayAddress = pImageBaseRelocation->TypeOffset;
for (uIndex = 0; uIndex < uTypeOffsetArraySize; uIndex++)
{
TypeValue = pwOffsetArrayAddress[uIndex];
if (TypeValue >> 12 == IMAGE_REL_BASED_HIGHLOW)
{
uRelocAddress = (TypeValue & 0xfff) + pImageBaseRelocation->VirtualAddress + (ULONG)pNewImage;
if (!MmIsAddressValid((PVOID)uRelocAddress))
{
continue;
}

*(ULONG*)uRelocAddress += uRelocOffset;
}
}

uRelocTableSize -= pImageBaseRelocation->SizeOfBlock;
pImageBaseRelocation = (IMAGE_BASE_RELOCATION *)(\
(ULONG)pImageBaseRelocation + pImageBaseRelocation->SizeOfBlock);
}
}


NTSTATUS ReadFileToMemory(wchar_t *strFileName, PVOID *lpVirtualAddress, PVOID pOrigImage)
{
NTSTATUS Status;
LARGE_INTEGER FileOffset;
HANDLE hFile;
OBJECT_ATTRIBUTES ObjAttr;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING usFileName;
IMAGE_DOS_HEADER ImageDosHeader;
IMAGE_NT_HEADERS ImageNtHeader;
IMAGE_SECTION_HEADER *pImageSectionHeader;

PVOID lpVirtualPointer;
ULONG SecVirtualAddress, SizeOfSection;
ULONG PointerToRawData;

ULONG uIndex = 0;

if (!MmIsAddressValid(strFileName))
{
return STATUS_UNSUCCESSFUL;
}
RtlInitUnicodeString(&usFileName, strFileName);

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 Error --- %#X", Status);
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 Error --- %#X", Status);
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 Error --- %#X", Status);
ZwClose(hFile);
return Status;
}

pImageSectionHeader = ExAllocatePool(NonPagedPool, sizeof(IMAGE_SECTION_HEADER)*ImageNtHeader.FileHeader.NumberOfSections);
if (pImageSectionHeader == NULL)
{
DbgPrint("ExAllocatePool pImageSectionHeader Error --- ");
return STATUS_UNSUCCESSFUL;
}

FileOffset.QuadPart = ImageDosHeader.e_lfanew + 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 ImageSectionHeader Error --- %#X", Status);
ExFreePool(pImageSectionHeader);
ZwClose(hFile);
return Status;
}

lpVirtualPointer = ExAllocatePool(NonPagedPool, ImageNtHeader.OptionalHeader.SizeOfImage);
if (lpVirtualPointer == NULL)
{
DbgPrint("ExAllocatePool Error ");
ExFreePool(pImageSectionHeader);
ZwClose(hFile);
return STATUS_UNSUCCESSFUL;
}

memset(lpVirtualPointer, 0, ImageNtHeader.OptionalHeader.SizeOfImage);
RtlCopyMemory(lpVirtualPointer, &ImageDosHeader, sizeof(IMAGE_DOS_HEADER));
RtlCopyMemory((PVOID)((ULONG)lpVirtualPointer+ImageDosHeader.e_lfanew),
&ImageNtHeader,
sizeof(IMAGE_NT_HEADERS));
RtlCopyMemory((PVOID)((ULONG)lpVirtualPointer + ImageDosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS)),
pImageSectionHeader, sizeof(IMAGE_SECTION_HEADER)*ImageNtHeader.FileHeader.NumberOfSections);

for (uIndex = 0; uIndex < ImageNtHeader.FileHeader.NumberOfSections; uIndex++)
{
SecVirtualAddress = pImageSectionHeader[uIndex].VirtualAddress;
SizeOfSection = __Max(pImageSectionHeader[uIndex].SizeOfRawData,
pImageSectionHeader[uIndex].Misc.VirtualSize);

PointerToRawData = pImageSectionHeader[uIndex].PointerToRawData;
FileOffset.QuadPart = PointerToRawData;

Status = ZwReadFile(hFile, NULL, NULL, NULL, &IoStatusBlock, (PVOID)((ULONG)lpVirtualPointer + SecVirtualAddress),
SizeOfSection, &FileOffset, NULL);

if (!NT_SUCCESS(Status))
{
DbgPrint("ZwReadFile ImageSectionHeader Error --- %#X", Status);
ExFreePool(pImageSectionHeader);
ExFreePool(lpVirtualPointer);
ZwClose(hFile);
return Status;
}

}

//基址重定位
RelocModule(lpVirtualPointer, pOrigImage);
SetNewSSDT(lpVirtualPointer, pOrigImage, &g_pNewSeviceTable);
//DbgPrint("RelocModule ok!");

//释放内存
ExFreePool(pImageSectionHeader);
*lpVirtualAddress = lpVirtualPointer;
DbgPrint("文件内存复制成功");

ZwClose(hFile);

return STATUS_SUCCESS;
}



PLDR_DATA_TABLE_ENTRY SearchDriver(PDRIVER_OBJECT pDriverObject, wchar_t *strDriverName)
{

ULONG Base = 0;//模块基地址
LDR_DATA_TABLE_ENTRY* SectionBase = 0;
LIST_ENTRY* Entry = 0;
LIST_ENTRY InLoadOrderLinks = { 0 };
UNICODE_STRING usModuleName;

RtlInitUnicodeString(&usModuleName, strDriverName);
Entry = ((LIST_ENTRY*)pDriverObject->DriverSection)->Flink;


do{
SectionBase = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);//得到这个Entry所属的Section的地址,此方法经过验证可行
if (SectionBase->EntryPoint &&
SectionBase->BaseDllName.Buffer &&
SectionBase->FullDllName.Buffer &&
SectionBase->LoadCount
)
{
//KdPrint(("%wZ", &SectionBase->BaseDllName));
//DbgPrint("模块名称:%wZ,地址:%x\n", &(SectionBase->FullDllName), SectionBase->DllBase);
if (0 == RtlCompareUnicodeString(&SectionBase->BaseDllName, &usModuleName, FALSE))
{
KdPrint(("----%wZ-----", &SectionBase->BaseDllName));
return SectionBase;
}
//DbgPrint("方法一遍历模块名称:%wZ,地址:%x\n", &(SectionBase->FullDllName), SectionBase->DllBase);
}
Entry = Entry->Flink;
} while (Entry != ((LIST_ENTRY*)pDriverObject->DriverSection)->Flink);//直到遍历回来

return 0;
}



VOID DriverUnload(IN PDRIVER_OBJECT pDriverObject)
{
DbgPrint("DriverUnload");

if (g_lpVirtualPointer)
{
ExFreePool(g_lpVirtualPointer);
UnHookKiFastCallEntry();
}
}



NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING RegistryPath)
{
//C:\WINDOWS\system32\ntkrnlpa.exe
//ReadFileToMemory(L"\\??\\C:\\WINDOWS\\system32\\ntkrnlpa.exe", &g_lpVitutalPointer, (PVOID)0x804D8000);
//Method1(pDriverObject);
PLDR_DATA_TABLE_ENTRY pLdrDataTableEntry;
pLdrDataTableEntry = SearchDriver(pDriverObject, L"ntoskrnl.exe");
//g_lpVitutalPointer
if (pLdrDataTableEntry)
{
ReadFileToMemory(L"\\??\\C:\\Windows\\System32\\ntkrnlpa.exe", &g_lpVirtualPointer, pLdrDataTableEntry->DllBase);
KdPrint(("g_lpVirtualPointer:%X", g_lpVirtualPointer));
g_NewKernelInc = (ULONG)g_lpVirtualPointer - (ULONG)pLdrDataTableEntry->DllBase;
SearchKiFastCallEntry();
}


pDriverObject->DriverUnload = DriverUnload;
DbgPrint("DriverEntry");

return STATUS_SUCCESS;
}


发表评论:
昵称

邮件地址 (选填)

个人主页 (选填)

内容