├── README.md ├── LICENSE ├── PeImg.h └── Driver.c /README.md: -------------------------------------------------------------------------------- 1 | # UTKModule 2 | 3 | Ports the PE headers which are used from user API into the kernel code when reading memory from the process in a `LOAD_IMAGE_NOTIFY_ROUTINE` callback to resolve the PE headers with the given base address, points the copy module IAT to the correct one in the virtual process. 4 | 5 | Modifies the code of the RtlUserThreadStart callback and reads the arguments passed to it. Then it changes the initial execution argument for the thread to a different location, but with the same executable memory. Bypasses some generic memory integrity checks. 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jason Johnson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PeImg.h: -------------------------------------------------------------------------------- 1 | #ifndef PE_IMG 2 | #define PE_IMG 3 | 4 | // preprocessors from usermode winapi winnt.h 5 | #define IMAGE_DIRECTORY_ENTRY_IAT 12 6 | #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 7 | 8 | typedef unsigned short WORD; 9 | typedef unsigned long DWORD; 10 | typedef long LONG; 11 | 12 | // PE header structures from usermode winapi winnt.h 13 | 14 | typedef struct _IMAGE_FILE_HEADER { 15 | WORD Machine; 16 | WORD NumberOfSections; 17 | DWORD TimeDateStamp; 18 | DWORD PointerToSymbolTable; 19 | DWORD NumberOfSymbols; 20 | WORD SizeOfOptionalHeader; 21 | WORD Characteristics; 22 | } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; 23 | 24 | typedef struct _IMAGE_DATA_DIRECTORY { 25 | DWORD VirtualAddress; 26 | DWORD Size; 27 | } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; 28 | 29 | typedef struct _IMAGE_OPTIONAL_HEADER { 30 | // 31 | // Standard fields. 32 | // 33 | 34 | WORD Magic; 35 | BYTE MajorLinkerVersion; 36 | BYTE MinorLinkerVersion; 37 | DWORD SizeOfCode; 38 | DWORD SizeOfInitializedData; 39 | DWORD SizeOfUninitializedData; 40 | DWORD AddressOfEntryPoint; 41 | DWORD BaseOfCode; 42 | DWORD BaseOfData; 43 | DWORD ImageBase; 44 | DWORD SectionAlignment; 45 | DWORD FileAlignment; 46 | WORD MajorOperatingSystemVersion; 47 | WORD MinorOperatingSystemVersion; 48 | WORD MajorImageVersion; 49 | WORD MinorImageVersion; 50 | WORD MajorSubsystemVersion; 51 | WORD MinorSubsystemVersion; 52 | DWORD Win32VersionValue; 53 | DWORD SizeOfImage; 54 | DWORD SizeOfHeaders; 55 | DWORD CheckSum; 56 | WORD Subsystem; 57 | WORD DllCharacteristics; 58 | DWORD SizeOfStackReserve; 59 | DWORD SizeOfStackCommit; 60 | DWORD SizeOfHeapReserve; 61 | DWORD SizeOfHeapCommit; 62 | DWORD LoaderFlags; 63 | DWORD NumberOfRvaAndSizes; 64 | IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; 65 | } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; 66 | 67 | typedef struct _IMAGE_NT_HEADERS { 68 | DWORD Signature; 69 | IMAGE_FILE_HEADER FileHeader; 70 | IMAGE_OPTIONAL_HEADER32 OptionalHeader; 71 | } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32, USERMODE_NT_HEADER, *PUSERMODE_NT_HEADER; 72 | 73 | typedef struct _USERMODE_IMAGE_HEADER 74 | { 75 | WORD e_magic; 76 | WORD e_cblp; 77 | WORD e_cp; 78 | WORD e_crlc; 79 | WORD e_cparhdr; 80 | WORD e_minalloc; 81 | WORD e_maxalloc; 82 | WORD e_ss; 83 | WORD e_sp; 84 | WORD e_csum; 85 | WORD e_ip; 86 | WORD e_cs; 87 | WORD e_lfarlc; 88 | WORD e_ovno; 89 | WORD e_res[4]; 90 | WORD e_oemid; 91 | WORD e_oeminfo; 92 | WORD e_res2[10]; 93 | LONG e_lfanew; 94 | } USERMODE_IMAGE_HEADER, *PUSERMODE_IMAGE_HEADER; 95 | 96 | // Structure for import address table 97 | 98 | typedef struct _IMP_AT 99 | { 100 | SIZE_T Size; 101 | PVOID Address; 102 | } IMP_AT, IMPORT_ADDRESS_TABLE; 103 | 104 | #endif 105 | -------------------------------------------------------------------------------- /Driver.c: -------------------------------------------------------------------------------- 1 | // Template - needs to be filled 2 | // Module copying needs to be implemented 3 | // jasonfish4 4 | 5 | #include 6 | #include 7 | #include 8 | #include "PeImg.h" 9 | 10 | #define MAIN_SIGOFF 0 // Signature offset in need of implementation 11 | #define NT_SIGOFF 1 // Signature offset in need of implementation 12 | #define MAIN_SIG 2 // Signature offset in need of implementation 13 | #define NT_SIG 3 // Signature offset in need of implementation 14 | 15 | DRIVER_INITIALIZE DriverEntry; 16 | PDEVICE_OBJECT pDeviceObject; 17 | UNICODE_STRING dev; 18 | 19 | DWORD_PTR signature_offset; 20 | DWORD_PTR image_base; 21 | DWORD_PTR process_id; 22 | PDWORD_PTR userthreadstart_callback; 23 | PDWORD_PTR userthreadstart_codecave; 24 | IMPORT_ADDRESS_TABLE import_address_table; 25 | 26 | BYTE userthread_hook[] = { 0xE9, 0x00, 0x00, 0x00, 0x00 }; // jmp address 27 | 28 | BYTE userthread_hook_method[] = { 29 | 0x2B, 0x05, 0x00, 0x00, 0x00, 0x00, // sub eax, [address] 30 | 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, // add eax, [address] 31 | 0x89, 0x44, 0x24, 0x04, // mov [esp+04],eax 32 | 0x89, 0x5C, 0x24, 0x08, // mov [esp+08],ebx 33 | 0xE9, 0x00, 0x00, 0x00, 0x00 // jmp address 34 | }; 35 | 36 | 37 | BOOLEAN CheckSignature64(DWORD_PTR SignatureAddress, DWORD64 Signature) 38 | { 39 | __try 40 | { 41 | ProbeForRead(SignatureAddress, sizeof(DWORD64), TYPE_ALIGNMENT(char)); 42 | if (RtlCompareMemory(SignatureAddress, &Signature, sizeof(DWORD64)) == sizeof(DWORD64)) 43 | return TRUE; 44 | else 45 | return FALSE; 46 | } 47 | __except (EXCEPTION_EXECUTE_HANDLER) 48 | { 49 | DbgPrint("Signature access failed - exception"); 50 | return FALSE; 51 | } 52 | } 53 | 54 | void SetProtection(PMDL* MdlArray, SIZE_T MdlArraySize, LONG Protection) 55 | { 56 | for (SIZE_T mdl = 0; mdl < MdlArraySize; mdl++) 57 | MmProtectMdlSystemAddress(MdlArray[mdl], Protection); 58 | } 59 | 60 | void ProbeLockPagesUser(PMDL* MdlArray, SIZE_T MdlArraySize, BOOLEAN Lock) 61 | { 62 | __try 63 | { 64 | if (Lock) 65 | { 66 | for (SIZE_T mdl = 0; mdl < MdlArraySize; mdl++) 67 | MmProbeAndLockPages(MdlArray[mdl], UserMode, IoReadAccess); 68 | } 69 | else 70 | { 71 | for (SIZE_T mdl = 0; mdl < MdlArraySize; mdl++) 72 | MmUnlockPages(MdlArray[mdl]); 73 | } 74 | } 75 | __except (EXCEPTION_EXECUTE_HANDLER) 76 | { 77 | DbgPrint("Probe failed - access violation"); 78 | return; 79 | } 80 | } 81 | VOID GetImportAddressTable(PVOID ModuleBase) 82 | { 83 | PUSERMODE_IMAGE_HEADER virtual_process_info = (PUSERMODE_IMAGE_HEADER)ModuleBase; 84 | PUSERMODE_NT_HEADER virtual_process_nt = (PUSERMODE_NT_HEADER)((BYTE*)virtual_process_info + 85 | virtual_process_info->e_lfanew); 86 | 87 | import_address_table.Size = virtual_process_nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size; 88 | import_address_table.Address = (PVOID)((DWORD32)virtual_process_info + 89 | virtual_process_nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress); 90 | } 91 | 92 | VOID ProcessLoadImageCallback(_In_opt_ PUNICODE_STRING FullImageName, IN HANDLE ProcessId, IN PIMAGE_INFO ImageInfo) 93 | { 94 | DWORD64 comparator; 95 | 96 | if (!process_id) 97 | { 98 | signature_offset = MAIN_SIGOFF; 99 | comparator = MAIN_SIG; 100 | } 101 | else 102 | { 103 | signature_offset = NT_SIGOFF; 104 | comparator = NT_SIG; 105 | } 106 | 107 | if (!CheckSignature64((PDWORD_PTR)((DWORD_PTR)ImageInfo->ImageBase + signature_offset), comparator)) 108 | { 109 | DbgPrint("Signature not found"); 110 | return; 111 | } 112 | 113 | if (!process_id) 114 | { 115 | GetImportAddressTable(ImageInfo->ImageBase); 116 | image_base = (DWORD_PTR)ImageInfo->ImageBase; 117 | process_id = (DWORD_PTR)ProcessId; 118 | return; 119 | } 120 | 121 | PMDL descriptor_array[2]; 122 | descriptor_array[0] = IoAllocateMdl(userthreadstart_callback, sizeof(userthread_hook), FALSE, FALSE, NULL); 123 | descriptor_array[1] = IoAllocateMdl(userthreadstart_codecave, sizeof(userthread_hook_method), FALSE, FALSE, NULL); 124 | 125 | __try 126 | { 127 | ProbeLockPagesUser(descriptor_array, 2, TRUE); 128 | SetProtection(descriptor_array, 2, PAGE_EXECUTE_READWRITE); 129 | 130 | DWORD_PTR jmp_codecave_callback = (userthreadstart_codecave - userthreadstart_callback) - 5; 131 | DWORD_PTR jmp_callback = (userthreadstart_callback - userthreadstart_codecave) - 5; 132 | 133 | RtlCopyMemory(&userthread_hook[1], &jmp_codecave_callback, 4); 134 | RtlCopyMemory(&userthread_hook_method[21], &jmp_callback, 4); 135 | RtlCopyMemory((PVOID)userthreadstart_callback, &userthread_hook, sizeof(userthread_hook)); 136 | RtlCopyMemory((PVOID)userthreadstart_codecave, &userthread_hook_method, sizeof(userthread_hook_method)); 137 | 138 | SetProtection(descriptor_array, 2, PAGE_EXECUTE_READ); 139 | ProbeLockPagesUser(descriptor_array, 2, FALSE); 140 | IoFreeMdl(descriptor_array[0]); 141 | IoFreeMdl(descriptor_array[1]); 142 | } 143 | __except (EXCEPTION_EXECUTE_HANDLER) 144 | { 145 | DbgPrint("Access violation occurred while probing and locking pages"); 146 | return; 147 | } 148 | } 149 | 150 | VOID WorkThread(IN PVOID pContext) 151 | { 152 | PsSetLoadImageNotifyRoutine(ProcessLoadImageCallback); 153 | // Wait State Code needs to be implemented as well as signals 154 | PsTerminateSystemThread(STATUS_SUCCESS); 155 | } 156 | 157 | NTSTATUS UnloadDriver(PDRIVER_OBJECT pDriverObject) 158 | { 159 | PsRemoveLoadImageNotifyRoutine(ProcessLoadImageCallback); 160 | IoDeleteDevice(pDriverObject->DeviceObject); 161 | return 0; 162 | } 163 | 164 | NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) 165 | { 166 | NTSTATUS status; 167 | WDF_DRIVER_CONFIG config; 168 | IoCreateDevice(DriverObject, 0, &dev, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject); 169 | 170 | HANDLE hControl; 171 | status = PsCreateSystemThread(&hControl, (ACCESS_MASK)0, NULL, NULL, NULL, WorkThread, NULL); 172 | 173 | if (!NT_SUCCESS(status)) 174 | return status; 175 | 176 | ZwClose(hControl); 177 | DriverObject->DriverUnload = UnloadDriver; 178 | return STATUS_SUCCESS; 179 | } 180 | --------------------------------------------------------------------------------