See More

/* * * Copyright (c) 2015-2017 by blindtiger ( [email protected] ) * * The contents of this file are subject to the Mozilla Public License Version * 2.0 (the "License")); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. SEe the License * for the specific language governing rights and limitations under the * License. * * The Initial Developer of the Original e is blindtiger. * */ #include #include #include #ifdef _WIN64 #include #endif // _WIN64 #include "Except.h" #include "Reload.h" #include "Testis.h" static PLIST_ENTRY LdrList; NTSTATUS NTAPI ProtectPages( __inout PVOID BaseAddress, __inout SIZE_T RegionSize, __in ULONG NewProtect, __out PULONG OldProtect ) { NTSTATUS Status = STATUS_SUCCESS; Status = StubProtectVirtualMemory( ZwCurrentProcess(), &BaseAddress, &RegionSize, NewProtect, OldProtect); return Status; } NTSTATUS NTAPI FindEntryForDriver( __in PSTR DriverName, __out PKLDR_DATA_TABLE_ENTRY * DataTableEntry ) { NTSTATUS Status = STATUS_SUCCESS; PDRIVER_OBJECT DriverObject = NULL; UNICODE_STRING DriverPath = { 0 }; PKLDR_DATA_TABLE_ENTRY LdrDataTableEntry = NULL; PKLDR_DATA_TABLE_ENTRY FoundDataTableEntry = NULL; ANSI_STRING AnsiImageFileName = { 0 }; UNICODE_STRING ImageFileName = { 0 }; extern POBJECT_TYPE * IoDriverObjectType; if (NULL != LdrList) { LdrDataTableEntry = CONTAINING_RECORD( LdrList, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks); FoundDataTableEntry = CONTAINING_RECORD( LdrDataTableEntry->InLoadOrderLinks.Flink, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks); RtlInitAnsiString(&AnsiImageFileName, DriverName); Status = RtlAnsiStringToUnicodeString( &ImageFileName, &AnsiImageFileName, TRUE); if (NT_SUCCESS(Status)) { Status = STATUS_NO_MORE_ENTRIES; while (FoundDataTableEntry != LdrDataTableEntry) { if (FoundDataTableEntry->DllBase) { if (FALSE != RtlEqualUnicodeString( &ImageFileName, &FoundDataTableEntry->BaseDllName, TRUE)) { *DataTableEntry = FoundDataTableEntry; Status = STATUS_SUCCESS; goto exit; } } FoundDataTableEntry = CONTAINING_RECORD( FoundDataTableEntry->InLoadOrderLinks.Flink, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks); } RtlFreeUnicodeString(&ImageFileName); } } RtlInitUnicodeString( &DriverPath, L"\\Driver\\disk"); Status = ObReferenceObjectByName( &DriverPath, OBJ_CASE_INSENSITIVE, NULL, FILE_ALL_ACCESS, *IoDriverObjectType, KernelMode, NULL, &DriverObject); if (NT_SUCCESS(Status)) { LdrDataTableEntry = DriverObject->DriverSection; if (NULL != LdrDataTableEntry) { FoundDataTableEntry = CONTAINING_RECORD( LdrDataTableEntry->InLoadOrderLinks.Flink, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks); RtlInitAnsiString(&AnsiImageFileName, DriverName); Status = RtlAnsiStringToUnicodeString( &ImageFileName, &AnsiImageFileName, TRUE); if (NT_SUCCESS(Status)) { Status = STATUS_NO_MORE_ENTRIES; while (FoundDataTableEntry != LdrDataTableEntry) { if (NULL != FoundDataTableEntry->DllBase) { if (FALSE != RtlEqualUnicodeString( &ImageFileName, &FoundDataTableEntry->BaseDllName, TRUE)) { *DataTableEntry = FoundDataTableEntry; Status = STATUS_SUCCESS; break; } } FoundDataTableEntry = CONTAINING_RECORD( FoundDataTableEntry->InLoadOrderLinks.Flink, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks); } RtlFreeUnicodeString(&ImageFileName); } } ObDereferenceObject(DriverObject); } exit: return Status; } NTSTATUS NTAPI FindEntryForAddress( __in PVOID Address, __out PLDR_DATA_TABLE_ENTRY * TableEntry ) { NTSTATUS Status = STATUS_NO_MORE_ENTRIES; PPEB Peb = NULL; PPEB_LDR_DATA Ldr = NULL; PLDR_DATA_TABLE_ENTRY DataTableEntry = NULL; PLDR_DATA_TABLE_ENTRY LdrDataTableEntry = NULL; PLDR_DATA_TABLE_ENTRY FoundDataTableEntry = NULL; if ((ULONG_PTR)Address > *(PULONG_PTR)MM_HIGHEST_USER_ADDRESS) { if (NULL != LdrList) { LdrDataTableEntry = CONTAINING_RECORD( LdrList, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks); FoundDataTableEntry = CONTAINING_RECORD( LdrDataTableEntry->InLoadOrderLinks.Flink, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks); while (FoundDataTableEntry != LdrDataTableEntry) { if ((ULONG_PTR)Address >= (ULONG_PTR)FoundDataTableEntry->DllBase && (ULONG_PTR)Address <= (ULONG_PTR)FoundDataTableEntry->DllBase + FoundDataTableEntry->SizeOfImage) { *TableEntry = FoundDataTableEntry; Status = STATUS_SUCCESS; goto exit; } FoundDataTableEntry = CONTAINING_RECORD( FoundDataTableEntry->InLoadOrderLinks.Flink, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks); } } #define KERNEL_NAME "ntoskrnl.exe" Status = FindEntryForDriver( KERNEL_NAME, &DataTableEntry); if (NT_SUCCESS(Status)) { Status = STATUS_NO_MORE_ENTRIES; LdrDataTableEntry = CONTAINING_RECORD( DataTableEntry->InLoadOrderLinks.Blink, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks); FoundDataTableEntry = CONTAINING_RECORD( LdrDataTableEntry->InLoadOrderLinks.Flink, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks); while (FoundDataTableEntry != LdrDataTableEntry) { if ((ULONG_PTR)Address >= (ULONG_PTR)FoundDataTableEntry->DllBase && (ULONG_PTR)Address <= (ULONG_PTR)FoundDataTableEntry->DllBase + FoundDataTableEntry->SizeOfImage) { *TableEntry = FoundDataTableEntry; Status = STATUS_SUCCESS; goto exit; } FoundDataTableEntry = CONTAINING_RECORD( FoundDataTableEntry->InLoadOrderLinks.Flink, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks); } } } Peb = PsGetProcessPeb(IoGetCurrentProcess()); if (NULL != Peb) { Ldr = Peb->Ldr; if (NULL != Ldr) { LdrDataTableEntry = CONTAINING_RECORD( &Ldr->InLoadOrderModuleList, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); FoundDataTableEntry = CONTAINING_RECORD( LdrDataTableEntry->InLoadOrderLinks.Flink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); if (NULL == Address) { Address = Peb->ImageBaseAddress; } while (FoundDataTableEntry != LdrDataTableEntry) { if ((ULONG_PTR)Address >= (ULONG_PTR)FoundDataTableEntry->DllBase && (ULONG_PTR)Address <= (ULONG_PTR)FoundDataTableEntry->DllBase + FoundDataTableEntry->SizeOfImage) { *TableEntry = FoundDataTableEntry; Status = STATUS_SUCCESS; goto exit; } FoundDataTableEntry = CONTAINING_RECORD( FoundDataTableEntry->InLoadOrderLinks.Flink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); } } } exit: return Status; } PVOID NTAPI GetImageHandle( __in PSTR ImageName ) { NTSTATUS Status = STATUS_NO_MORE_ENTRIES; PPEB Peb = NULL; PPEB_LDR_DATA Ldr = NULL; PLDR_DATA_TABLE_ENTRY LdrDataTableEntry = NULL; PLDR_DATA_TABLE_ENTRY FoundDataTableEntry = NULL; ANSI_STRING AnsiImageFileName = { 0 }; UNICODE_STRING ImageFileName = { 0 }; PVOID ImageBase = 0; if (NULL != ImageName) { Status = FindEntryForDriver( ImageName, &LdrDataTableEntry); if (Status >= 0) { ImageBase = LdrDataTableEntry->DllBase; goto exit; } } Peb = PsGetProcessPeb(IoGetCurrentProcess()); if (NULL != Peb) { Ldr = Peb->Ldr; if (NULL != Ldr) { LdrDataTableEntry = CONTAINING_RECORD( &Ldr->InLoadOrderModuleList, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); FoundDataTableEntry = CONTAINING_RECORD( LdrDataTableEntry->InLoadOrderLinks.Flink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); if (NULL == ImageName) { ImageBase = Peb->ImageBaseAddress; goto exit; } else { RtlInitAnsiString( &AnsiImageFileName, ImageName); Status = RtlAnsiStringToUnicodeString( &ImageFileName, &AnsiImageFileName, TRUE); if (NT_SUCCESS(Status)) { while (FoundDataTableEntry != LdrDataTableEntry) { if (FALSE != RtlEqualUnicodeString( &ImageFileName, &FoundDataTableEntry->BaseDllName, TRUE)) { ImageBase = FoundDataTableEntry->DllBase; break; } FoundDataTableEntry = CONTAINING_RECORD( FoundDataTableEntry->InLoadOrderLinks.Flink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); } RtlFreeUnicodeString(&ImageFileName); } } } } exit: return ImageBase; } PVOID NTAPI FetchAddressOfEntryPoint( __in PVOID ImageBase ) { PIMAGE_NT_HEADERS NtHeaders = NULL; ULONG Offset = 0; PVOID EntryPoint = NULL; __try { if (NULL != NtHeaders) { if (IMAGE_NT_OPTIONAL_HDR32_MAGIC == NtHeaders->OptionalHeader.Magic) { Offset = ((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.AddressOfEntryPoint; } if (IMAGE_NT_OPTIONAL_HDR64_MAGIC == NtHeaders->OptionalHeader.Magic) { Offset = ((PIMAGE_NT_HEADERS64)NtHeaders)->OptionalHeader.AddressOfEntryPoint; } if (0 != Offset) { EntryPoint = (PCHAR)ImageBase + Offset; } } } __except (EXCEPTION_EXECUTE_HANDLER) { EntryPoint = NULL; } return EntryPoint; } ULONG NTAPI FetchTimeStamp( __in PVOID ImageBase ) { PIMAGE_NT_HEADERS NtHeaders = NULL; ULONG TimeStamp = 0; __try { NtHeaders = RtlImageNtHeader(ImageBase); if (NULL != NtHeaders) { TimeStamp = NtHeaders->FileHeader.TimeDateStamp; } } __except (EXCEPTION_EXECUTE_HANDLER) { TimeStamp = 0; } return TimeStamp; } USHORT NTAPI FetchSubsystem( __in PVOID ImageBase ) { PIMAGE_NT_HEADERS NtHeaders = NULL; USHORT Subsystem = 0; __try { NtHeaders = RtlImageNtHeader(ImageBase); if (NULL != NtHeaders) { if (IMAGE_NT_OPTIONAL_HDR32_MAGIC == NtHeaders->OptionalHeader.Magic) { Subsystem = ((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.Subsystem; } if (IMAGE_NT_OPTIONAL_HDR64_MAGIC == NtHeaders->OptionalHeader.Magic) { Subsystem = ((PIMAGE_NT_HEADERS64)NtHeaders)->OptionalHeader.Subsystem; } } } __except (EXCEPTION_EXECUTE_HANDLER) { Subsystem = 0; } return Subsystem; } ULONG NTAPI FetchSizeOfImage( __in PVOID ImageBase ) { PIMAGE_NT_HEADERS NtHeaders = NULL; ULONG SizeOfImage = 0; __try { NtHeaders = RtlImageNtHeader(ImageBase); if (NULL != NtHeaders) { if (IMAGE_NT_OPTIONAL_HDR32_MAGIC == NtHeaders->OptionalHeader.Magic) { SizeOfImage = ((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.SizeOfImage; } if (IMAGE_NT_OPTIONAL_HDR64_MAGIC == NtHeaders->OptionalHeader.Magic) { SizeOfImage = ((PIMAGE_NT_HEADERS64)NtHeaders)->OptionalHeader.SizeOfImage; } } } __except (EXCEPTION_EXECUTE_HANDLER) { SizeOfImage = 0; } return SizeOfImage; } PVOID NTAPI GetProcedureAddress( __in PVOID ImageBase, __in_opt PSTR ProcedureName, __in_opt ULONG ProcedureNumber ) { PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL; ULONG Size = 0; PULONG NameTable = NULL; PUSHORT OrdinalTable = NULL; PULONG AddressTable = NULL; PSTR NameTableName = NULL; USHORT HintIndex = 0; PVOID ProcedureAddress = NULL; ExportDirectory = RtlImageDirectoryEntryToData( ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &Size); if (NULL != ExportDirectory) { NameTable = (PCHAR)ImageBase + ExportDirectory->AddressOfNames; OrdinalTable = (PCHAR)ImageBase + ExportDirectory->AddressOfNameOrdinals; AddressTable = (PCHAR)ImageBase + ExportDirectory->AddressOfFunctions; if (NULL != NameTable && NULL != OrdinalTable && NULL != AddressTable) { if (ProcedureNumber >= ExportDirectory->Base && ProcedureNumber < MAXSHORT) { ProcedureAddress = (PCHAR)ImageBase + AddressTable[ProcedureNumber - ExportDirectory->Base]; } else { for (HintIndex = 0; HintIndex < ExportDirectory->NumberOfNames; HintIndex++) { NameTableName = (PCHAR)ImageBase + NameTable[HintIndex]; if (0 == strcmp( ProcedureName, NameTableName)) { ProcedureAddress = (PCHAR)ImageBase + AddressTable[OrdinalTable[HintIndex]]; } } } } } return ProcedureAddress; } PULONG_PTR NTAPI FindThunk( __in PVOID ImageBase, __in PSTR ImportName, __in_opt PSTR ThunkName, __in_opt ULONG ThunkNumber ) { PIMAGE_IMPORT_DESCRIPTOR ImportDirectory = NULL; ULONG Size = 0; PIMAGE_THUNK_DATA OriginalThunk = NULL; PIMAGE_THUNK_DATA Thunk = NULL; PIMAGE_IMPORT_BY_NAME ImportByName = NULL; USHORT Ordinal = 0; PSTR ForwardImageName = NULL; ULONG Index = 0; PULONG_PTR FoundThunk = NULL; ImportDirectory = RtlImageDirectoryEntryToData( ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &Size); if (0 != Size) { do { OriginalThunk = (PCHAR)ImageBase + ImportDirectory->OriginalFirstThunk; Thunk = (PCHAR)ImageBase + ImportDirectory->FirstThunk; ForwardImageName = (PCHAR)ImageBase + ImportDirectory->Name; if (0 == _stricmp( ImportName, ForwardImageName)) { do { if (IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal)) { Ordinal = (USHORT)IMAGE_ORDINAL(OriginalThunk->u1.Ordinal); if (ThunkNumber == Ordinal) { FoundThunk = &Thunk->u1.Function; goto exit; } } else { ImportByName = (PCHAR)ImageBase + OriginalThunk->u1.AddressOfData; if (0 == _stricmp( ImportByName->Name, ThunkName)) { FoundThunk = &Thunk->u1.Function; goto exit; } } OriginalThunk++; Thunk++; } while (OriginalThunk->u1.Function); } ImportDirectory++; } while (0 != ImportDirectory->Characteristics); } exit: return FoundThunk; } VOID NTAPI ReplaceThunk( __in PVOID ImageBase, __in PSTR ImportName, __in PREPLACE_THUNK ThunkTable, __in_bcount(ThunkTable) ULONG ThunkCount ) { PIMAGE_IMPORT_DESCRIPTOR ImportDirectory = NULL; ULONG Size = 0; PIMAGE_THUNK_DATA OriginalThunk = NULL; PIMAGE_THUNK_DATA Thunk = NULL; PIMAGE_IMPORT_BY_NAME ImportByName = NULL; USHORT Ordinal = 0; PSTR ForwardImageName = NULL; ULONG Index = 0; ImportDirectory = RtlImageDirectoryEntryToData( ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &Size); if (0 != Size) { do { OriginalThunk = (PCHAR)ImageBase + ImportDirectory->OriginalFirstThunk; Thunk = (PCHAR)ImageBase + ImportDirectory->FirstThunk; ForwardImageName = (PCHAR)ImageBase + ImportDirectory->Name; if (0 == _stricmp( ImportName, ForwardImageName)) { do { if (IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal)) { Ordinal = (USHORT)IMAGE_ORDINAL(OriginalThunk->u1.Ordinal); } else { ImportByName = (PCHAR)ImageBase + OriginalThunk->u1.AddressOfData; for (Index = 0; Index < ThunkCount; Index++) { if (0 == _stricmp( ImportByName->Name, ThunkTable[Index].Name)) { Thunk->u1.Function = (ULONG_PTR)ThunkTable[Index].Function; } } } OriginalThunk++; Thunk++; } while (OriginalThunk->u1.Function); } ImportDirectory++; } while (0 != ImportDirectory->Characteristics); } } VOID NTAPI SnapThunk( __in PVOID ImageBase ) { PIMAGE_IMPORT_DESCRIPTOR ImportDirectory = NULL; ULONG Size = 0; PIMAGE_THUNK_DATA OriginalThunk = NULL; PIMAGE_THUNK_DATA Thunk = NULL; PIMAGE_IMPORT_BY_NAME ImportByName = NULL; USHORT Ordinal = 0; PSTR ForwardImageName = NULL; PSTR ForwardImageBase = NULL; PVOID FunctionAddress = NULL; ImportDirectory = RtlImageDirectoryEntryToData( ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &Size); if (0 != Size) { do { OriginalThunk = (PCHAR)ImageBase + ImportDirectory->OriginalFirstThunk; Thunk = (PCHAR)ImageBase + ImportDirectory->FirstThunk; ForwardImageName = (PCHAR)ImageBase + ImportDirectory->Name; ForwardImageBase = GetImageHandle(ForwardImageName); if (NULL != ForwardImageBase) { do { if (IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal)) { Ordinal = (USHORT)IMAGE_ORDINAL(OriginalThunk->u1.Ordinal); FunctionAddress = GetProcedureAddress( ForwardImageBase, NULL, Ordinal); if (NULL != FunctionAddress) { Thunk->u1.Function = (ULONG_PTR)FunctionAddress; } else { DbgPrint( "Soul - Testis - import procedure ordinal@%d not found\n", Ordinal); } } else { ImportByName = (PCHAR)ImageBase + OriginalThunk->u1.AddressOfData; FunctionAddress = GetProcedureAddress( ForwardImageBase, ImportByName->Name, 0); if (NULL != FunctionAddress) { Thunk->u1.Function = (ULONG_PTR)FunctionAddress; } else { DbgPrint( "Soul - Testis - import procedure %hs not found\n", ImportByName->Name); } } OriginalThunk++; Thunk++; } while (OriginalThunk->u1.Function); } else { DbgPrint( "Soul - Testis - import dll %hs not found\n", ForwardImageName); } ImportDirectory++; } while (0 != ImportDirectory->Characteristics); } } FORCEINLINE ULONG NTAPI GetRelocCount( __in ULONG SizeOfBlock ) { ULONG Count = 0; Count = (SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT); return Count; } PIMAGE_BASE_RELOCATION NTAPI RelocationBlock( __in PVOID VA, __in ULONG Count, __in PUSHORT NextOffset, __in LONG_PTR Diff ) { PUSHORT FixupVA = NULL; USHORT Offset = 0; USHORT Type = 0; while (Count--) { Offset = *NextOffset & 0xfff; FixupVA = (PCHAR)VA + Offset; Type = (*NextOffset >> 12) & 0xf; switch (Type) { case IMAGE_REL_BASED_ABSOLUTE: { break; } case IMAGE_REL_BASED_HIGH: { FixupVA[1] += (USHORT)((Diff >> 16) & 0xffff); break; } case IMAGE_REL_BASED_LOW: { FixupVA[0] += (USHORT)(Diff & 0xffff); break; } case IMAGE_REL_BASED_HIGHLOW: { *(PULONG)FixupVA += (ULONG)Diff; break; } case IMAGE_REL_BASED_HIGHADJ: { FixupVA[0] += NextOffset[1] & 0xffff; FixupVA[1] += (USHORT)((Diff >> 16) & 0xffff); ++NextOffset; --Count; break; } case IMAGE_REL_BASED_MIPS_JMPADDR: case IMAGE_REL_BASED_SECTION: case IMAGE_REL_BASED_REL32: // case IMAGE_REL_BASED_VXD_RELATIVE: // case IMAGE_REL_BASED_MIPS_JMPADDR16: case IMAGE_REL_BASED_IA64_IMM64: { break; } case IMAGE_REL_BASED_DIR64: { *(PULONG_PTR)FixupVA += Diff; break; } default: { return NULL; } } ++NextOffset; } return (PIMAGE_BASE_RELOCATION)NextOffset; } VOID NTAPI RelocateImage( __in PVOID ImageBase, __in LONG_PTR Diff ) { PIMAGE_BASE_RELOCATION RelocDirectory = NULL; ULONG Size = 0; PVOID VA = 0; RelocDirectory = RtlImageDirectoryEntryToData( ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &Size); if (0 != Size) { if (0 != Diff) { while (0 != Size) { VA = (PCHAR)ImageBase + RelocDirectory->VirtualAddress; Size -= RelocDirectory->SizeOfBlock; RelocDirectory = RelocationBlock( VA, GetRelocCount(RelocDirectory->SizeOfBlock), (PUSHORT)(RelocDirectory + 1), Diff); } } } } PVOID NTAPI AllocatePages( __in PVOID ViewBase ) { NTSTATUS Status = STATUS_SUCCESS; PVOID ImageBase = NULL; PHYSICAL_ADDRESS HighestAcceptableAddress = { 0 }; USHORT Subsystem = 0; ULONG SizeOfImage = 0; ULONG OldProtect = 0; Subsystem = FetchSubsystem(ViewBase); SizeOfImage = FetchSizeOfImage(ViewBase); if (0 != SizeOfImage) { if (IMAGE_SUBSYSTEM_NATIVE == Subsystem) { HighestAcceptableAddress.QuadPart = -1; ImageBase = MmAllocateContiguousMemory( SizeOfImage, HighestAcceptableAddress); } else if (IMAGE_SUBSYSTEM_WINDOWS_GUI == Subsystem || IMAGE_SUBSYSTEM_WINDOWS_CUI == Subsystem) { Status = ZwAllocateVirtualMemory( ZwCurrentProcess(), &ImageBase, 0, &SizeOfImage, MEM_COMMIT, PAGE_EXECUTE); if (NT_SUCCESS(Status)) { Status = ProtectPages( ImageBase, SizeOfImage, PAGE_READWRITE, &OldProtect); } } else { DbgPrint( "Soul - Testis - image type not supported.\n"); } } return ImageBase; } VOID NTAPI UnloadImage( __in PVOID ImageBase ) { NTSTATUS Status = STATUS_SUCCESS; USHORT Subsystem = 0; SIZE_T RegionSize = 0; Subsystem = FetchSubsystem(ImageBase); if (IMAGE_SUBSYSTEM_NATIVE == Subsystem) { MmFreeContiguousMemory(ImageBase); } else if (IMAGE_SUBSYSTEM_WINDOWS_GUI == Subsystem || IMAGE_SUBSYSTEM_WINDOWS_CUI == Subsystem) { Status = ZwFreeVirtualMemory( ZwCurrentProcess(), &ImageBase, &RegionSize, MEM_RELEASE); NT_SUCCESS(Status); } } PVOID NTAPI MapImage( __in PVOID ViewBase ) { NTSTATUS Status = STATUS_SUCCESS; PVOID ImageBase = NULL; PIMAGE_NT_HEADERS NtHeaders = NULL; PIMAGE_SECTION_HEADER NtSection = NULL; LONG_PTR Diff = 0; SIZE_T Index = 0; __try { NtHeaders = RtlImageNtHeader(ViewBase); if (NULL != NtHeaders) { ImageBase = AllocatePages(ViewBase); if (NULL != ImageBase) { RtlZeroMemory( ImageBase, NtHeaders->OptionalHeader.SizeOfImage); NtSection = IMAGE_FIRST_SECTION(NtHeaders); RtlCopyMemory( ImageBase, ViewBase, NtSection->VirtualAddress); for (Index = 0; Index < NtHeaders->FileHeader.NumberOfSections; Index++) { RtlCopyMemory( (PCHAR)ImageBase + NtSection[Index].VirtualAddress, (PCHAR)ViewBase + NtSection[Index].PointerToRawData, NtSection[Index].SizeOfRawData); } NtHeaders = RtlImageNtHeader(ImageBase); Diff = (LONG_PTR)ImageBase - NtHeaders->OptionalHeader.ImageBase; NtHeaders->OptionalHeader.ImageBase = (ULONG_PTR)ImageBase; RelocateImage(ImageBase, Diff); SnapThunk(ImageBase); } } } __except (EXCEPTION_EXECUTE_HANDLER) { ImageBase = NULL; } return ImageBase; } static ULONG NTAPI MakeProtection( __in PIMAGE_SECTION_HEADER NtSection ) { ULONG Protection = 0; __try { if (FlagOn( NtSection->Characteristics, IMAGE_SCN_MEM_WRITE) == IMAGE_SCN_MEM_WRITE) { Protection = PAGE_READWRITE; } else { if (FlagOn( NtSection->Characteristics, IMAGE_SCN_MEM_EXECUTE) == IMAGE_SCN_MEM_EXECUTE) { Protection = PAGE_EXECUTE_READ; } else { Protection = PAGE_READONLY; } if (FlagOn( NtSection->Characteristics, IMAGE_SCN_MEM_NOT_CACHED) == IMAGE_SCN_MEM_NOT_CACHED) { Protection |= PAGE_NOCACHE; } } } __except (EXCEPTION_EXECUTE_HANDLER) { Protection = PAGE_EXECUTE_READWRITE; } return Protection; } VOID NTAPI SetImageProtection( __in PVOID ImageBase, __in BOOLEAN Reset ) { PIMAGE_NT_HEADERS NtHeaders = NULL; PIMAGE_SECTION_HEADER NtSection = NULL; ULONG OldProtection = 0; ULONG SizeToLock = 0; ULONG SizeOfImage = 0; PVOID BaseAddress = NULL; SIZE_T RegionSize = 0; ULONG Index = 0; __try { NtHeaders = RtlImageNtHeader(ImageBase); SizeOfImage = FetchSizeOfImage(ImageBase); if (NULL != NtHeaders) { NtSection = IMAGE_FIRST_SECTION(NtHeaders); BaseAddress = ImageBase; RegionSize = NtSection->VirtualAddress; ProtectPages( BaseAddress, RegionSize, PAGE_READONLY, &OldProtection); for (Index = 0; Index < NtHeaders->FileHeader.NumberOfSections; Index++) { if (0 != NtSection[Index].PointerToRawData) { SizeToLock = NtSection[Index].SizeOfRawData; if (SizeToLock < NtSection[Index].Misc.VirtualSize) { SizeToLock = NtSection[Index].Misc.VirtualSize; } BaseAddress = (PCHAR)ImageBase + NtSection[Index].VirtualAddress; RegionSize = SizeToLock; ProtectPages( BaseAddress, RegionSize, FALSE != Reset ? PAGE_EXECUTE_READWRITE : MakeProtection(&NtSection[Index]), &OldProtection); } } } } __except (EXCEPTION_EXECUTE_HANDLER) { NOTHING; } } VOID NTAPI LoadImage( __in PVOID ViewBase, __out_opt PVOID * ImageHandle ) { PVOID ImageBase = NULL; ImageBase = MapImage(ViewBase); if (NULL != ImageBase) { if ((ULONG_PTR)ImageBase <= *(PULONG_PTR)MM_HIGHEST_USER_ADDRESS) { SetImageProtection(ImageBase, FALSE); #ifndef _WIN64 if (OsBuildNumber < 9200) { InsertUserSpecialInvertedFunctionTable( ImageBase, FetchSizeOfImage(ImageBase)); } else { InsertUserInvertedFunctionTable( ImageBase, FetchSizeOfImage(ImageBase)); } #else InsertUserInvertedFunctionTable( ImageBase, FetchSizeOfImage(ImageBase)); #endif // !_WIN64 } else { if (NULL != LdrList) { InsertInvertedFunctionTable( ImageBase, FetchSizeOfImage(ImageBase)); } } *ImageHandle = ImageBase; } } PKLDR_DATA_TABLE_ENTRY NTAPI InsertDataTableEntry( __in PCWSTR ImageName, __in PVOID ImageHandle ) { PKLDR_DATA_TABLE_ENTRY DataTableEntry = NULL; if (NULL == LdrList) { LdrList = ExAllocatePool( NonPagedPool, sizeof(LIST_ENTRY)); if (NULL != LdrList) { InitializeListHead(LdrList); } } if (NULL != LdrList) { DataTableEntry = ExAllocatePool( NonPagedPool, sizeof(KLDR_DATA_TABLE_ENTRY) + MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR) * 2); if (NULL != DataTableEntry) { RtlZeroMemory( DataTableEntry, sizeof(KLDR_DATA_TABLE_ENTRY) + MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR) * 2); DataTableEntry->DllBase = ImageHandle; DataTableEntry->SizeOfImage = FetchSizeOfImage(ImageHandle); DataTableEntry->EntryPoint = FetchAddressOfEntryPoint(ImageHandle); CaptureImageExceptionValues( ImageHandle, &DataTableEntry->ExceptionTable, &DataTableEntry->ExceptionTableSize); DataTableEntry->FullDllName.Buffer = DataTableEntry + 1; DataTableEntry->FullDllName.MaximumLength = MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR); wcscat( DataTableEntry->FullDllName.Buffer, L"Pfs:\\"); wcscat( DataTableEntry->FullDllName.Buffer, ImageName); DataTableEntry->FullDllName.Length = wcslen(DataTableEntry->FullDllName.Buffer) * sizeof(WCHAR); DataTableEntry->BaseDllName.Buffer = DataTableEntry->FullDllName.Buffer + MAXIMUM_FILENAME_LENGTH; DataTableEntry->BaseDllName.MaximumLength = MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR); wcscat( DataTableEntry->BaseDllName.Buffer, ImageName); DataTableEntry->BaseDllName.Length = wcslen(DataTableEntry->BaseDllName.Buffer) * sizeof(WCHAR); InsertTailList( LdrList, &DataTableEntry->InLoadOrderLinks); } } return DataTableEntry; } #ifdef _WIN64 NTSTATUS NTAPI Wx86FindEntryForAddress( __in PVOID Address, __out PLDR_DATA_TABLE_ENTRY32 * TableEntry ) { NTSTATUS Status = STATUS_NO_MORE_ENTRIES; PWOW64_PROCESS Wow64Process = NULL; PPEB32 Peb = NULL; PPEB_LDR_DATA32 Ldr = NULL; PLDR_DATA_TABLE_ENTRY32 LdrDataTableEntry = NULL; PLDR_DATA_TABLE_ENTRY32 FoundDataTableEntry = NULL; Wow64Process = PsGetCurrentProcessWow64Process(); if (NULL != Wow64Process) { Peb = (PPEB32)&Wow64Process->Wow64; Ldr = ULongToPtr(Peb->Ldr); if (NULL != Ldr) { LdrDataTableEntry = CONTAINING_RECORD( &Ldr->InLoadOrderModuleList, LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks); FoundDataTableEntry = CONTAINING_RECORD( ULongToPtr(LdrDataTableEntry->InLoadOrderLinks.Flink), LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks); if (NULL == Address) { Address = ULongToPtr(Peb->ImageBaseAddress); } while (FoundDataTableEntry != LdrDataTableEntry) { if (PtrToUlong(Address) >= FoundDataTableEntry->DllBase && PtrToUlong(Address) <= FoundDataTableEntry->DllBase + FoundDataTableEntry->SizeOfImage) { *TableEntry = FoundDataTableEntry; Status = STATUS_SUCCESS; goto exit; } FoundDataTableEntry = CONTAINING_RECORD( ULongToPtr(FoundDataTableEntry->InLoadOrderLinks.Flink), LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks); } } } exit: return Status; } ULONG NTAPI Wx86GetImageHandle( __in PSTR ImageName ) { NTSTATUS Status = STATUS_SUCCESS; PWOW64_PROCESS Wow64Process = NULL; PPEB32 Peb = NULL; PPEB_LDR_DATA32 Ldr = NULL; PLDR_DATA_TABLE_ENTRY32 LdrDataTableEntry = NULL; PLDR_DATA_TABLE_ENTRY32 FoundDataTableEntry = NULL; ANSI_STRING AnsiImageFileName = { 0 }; UNICODE_STRING ImageFileName = { 0 }; UNICODE_STRING Wx86ImageFileName = { 0 }; ULONG ImageBase = 0; Wow64Process = PsGetCurrentProcessWow64Process(); if (NULL != Wow64Process) { Peb = (PPEB32)&Wow64Process->Wow64; Ldr = ULongToPtr(Peb->Ldr); if (NULL != Ldr) { LdrDataTableEntry = CONTAINING_RECORD( &Ldr->InLoadOrderModuleList, LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks); FoundDataTableEntry = CONTAINING_RECORD( ULongToPtr(LdrDataTableEntry->InLoadOrderLinks.Flink), LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks); if (NULL == ImageName) { ImageBase = Peb->ImageBaseAddress; goto exit; } else { RtlInitAnsiString( &AnsiImageFileName, ImageName); Status = RtlAnsiStringToUnicodeString( &ImageFileName, &AnsiImageFileName, TRUE); if (NT_SUCCESS(Status)) { while (FoundDataTableEntry != LdrDataTableEntry) { UStr32ToUStr(&Wx86ImageFileName, &FoundDataTableEntry->BaseDllName); if (FALSE != RtlEqualUnicodeString( &ImageFileName, &Wx86ImageFileName, TRUE)) { ImageBase = FoundDataTableEntry->DllBase; RtlFreeUnicodeString(&ImageFileName); goto exit; } FoundDataTableEntry = CONTAINING_RECORD( ULongToPtr(FoundDataTableEntry->InLoadOrderLinks.Flink), LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks); } RtlFreeUnicodeString(&ImageFileName); } } } } exit: return ImageBase; } ULONG NTAPI Wx86GetProcedureAddress( __in ULONG ImageHandle, __in_opt PSTR ProcedureName, __in_opt ULONG ProcedureNumber ) { PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL; ULONG Size = 0; PULONG NameTable = NULL; PUSHORT OrdinalTable = NULL; PULONG AddressTable = NULL; PSTR NameTableName = NULL; USHORT HintIndex = 0; ULONG ProcedureAddress = 0; ExportDirectory = RtlImageDirectoryEntryToData( ULongToPtr(ImageHandle), TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &Size); if (NULL != ExportDirectory) { NameTable = (PCHAR)ULongToPtr(ImageHandle) + ExportDirectory->AddressOfNames; OrdinalTable = (PCHAR)ULongToPtr(ImageHandle) + ExportDirectory->AddressOfNameOrdinals; AddressTable = (PCHAR)ULongToPtr(ImageHandle) + ExportDirectory->AddressOfFunctions; if (NULL != NameTable && NULL != OrdinalTable && NULL != AddressTable) { if (ProcedureNumber >= ExportDirectory->Base && ProcedureNumber < MAXSHORT) { ProcedureAddress = ImageHandle + AddressTable[ProcedureNumber - ExportDirectory->Base]; } else { for (HintIndex = 0; HintIndex < ExportDirectory->NumberOfNames; HintIndex++) { NameTableName = (PCHAR)ULongToPtr(ImageHandle) + NameTable[HintIndex]; if (0 == strcmp( ProcedureName, NameTableName)) { ProcedureAddress = ImageHandle + AddressTable[OrdinalTable[HintIndex]]; } } } } } return ProcedureAddress; } VOID NTAPI Wx86SnapThunk( __in ULONG ImageHandle ) { PIMAGE_IMPORT_DESCRIPTOR ImportDirectory = NULL; ULONG Size = 0; PIMAGE_THUNK_DATA32 OriginalThunk = NULL; PIMAGE_THUNK_DATA32 Thunk = NULL; PIMAGE_IMPORT_BY_NAME ImportByName = NULL; USHORT Ordinal = 0; ULONG ImportDllName = 0; ULONG ImportDllHandle = 0; ULONG FunctionAddress = 0; ImportDirectory = RtlImageDirectoryEntryToData( ULongToPtr(ImageHandle), TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &Size); if (0 != Size) { do { OriginalThunk = (PCHAR)ULongToPtr(ImageHandle) + ImportDirectory->OriginalFirstThunk; Thunk = (PCHAR)ULongToPtr(ImageHandle) + ImportDirectory->FirstThunk; ImportDllName = ImageHandle + ImportDirectory->Name; ImportDllHandle = Wx86GetImageHandle(UlongToPtr(ImportDllName)); if (0 != ImportDllHandle) { do { Ordinal = IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal); if (0 != Ordinal) { FunctionAddress = Wx86GetProcedureAddress( ImportDllHandle, NULL, Ordinal); if (0 != FunctionAddress) { Thunk->u1.Function = FunctionAddress; } else { DbgPrint( "Soul - Testis - import procedure ordinal@%d not found\n", Ordinal); } } else { ImportByName = (PCHAR)ULongToPtr(ImageHandle) + OriginalThunk->u1.AddressOfData; FunctionAddress = Wx86GetProcedureAddress( ImportDllHandle, ImportByName->Name, 0); if (0 != FunctionAddress) { Thunk->u1.Function = FunctionAddress; } else { DbgPrint( "Soul - Testis - import procedure %hs not found\n", ImportByName->Name); } } OriginalThunk++; Thunk++; } while (OriginalThunk->u1.Function); } else { DbgPrint( "Soul - Testis - import dll %hs not found\n", ImportDllName); } ImportDirectory++; } while (0 != ImportDirectory->Characteristics); } } PVOID NTAPI Wx86MapImage( __in PVOID ViewBase ) { NTSTATUS Status = STATUS_SUCCESS; PVOID ImageBase = 0; PIMAGE_NT_HEADERS32 NtHeaders = NULL; PIMAGE_SECTION_HEADER NtSection = NULL; LONG Diff = 0; SIZE_T Index = 0; NtHeaders = RtlImageNtHeader(ViewBase); if (NULL != NtHeaders) { ImageBase = AllocatePages(ViewBase); if (NULL != ImageBase && 0 == ((ULONG_PTR)ImageBase >> 32)) { RtlZeroMemory( ImageBase, NtHeaders->OptionalHeader.SizeOfImage); NtSection = IMAGE_FIRST_SECTION(NtHeaders); RtlCopyMemory( ImageBase, ViewBase, NtSection->VirtualAddress); for (Index = 0; Index < NtHeaders->FileHeader.NumberOfSections; Index++) { if (0 != NtSection[Index].PointerToRawData) { RtlCopyMemory( (PCHAR)ImageBase + NtSection[Index].VirtualAddress, (PCHAR)ViewBase + NtSection[Index].PointerToRawData, NtSection[Index].SizeOfRawData); } } NtHeaders = RtlImageNtHeader(ImageBase); Diff = PtrToLong(ImageBase) - NtHeaders->OptionalHeader.ImageBase; NtHeaders->OptionalHeader.ImageBase = PtrToUlong(ImageBase); RelocateImage(ImageBase, Diff); Wx86SnapThunk(PtrToUlong(ImageBase)); } else { UnloadImage(ImageBase); ImageBase = NULL; } } return ImageBase; } VOID NTAPI Wx86LoadImage( __in PVOID ViewBase, __out PVOID * ImageHandle ) { PVOID ImageBase = NULL; ImageBase = Wx86MapImage(ViewBase); if (NULL != ImageBase) { SetImageProtection(ImageBase, FALSE); if (OsBuildNumber < 9200) { InsertWx86UserSpecialInvertedFunctionTable( ImageBase, FetchSizeOfImage(ImageBase)); } else { InsertWx86UserInvertedFunctionTable( ImageBase, FetchSizeOfImage(ImageBase)); } *ImageHandle = ImageBase; } } #endif // _WIN64