├── .github └── workflows │ └── msbuild.yml ├── MIIEow └── MIIEow │ ├── MIIEow.inf │ ├── MIIEow.sln │ ├── MIIEow.vcxproj │ ├── MIIEow.vcxproj.filters │ ├── Source.c │ └── Undocumented.h ├── MIIEowClient └── MIIEowClient │ ├── MIIEowClient.filters │ ├── MIIEowClient.sln │ ├── MIIEowClient.user │ ├── MIIEowClient.vcxproj │ ├── MIIEowClient.vcxproj.user │ └── Source.c ├── README.md └── sppdebug.reg /.github/workflows/msbuild.yml: -------------------------------------------------------------------------------- 1 | name: Build driver 2 | on: 3 | push: 4 | branches: 5 | - trunk 6 | jobs: 7 | build: 8 | strategy: 9 | matrix: 10 | configuration: [Debug, Release] 11 | platform: [x64] 12 | runs-on: windows-2022 13 | env: 14 | Driver_Solution_Path: MIIEow\MIIEow\MIIEow.sln 15 | Client_Solution_Path: MIIEowClient\MIIEowClient\MIIEowClient.sln 16 | steps: 17 | - name: Check out repository code 18 | uses: actions/checkout@v3 19 | 20 | - name: Add MSBuild to PATH 21 | uses: microsoft/setup-msbuild@v1.0.2 22 | 23 | - name: Build solutions 24 | run: | 25 | msbuild ${{ env.Driver_Solution_Path }} -p:Configuration=${{ env.Configuration }} -p:Platform=${{ env.Platform }} 26 | msbuild ${{ env.Client_Solution_Path }} -p:Configuration=${{ env.Configuration }} -p:Platform=${{ env.Platform }} 27 | env: 28 | Configuration: ${{ matrix.configuration }} 29 | Platform: ${{ matrix.platform }} 30 | 31 | - name: Package 32 | run: | 33 | mkdir ${{ env.Configuration }}_${{ env.Platform }}/ 34 | xcopy /e /k /h /i MIIEow\MIIEow\${{ env.Platform }}\${{ env.Configuration }} ${{ env.Configuration }}_${{ env.Platform }}/ 35 | xcopy /e /k /h /i MIIEowClient\MIIEowClient\${{ env.Platform }}\${{ env.Configuration }} ${{ env.Configuration }}_${{ env.Platform }}/ 36 | env: 37 | Configuration: ${{ matrix.configuration }} 38 | Platform: ${{ matrix.platform }} 39 | 40 | - name: Upload 41 | uses: actions/upload-artifact@v4 42 | with: 43 | name: miieow_${{ github.sha }}_${{ env.Configuration }}_${{ env.Platform }} 44 | path: ${{ env.Configuration }}_${{ env.Platform }} 45 | env: 46 | Configuration: ${{ matrix.configuration }} 47 | Platform: ${{ matrix.platform }} 48 | -------------------------------------------------------------------------------- /MIIEow/MIIEow/MIIEow.inf: -------------------------------------------------------------------------------- 1 | ; 2 | ; MIIEow.inf 3 | ; 4 | 5 | [Version] 6 | Signature="$WINDOWS NT$" 7 | Class=System 8 | ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318} 9 | Provider=%ManufacturerName% 10 | DriverVer= 11 | CatalogFile=MIIEow.cat 12 | PnpLockdown=1 13 | 14 | [DestinationDirs] 15 | DefaultDestDir = 13 16 | 17 | [SourceDisksNames] 18 | 1 = %DiskName%,,,"" 19 | 20 | [SourceDisksFiles] 21 | 22 | [Manufacturer] 23 | 24 | [Standard.NT$ARCH$.10.0...16299] 25 | 26 | [Strings] 27 | ManufacturerName="" ;TODO: Replace with your manufacturer name 28 | DiskName="MIIEow Source Disk" 29 | -------------------------------------------------------------------------------- /MIIEow/MIIEow/MIIEow.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.10.35013.160 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MIIEow", "MIIEow.vcxproj", "{BBEE9FBF-2223-44A6-9937-BEA956D06E92}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM64 = Debug|ARM64 11 | Debug|x64 = Debug|x64 12 | Release|ARM64 = Release|ARM64 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {BBEE9FBF-2223-44A6-9937-BEA956D06E92}.Debug|ARM64.ActiveCfg = Debug|ARM64 17 | {BBEE9FBF-2223-44A6-9937-BEA956D06E92}.Debug|ARM64.Build.0 = Debug|ARM64 18 | {BBEE9FBF-2223-44A6-9937-BEA956D06E92}.Debug|ARM64.Deploy.0 = Debug|ARM64 19 | {BBEE9FBF-2223-44A6-9937-BEA956D06E92}.Debug|x64.ActiveCfg = Debug|x64 20 | {BBEE9FBF-2223-44A6-9937-BEA956D06E92}.Debug|x64.Build.0 = Debug|x64 21 | {BBEE9FBF-2223-44A6-9937-BEA956D06E92}.Debug|x64.Deploy.0 = Debug|x64 22 | {BBEE9FBF-2223-44A6-9937-BEA956D06E92}.Release|ARM64.ActiveCfg = Release|ARM64 23 | {BBEE9FBF-2223-44A6-9937-BEA956D06E92}.Release|ARM64.Build.0 = Release|ARM64 24 | {BBEE9FBF-2223-44A6-9937-BEA956D06E92}.Release|ARM64.Deploy.0 = Release|ARM64 25 | {BBEE9FBF-2223-44A6-9937-BEA956D06E92}.Release|x64.ActiveCfg = Release|x64 26 | {BBEE9FBF-2223-44A6-9937-BEA956D06E92}.Release|x64.Build.0 = Release|x64 27 | {BBEE9FBF-2223-44A6-9937-BEA956D06E92}.Release|x64.Deploy.0 = Release|x64 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | GlobalSection(ExtensibilityGlobals) = postSolution 33 | SolutionGuid = {67AC022C-5E9C-4E21-BB55-BFE076997E2B} 34 | EndGlobalSection 35 | EndGlobal 36 | -------------------------------------------------------------------------------- /MIIEow/MIIEow/MIIEow.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | Debug 14 | ARM64 15 | 16 | 17 | Release 18 | ARM64 19 | 20 | 21 | 22 | {BBEE9FBF-2223-44A6-9937-BEA956D06E92} 23 | {dd38f7fc-d7bd-488b-9242-7d8754cde80d} 24 | v4.5 25 | 12.0 26 | Debug 27 | x64 28 | MIIEow 29 | 30 | 31 | 32 | Windows10 33 | true 34 | WindowsKernelModeDriver10.0 35 | Driver 36 | WDM 37 | false 38 | 39 | 40 | Windows10 41 | false 42 | WindowsKernelModeDriver10.0 43 | Driver 44 | WDM 45 | false 46 | 47 | 48 | Windows10 49 | true 50 | WindowsKernelModeDriver10.0 51 | Driver 52 | WDM 53 | 54 | 55 | Windows10 56 | false 57 | WindowsKernelModeDriver10.0 58 | Driver 59 | WDM 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | DbgengKernelDebugger 71 | 72 | 73 | DbgengKernelDebugger 74 | 75 | 76 | DbgengKernelDebugger 77 | 78 | 79 | DbgengKernelDebugger 80 | 81 | 82 | 83 | sha256 84 | 85 | 86 | 87 | 88 | sha256 89 | 90 | 91 | MinSpace 92 | 93 | 94 | true 95 | 96 | 97 | UseLinkTimeCodeGeneration 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /MIIEow/MIIEow/MIIEow.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | 22 | 23 | Driver Files 24 | 25 | 26 | 27 | 28 | Source Files 29 | 30 | 31 | 32 | 33 | Header Files 34 | 35 | 36 | -------------------------------------------------------------------------------- /MIIEow/MIIEow/Source.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Undocumented.h" 5 | 6 | #define DRIVER_NAME "miieow" 7 | 8 | static UNICODE_STRING DriverName; 9 | static UNICODE_STRING DeviceName; 10 | static UNICODE_STRING SymbolicLink; 11 | 12 | NTSTATUS 13 | MwCreate(_In_ PDEVICE_OBJECT pDeviceObject, _In_ PIRP pIrp); 14 | 15 | NTSTATUS 16 | MwClose(_In_ PDEVICE_OBJECT pDeviceObject, _In_ PIRP pIrp); 17 | 18 | NTSTATUS 19 | MwCtl(_In_ PDEVICE_OBJECT pDeviceObject, _In_ PIRP pIrp); 20 | 21 | #define MwCtlReadProcessMemory CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) 22 | #define MwCtlWriteProcessMemory CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) 23 | #define MwCtlProtectProcessMemory CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) 24 | #define MwCtlGetModuleInfo CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) 25 | 26 | struct MwVmRequest 27 | { 28 | _In_ DWORD ProcessId; 29 | _In_ PVOID Src; 30 | _In_ SIZE_T Size; 31 | _Out_ PVOID Dst; 32 | }; 33 | 34 | struct MwVpRequest 35 | { 36 | _In_ DWORD ProcessId; 37 | _In_ PVOID Address; 38 | _In_ ULONG NewProt; 39 | _In_ SIZE_T Size; 40 | _Out_ ULONG* pOldProt; 41 | }; 42 | 43 | struct MwMiRequest 44 | { 45 | _In_ DWORD ProcessId; 46 | _In_ WCHAR Module[256]; 47 | _Out_ PVOID BaseAddr; 48 | _Out_ ULONG Size; 49 | }; 50 | 51 | NTSTATUS 52 | DriverEntry(_In_ PDRIVER_OBJECT pDriverObject, _In_ PUNICODE_STRING pRegistryPath) 53 | { 54 | UNREFERENCED_PARAMETER(pRegistryPath); 55 | 56 | 57 | NTSTATUS Status = STATUS_SUCCESS; 58 | 59 | RtlInitUnicodeString(&DriverName, L"\\Driver\\" DRIVER_NAME); 60 | RtlInitUnicodeString(&DeviceName, L"\\Device\\" DRIVER_NAME); 61 | RtlInitUnicodeString(&SymbolicLink, L"\\DosDevices\\" DRIVER_NAME); 62 | 63 | if (pDriverObject == NULL) 64 | { 65 | return IoCreateDriver(&DriverName, &DriverEntry); 66 | } 67 | 68 | PDEVICE_OBJECT pDeviceObject = NULL; 69 | Status = IoCreateDevice(pDriverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject); 70 | if (Status != STATUS_SUCCESS) 71 | { 72 | return Status; 73 | } 74 | 75 | Status = IoCreateSymbolicLink(&SymbolicLink, &DeviceName); 76 | if (Status != STATUS_SUCCESS) 77 | { 78 | return Status; 79 | } 80 | 81 | SetFlag(pDeviceObject->Flags, DO_BUFFERED_IO); 82 | pDriverObject->MajorFunction[IRP_MJ_CREATE] = MwCreate; 83 | pDriverObject->MajorFunction[IRP_MJ_CLOSE] = MwClose; 84 | pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MwCtl; 85 | 86 | ClearFlag(pDeviceObject->Flags, DO_DEVICE_INITIALIZING); 87 | 88 | return Status; 89 | } 90 | 91 | NTSTATUS 92 | MwCopyVirtualMemory(_In_ PEPROCESS pSourceProcess, _In_ PVOID SourceAddress, _In_ PEPROCESS pDestinationProcess, _In_ PVOID DestinationAddress, _In_ SIZE_T Size) 93 | { 94 | NTSTATUS Status; 95 | 96 | SIZE_T ReturnSize; 97 | Status = MmCopyVirtualMemory(pSourceProcess, SourceAddress, pDestinationProcess, DestinationAddress, Size, KernelMode, &ReturnSize); 98 | 99 | return Status; 100 | } 101 | 102 | NTSTATUS 103 | MwCreate(_In_ PDEVICE_OBJECT pDeviceObject, _In_ PIRP pIrp) 104 | { 105 | UNREFERENCED_PARAMETER(pDeviceObject); 106 | IoCompleteRequest(pIrp, IO_NO_INCREMENT); 107 | return pIrp->IoStatus.Status; 108 | } 109 | 110 | NTSTATUS 111 | MwClose(_In_ PDEVICE_OBJECT pDeviceObject, _In_ PIRP pIrp) 112 | { 113 | UNREFERENCED_PARAMETER(pDeviceObject); 114 | IoCompleteRequest(pIrp, IO_NO_INCREMENT); 115 | return pIrp->IoStatus.Status; 116 | } 117 | 118 | NTSTATUS 119 | MwCtl(_In_ PDEVICE_OBJECT pDeviceObject, _In_ PIRP pIrp) 120 | { 121 | UNREFERENCED_PARAMETER(pDeviceObject); 122 | UNREFERENCED_PARAMETER(pIrp); 123 | 124 | NTSTATUS Status = STATUS_SUCCESS; 125 | PEPROCESS pTargetProcess = NULL; 126 | 127 | pIrp->IoStatus.Information = 0; 128 | 129 | PIO_STACK_LOCATION pStackIrp = IoGetCurrentIrpStackLocation(pIrp); 130 | if (pStackIrp == NULL || pIrp->AssociatedIrp.SystemBuffer == NULL) 131 | { 132 | Status = STATUS_UNSUCCESSFUL; 133 | goto Cleanup; 134 | } 135 | 136 | const ULONG ControlCode = pStackIrp->Parameters.DeviceIoControl.IoControlCode; 137 | switch (ControlCode) 138 | { 139 | case MwCtlReadProcessMemory: 140 | { 141 | struct MwVmRequest *Request = (struct MwVmRequest *)pIrp->AssociatedIrp.SystemBuffer; 142 | 143 | Status = PsLookupProcessByProcessId((HANDLE)Request->ProcessId, &pTargetProcess); 144 | if (Status != STATUS_SUCCESS) 145 | { 146 | goto Cleanup; 147 | } 148 | 149 | Status = MwCopyVirtualMemory(pTargetProcess, Request->Src, PsGetCurrentProcess(), Request->Dst, Request->Size); 150 | if (Status != STATUS_SUCCESS) 151 | { 152 | goto Cleanup; 153 | } 154 | 155 | pIrp->IoStatus.Information = sizeof(struct MwVmRequest); 156 | break; 157 | } 158 | 159 | case MwCtlWriteProcessMemory: 160 | { 161 | struct MwVmRequest* Request = (struct MwVmRequest*)pIrp->AssociatedIrp.SystemBuffer; 162 | 163 | Status = PsLookupProcessByProcessId((HANDLE)Request->ProcessId, &pTargetProcess); 164 | if (Status != STATUS_SUCCESS) 165 | { 166 | goto Cleanup; 167 | } 168 | 169 | Status = MwCopyVirtualMemory(PsGetCurrentProcess(), Request->Src, pTargetProcess, Request->Dst, Request->Size); 170 | if (Status != STATUS_SUCCESS) 171 | { 172 | goto Cleanup; 173 | } 174 | 175 | pIrp->IoStatus.Information = sizeof(struct MwVmRequest); 176 | break; 177 | } 178 | 179 | case MwCtlProtectProcessMemory: 180 | { 181 | struct MwVpRequest* Request = (struct MwVpRequest*)pIrp->AssociatedIrp.SystemBuffer; 182 | 183 | Status = PsLookupProcessByProcessId((HANDLE)Request->ProcessId, &pTargetProcess); 184 | if (Status != STATUS_SUCCESS) 185 | { 186 | goto Cleanup; 187 | } 188 | 189 | // Locals used in usermode address space scope must be stack relative 190 | // due to cr3 being modified. However, the stack is still paged in and 191 | // other normal registers are preserved 192 | PVOID Address = Request->Address; 193 | SIZE_T Size = Request->Size; 194 | ULONG NewProt = Request->NewProt; 195 | ULONG OldProt; 196 | 197 | KAPC_STATE state = { 0 }; 198 | KeStackAttachProcess(pTargetProcess, &state); 199 | { 200 | Status = ZwProtectVirtualMemory(ZwCurrentProcess(), &Address, &Size, NewProt, &OldProt); 201 | } 202 | KeUnstackDetachProcess(&state); 203 | 204 | *Request->pOldProt = OldProt; 205 | pIrp->IoStatus.Information = sizeof(struct MwVpRequest); 206 | break; 207 | } 208 | 209 | case MwCtlGetModuleInfo: 210 | { 211 | struct MwMiRequest* pRequest = (struct MwMiRequest*)pIrp->AssociatedIrp.SystemBuffer; 212 | 213 | Status = PsLookupProcessByProcessId((HANDLE)pRequest->ProcessId, &pTargetProcess); 214 | if (Status != STATUS_SUCCESS) 215 | { 216 | goto Cleanup; 217 | } 218 | 219 | PEB* pPeb = PsGetProcessPeb(pTargetProcess); 220 | 221 | UNICODE_STRING TargetModule; 222 | RtlInitUnicodeString(&TargetModule, pRequest->Module); 223 | 224 | PVOID ModuleBase = NULL; 225 | ULONG ModuleSize = 0; 226 | { 227 | KAPC_STATE State; 228 | KeStackAttachProcess(pTargetProcess, &State); 229 | { 230 | for (PLIST_ENTRY entry = pPeb->Ldr->InLoadOrderModuleList.Flink; entry != &pPeb->Ldr->InLoadOrderModuleList; entry = entry->Flink) 231 | { 232 | PLDR_DATA_TABLE_ENTRY _entry = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); 233 | if (RtlCompareUnicodeString(&TargetModule, &_entry->BaseDllName, TRUE) == 0) 234 | { 235 | ModuleBase = _entry->DllBase; 236 | ModuleSize = _entry->SizeOfImage; 237 | } 238 | } 239 | } 240 | KeUnstackDetachProcess(&State); 241 | } 242 | 243 | pRequest->BaseAddr = ModuleBase; 244 | pRequest->Size = ModuleSize; 245 | 246 | pIrp->IoStatus.Information = sizeof(struct MwMiRequest); 247 | break; 248 | } 249 | 250 | default: 251 | { 252 | Status = STATUS_UNSUCCESSFUL; 253 | pIrp->IoStatus.Information = 0; 254 | break; 255 | } 256 | } 257 | 258 | Cleanup: 259 | if (pTargetProcess != NULL) ObDereferenceObject(pTargetProcess); 260 | pIrp->IoStatus.Status = Status; 261 | IoCompleteRequest(pIrp, IO_NO_INCREMENT); 262 | return Status; 263 | } 264 | -------------------------------------------------------------------------------- /MIIEow/MIIEow/Undocumented.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" 8 | { 9 | #endif 10 | 11 | NTKERNELAPI NTSTATUS IoCreateDriver(PUNICODE_STRING DriverName, 12 | PDRIVER_INITIALIZE InitializationFunction); 13 | 14 | NTKERNELAPI NTSTATUS MmCopyVirtualMemory(PEPROCESS SourceProcess, PVOID SourceAddress, 15 | PEPROCESS TargetProcess, PVOID TargetAddress, 16 | SIZE_T BufferSize, KPROCESSOR_MODE PreviousMode, 17 | PSIZE_T ReturnSize); 18 | 19 | NTSTATUS ZwProtectVirtualMemory( 20 | IN HANDLE ProcessHandle, 21 | IN OUT PVOID* BaseAddress, 22 | IN OUT SIZE_T* NumberOfBytesToProtect, 23 | IN ULONG NewAccessProtection, 24 | OUT PULONG OldAccessProtection); 25 | 26 | NTKERNELAPI PPEB NTAPI PsGetProcessPeb(IN PEPROCESS Process); 27 | 28 | typedef struct _PEB_LDR_DATA 29 | { 30 | ULONG Length; 31 | UCHAR Initialized; 32 | PVOID SsHandle; 33 | LIST_ENTRY InLoadOrderModuleList; 34 | LIST_ENTRY InMemoryOrderModuleList; 35 | LIST_ENTRY InInitializationOrderModuleList; 36 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 37 | 38 | typedef struct _PEB_LDR_DATA32 39 | { 40 | ULONG Length; 41 | UCHAR Initialized; 42 | ULONG SsHandle; 43 | LIST_ENTRY32 InLoadOrderModuleList; 44 | LIST_ENTRY32 InMemoryOrderModuleList; 45 | LIST_ENTRY32 InInitializationOrderModuleList; 46 | } PEB_LDR_DATA32, * PPEB_LDR_DATA32; 47 | 48 | typedef struct _PEB 49 | { 50 | UCHAR InheritedAddressSpace; 51 | UCHAR ReadImageFileExecOptions; 52 | UCHAR BeingDebugged; 53 | UCHAR BitField; 54 | PVOID Mutant; 55 | PVOID ImageBaseAddress; 56 | PPEB_LDR_DATA Ldr; 57 | PVOID ProcessParameters; 58 | PVOID SubSystemData; 59 | PVOID ProcessHeap; 60 | PVOID FastPebLock; 61 | PVOID AtlThunkSListPtr; 62 | PVOID IFEOKey; 63 | PVOID CrossProcessFlags; 64 | PVOID KernelCallbackTable; 65 | ULONG SystemReserved; 66 | ULONG AtlThunkSListPtr32; 67 | PVOID ApiSetMap; 68 | } PEB, * PPEB; 69 | 70 | typedef struct _PEB32 71 | { 72 | UCHAR InheritedAddressSpace; 73 | UCHAR ReadImageFileExecOptions; 74 | UCHAR BeingDebugged; 75 | UCHAR BitField; 76 | ULONG Mutant; 77 | ULONG ImageBaseAddress; 78 | ULONG Ldr; 79 | ULONG ProcessParameters; 80 | ULONG SubSystemData; 81 | ULONG ProcessHeap; 82 | ULONG FastPebLock; 83 | ULONG AtlThunkSListPtr; 84 | ULONG IFEOKey; 85 | ULONG CrossProcessFlags; 86 | ULONG UserSharedInfoPtr; 87 | ULONG SystemReserved; 88 | ULONG AtlThunkSListPtr32; 89 | ULONG ApiSetMap; 90 | } PEB32, * PPEB32; 91 | 92 | typedef struct _LDR_DATA_TABLE_ENTRY 93 | { 94 | LIST_ENTRY InLoadOrderLinks; 95 | LIST_ENTRY InMemoryOrderLinks; 96 | LIST_ENTRY InInitializationOrderLinks; 97 | PVOID DllBase; 98 | PVOID EntryPoint; 99 | ULONG SizeOfImage; 100 | UNICODE_STRING FullDllName; 101 | UNICODE_STRING BaseDllName; 102 | ULONG Flags; 103 | USHORT LoadCount; 104 | USHORT TlsIndex; 105 | LIST_ENTRY HashLinks; 106 | ULONG TimeDateStamp; 107 | } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; 108 | 109 | typedef struct _LDR_DATA_TABLE_ENTRY32 110 | { 111 | LIST_ENTRY32 InLoadOrderLinks; 112 | LIST_ENTRY32 InMemoryOrderLinks; 113 | LIST_ENTRY32 InInitializationOrderLinks; 114 | ULONG DllBase; 115 | ULONG EntryPoint; 116 | ULONG SizeOfImage; 117 | UNICODE_STRING32 FullDllName; 118 | UNICODE_STRING32 BaseDllName; 119 | ULONG Flags; 120 | USHORT LoadCount; 121 | USHORT TlsIndex; 122 | LIST_ENTRY32 HashLinks; 123 | ULONG TimeDateStamp; 124 | } LDR_DATA_TABLE_ENTRY32, * PLDR_DATA_TABLE_ENTRY32; 125 | 126 | #ifdef __cplusplus 127 | } 128 | #endif -------------------------------------------------------------------------------- /MIIEowClient/MIIEowClient/MIIEowClient.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /MIIEowClient/MIIEowClient/MIIEowClient.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.10.35013.160 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MIIEowClient", "MIIEowClient.vcxproj", "{F69369ED-3072-418D-9621-BDDEF9AC9194}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {F69369ED-3072-418D-9621-BDDEF9AC9194}.Debug|x64.ActiveCfg = Debug|x64 17 | {F69369ED-3072-418D-9621-BDDEF9AC9194}.Debug|x64.Build.0 = Debug|x64 18 | {F69369ED-3072-418D-9621-BDDEF9AC9194}.Debug|x86.ActiveCfg = Debug|Win32 19 | {F69369ED-3072-418D-9621-BDDEF9AC9194}.Debug|x86.Build.0 = Debug|Win32 20 | {F69369ED-3072-418D-9621-BDDEF9AC9194}.Release|x64.ActiveCfg = Release|x64 21 | {F69369ED-3072-418D-9621-BDDEF9AC9194}.Release|x64.Build.0 = Release|x64 22 | {F69369ED-3072-418D-9621-BDDEF9AC9194}.Release|x86.ActiveCfg = Release|Win32 23 | {F69369ED-3072-418D-9621-BDDEF9AC9194}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {6387F977-68F6-4156-8B73-29EA132E9A44} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /MIIEowClient/MIIEowClient/MIIEowClient.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /MIIEowClient/MIIEowClient/MIIEowClient.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 17.0 23 | Win32Proj 24 | {f69369ed-3072-418d-9621-bddef9ac9194} 25 | PhoneAct 26 | 10.0 27 | MIIEowClient 28 | 29 | 30 | 31 | Application 32 | true 33 | v143 34 | Unicode 35 | 36 | 37 | Application 38 | false 39 | v143 40 | true 41 | Unicode 42 | 43 | 44 | Application 45 | true 46 | v143 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v143 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | Level3 77 | true 78 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 79 | true 80 | 81 | 82 | Console 83 | true 84 | 85 | 86 | 87 | 88 | Level3 89 | true 90 | true 91 | true 92 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 93 | true 94 | 95 | 96 | Console 97 | true 98 | true 99 | true 100 | 101 | 102 | 103 | 104 | Level3 105 | true 106 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 107 | true 108 | 109 | 110 | Console 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | true 118 | true 119 | true 120 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | true 122 | MultiThreaded 123 | 124 | 125 | Console 126 | true 127 | true 128 | true 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /MIIEowClient/MIIEowClient/MIIEowClient.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /MIIEowClient/MIIEowClient/Source.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* ------------------------------- CFG ------------------------------- */ 6 | 7 | #include 8 | #pragma comment(lib, "slc.lib") 9 | 10 | #define DRIVER_NAME L"miieow" 11 | 12 | #define PROCESS_NAME L"sppsvc.exe" 13 | #define MODULE_NAME L"sppsvc.exe" 14 | 15 | #define OFFSET 0 16 | #define SIGNATURE_SZ 10 17 | #define SIGNATURE { 0x8B, 0x7D, 0x00, 0x85, 0xFF, 0x75, 0x00, 0x49, 0x8B, 0x06 } 18 | #define MASK { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 } 19 | 20 | #define PATCH { 0x31, 0xff, 0x90 } 21 | #define PATCH_SZ 3 22 | 23 | static HSLC hSLC = NULL; 24 | void Pre() 25 | { 26 | // Spin up an sppsvc.exe instance 27 | SLOpen(&hSLC); 28 | } 29 | 30 | void Post() 31 | { 32 | SLClose(hSLC); 33 | } 34 | 35 | /* ------------------------------- CFG ------------------------------- */ 36 | 37 | 38 | /* --------------------------- MIIEow API --------------------------- */ 39 | 40 | // MIIEow Interface 41 | #define MwCtlReadProcessMemory CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) 42 | #define MwCtlWriteProcessMemory CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) 43 | #define MwCtlProtectProcessMemory CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) 44 | #define MwCtlGetModuleInfo CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) 45 | 46 | struct MwVmRequest 47 | { 48 | _In_ DWORD ProcessId; 49 | _In_ PVOID Src; 50 | _In_ SIZE_T Size; 51 | _Out_ PVOID Dst; 52 | }; 53 | 54 | struct MwVpRequest 55 | { 56 | _In_ DWORD ProcessId; 57 | _In_ PVOID Address; 58 | _In_ ULONG NewProt; 59 | _In_ SIZE_T Size; 60 | _Out_ ULONG* pOldProt; 61 | }; 62 | 63 | struct MwMiRequest 64 | { 65 | _In_ DWORD ProcessId; 66 | _In_ WCHAR Module[256]; 67 | _Out_ PVOID BaseAddr; 68 | _Out_ ULONG Size; 69 | }; 70 | // MIIEow Interface 71 | 72 | struct MIIEow 73 | { 74 | HANDLE hDriver; 75 | DWORD ProcessId; 76 | }; 77 | 78 | struct MIIEow* 79 | MwcCreate(_In_ DWORD ProcessId) 80 | { 81 | struct MIIEow* pMIIEow = (struct MIIEow*)malloc(sizeof(struct MIIEow)); 82 | if (pMIIEow != NULL) 83 | { 84 | pMIIEow->ProcessId = ProcessId; 85 | pMIIEow->hDriver = CreateFileW(L"\\\\.\\" DRIVER_NAME, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 86 | return pMIIEow; 87 | } 88 | else 89 | { 90 | MessageBoxW(NULL, L"Failed to init Mwc", L"Error", MB_OK | MB_ICONERROR); 91 | ExitProcess(1); 92 | } 93 | } 94 | 95 | void 96 | MwcReadProcessMemory(struct MIIEow *pMIIEow, _In_ PVOID Address, _In_ SIZE_T Size, _Out_ PVOID pBuffer) 97 | { 98 | struct MwVmRequest r; 99 | r.ProcessId = pMIIEow->ProcessId; 100 | r.Src = Address; 101 | r.Dst = pBuffer; 102 | r.Size = Size; 103 | 104 | if (DeviceIoControl(pMIIEow->hDriver, MwCtlReadProcessMemory, (PVOID)&r, sizeof(r), (PVOID)&r, sizeof(r), NULL, NULL) == FALSE) 105 | { 106 | MessageBoxW(NULL, L"Failed to read memory", L"Error", MB_OK | MB_ICONERROR); 107 | ExitProcess(1); 108 | } 109 | } 110 | 111 | void 112 | MwcWriteProcessMemory(struct MIIEow* pMIIEow, _In_ PVOID Address, _In_ SIZE_T Size, _In_ PVOID pBuffer) 113 | { 114 | struct MwVmRequest r; 115 | r.ProcessId = pMIIEow->ProcessId; 116 | r.Src = pBuffer; 117 | r.Dst = Address; 118 | r.Size = Size; 119 | 120 | if (DeviceIoControl(pMIIEow->hDriver, MwCtlWriteProcessMemory, (PVOID)&r, sizeof(r), (PVOID)&r, sizeof(r), NULL, NULL) == FALSE) 121 | { 122 | MessageBoxW(NULL, L"Failed to write memory", L"Error", MB_OK | MB_ICONERROR); 123 | ExitProcess(1); 124 | } 125 | } 126 | 127 | void 128 | MwcProtectProcessMemory(struct MIIEow* pMIIEow, _In_ PVOID Address, _In_ SIZE_T Size, _In_ ULONG NewProt, _Out_ ULONG* pOldProt) 129 | { 130 | struct MwVpRequest r; 131 | r.ProcessId = pMIIEow->ProcessId; 132 | r.Address = Address; 133 | r.NewProt = NewProt; 134 | r.Size = Size; 135 | r.pOldProt = pOldProt; 136 | 137 | if (DeviceIoControl(pMIIEow->hDriver, MwCtlProtectProcessMemory, (PVOID)&r, sizeof(r), (PVOID)&r, sizeof(r), NULL, NULL) == FALSE) 138 | { 139 | MessageBoxW(NULL, L"Failed to virtual protect memory", L"Error", MB_OK | MB_ICONERROR); 140 | ExitProcess(1); 141 | } 142 | } 143 | 144 | struct MwMiRequest 145 | MwcGetModuleInfo(struct MIIEow* pMIIEow, LPCWSTR ModuleName) 146 | { 147 | struct MwMiRequest r; 148 | r.ProcessId = pMIIEow->ProcessId; 149 | wcscpy_s(r.Module, 256, ModuleName); 150 | 151 | if (DeviceIoControl(pMIIEow->hDriver, MwCtlGetModuleInfo, (PVOID)&r, sizeof(r), (PVOID)&r, sizeof(r), NULL, NULL) == FALSE) 152 | { 153 | MessageBoxW(NULL, L"Failed to get base address", L"Error", MB_OK | MB_ICONERROR); 154 | ExitProcess(1); 155 | } 156 | 157 | return r; 158 | } 159 | 160 | void 161 | MwcDelete(struct MIIEow* pMIIEow) 162 | { 163 | if (pMIIEow != NULL) 164 | { 165 | if (pMIIEow->hDriver != INVALID_HANDLE_VALUE) 166 | { 167 | CloseHandle(pMIIEow->hDriver); 168 | } 169 | free(pMIIEow); 170 | } 171 | } 172 | 173 | /* --------------------------- MIIEow API --------------------------- */ 174 | 175 | PVOID 176 | SignatureScan(struct MIIEow* pMIIEow, PVOID BaseAddress, SIZE_T Size) 177 | { 178 | PVOID EndAddress = (PVOID)((SIZE_T)BaseAddress + Size); 179 | 180 | const BYTE Signature[SIGNATURE_SZ] = SIGNATURE; 181 | const BYTE Mask[SIGNATURE_SZ] = MASK; 182 | 183 | for (BYTE* Address = BaseAddress; Address < ((SIZE_T)EndAddress - SIGNATURE_SZ); Address++) 184 | { 185 | // TODO: Do this by page, ioctl is expensive 186 | BYTE Buffer[SIGNATURE_SZ] = { 0 }; 187 | MwcReadProcessMemory(pMIIEow, Address, SIGNATURE_SZ, Buffer); 188 | 189 | BOOL Found = TRUE; 190 | for (int i = 0; i < SIGNATURE_SZ; i++) 191 | { 192 | if (Mask[i] == 0 && Buffer[i] != Signature[i]) 193 | { 194 | Found = FALSE; 195 | break; 196 | } 197 | } 198 | if (Found) return Address + OFFSET; 199 | } 200 | return NULL; 201 | } 202 | 203 | 204 | DWORD 205 | GetProcessIdByName(LPCWSTR processName) 206 | { 207 | PROCESSENTRY32 Entry; 208 | Entry.dwSize = sizeof(PROCESSENTRY32); 209 | HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); 210 | 211 | if (Process32First(Snapshot, &Entry) == TRUE) 212 | { 213 | while (Process32Next(Snapshot, &Entry) == TRUE) 214 | { 215 | if (_wcsicmp(Entry.szExeFile, processName) == 0) 216 | { 217 | CloseHandle(Snapshot); 218 | return Entry.th32ProcessID; 219 | } 220 | } 221 | } 222 | CloseHandle(Snapshot); 223 | return (DWORD)-1; 224 | } 225 | 226 | int main() 227 | { 228 | Pre(); 229 | 230 | LPCWSTR TargetProcessName = PROCESS_NAME; 231 | DWORD ProcessId = GetProcessIdByName(TargetProcessName); 232 | 233 | if (ProcessId == (DWORD)-1) 234 | { 235 | MessageBoxW(NULL, L"Failed to find target process", L"Error", MB_OK | MB_ICONERROR); 236 | ExitProcess(1); 237 | } 238 | printf("[+] Located target process\n"); 239 | 240 | struct MIIEow* pMIIEow = MwcCreate(ProcessId); 241 | printf("[+] MIIEow initialised\n"); 242 | 243 | struct MwMiRequest ModuleInfo = MwcGetModuleInfo(pMIIEow, MODULE_NAME); 244 | printf("[+] Got base address : %zx\n", (SIZE_T)ModuleInfo.BaseAddr); 245 | 246 | PVOID PatchAddr = SignatureScan(pMIIEow, ModuleInfo.BaseAddr, ModuleInfo.Size); 247 | printf("[+] Scan result : %zx\n", (SIZE_T)PatchAddr); 248 | 249 | BYTE SanityByte; 250 | MwcReadProcessMemory(pMIIEow, PatchAddr, 1, &SanityByte); 251 | printf("[+] Sanity byte : %zx\n", (SIZE_T)SanityByte); 252 | 253 | ULONG OldProt; 254 | MwcProtectProcessMemory(pMIIEow, PatchAddr, 4096, PAGE_EXECUTE_READWRITE, &OldProt); 255 | 256 | printf("[+] Set protection to RWX\n"); 257 | 258 | const BYTE Patch[PATCH_SZ] = PATCH; 259 | MwcWriteProcessMemory(pMIIEow, PatchAddr, PATCH_SZ, Patch); 260 | printf("[+] Patched\n"); 261 | 262 | ULONG _; 263 | MwcProtectProcessMemory(pMIIEow, PatchAddr, 4096, OldProt, &_); 264 | printf("[+] Restored protection\n"); 265 | 266 | MwcDelete(pMIIEow); 267 | 268 | Post(); 269 | 270 | return 0; 271 | } 272 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MIIEow 2 | 3 | Kernel driver to disable license signature verification in SPPSVC. Add the provided registry files to prevent SPPSVC stopping (and thus losing the patch) first. The driver is compatible with both kdmapper and normal driver installation. 4 | -------------------------------------------------------------------------------- /sppdebug.reg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/massgravel/miieow/ac09796061a70d3ccf956479f8d4b2309ea03de9/sppdebug.reg --------------------------------------------------------------------------------