1 /* 2 * PROJECT: ReactOS 'Layers' Shim library 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Shim for VMWare Horizon setup 5 * COPYRIGHT: Copyright 2017 Thomas Faber (thomas.faber@reactos.org) 6 * Copyright 2017 Mark Jansen (mark.jansen@reactos.org) 7 */ 8 9 #define WIN32_NO_STATUS 10 #include <windef.h> 11 #include <winbase.h> 12 #include <shimlib.h> 13 #include "ntndk.h" 14 15 static BOOL Write(PBYTE Address, PBYTE Data, SIZE_T Size) 16 { 17 PVOID BaseAddress = Address; 18 SIZE_T RegionSize = Size; 19 ULONG OldProtection; 20 NTSTATUS Status = NtProtectVirtualMemory(NtCurrentProcess(), &BaseAddress, &RegionSize, PAGE_EXECUTE_READWRITE, &OldProtection); 21 if (NT_SUCCESS(Status)) 22 { 23 SIZE_T Bytes; 24 Status = NtWriteVirtualMemory(NtCurrentProcess(), Address, Data, Size, &Bytes); 25 if (NT_SUCCESS(Status) && Bytes != Size) 26 Status = STATUS_MEMORY_NOT_ALLOCATED; 27 NtProtectVirtualMemory(NtCurrentProcess(), &BaseAddress, &RegionSize, OldProtection, &OldProtection); 28 } 29 return NT_SUCCESS(Status); 30 } 31 32 static void FixupDll(PLDR_DATA_TABLE_ENTRY LdrEntry) 33 { 34 static const UCHAR Match1[5] = { 0x0C, 0x8B, 0xFC, 0xF3, 0xA5 }; 35 static const UCHAR Match2[5] = { 0x0C, 0x8B, 0xFC, 0xF3, 0xA5 }; 36 static const UCHAR Match3[5] = { 0xB0, 0x8B, 0xFC, 0xF3, 0xA5 }; 37 UCHAR Replacement1[5] = { 0x10, 0x89, 0x34, 0x24, 0x90 }; 38 UCHAR Replacement2[5] = { 0x10, 0x89, 0x34, 0x24, 0x90 }; 39 UCHAR Replacement3[5] = { 0xB4, 0x89, 0x34, 0x24, 0x90 }; 40 #define OFFSET_1 0x21A6E 41 #define OFFSET_2 0x21B04 42 #define OFFSET_3 0x21C3C 43 44 45 UCHAR Buffer[5]; 46 PBYTE Base = LdrEntry->DllBase; 47 SIZE_T Bytes; 48 49 /* 50 00020E6E: 0C 8B FC F3 A5 --> 10 89 34 24 90 F11A6E - ef0000 = 21A6E 51 00020F04: 0C 8B FC F3 A5 --> 10 89 34 24 90 F11B04 - ef0000 = 21B04 52 00021C3C: B0 8B FC F3 A5 --> B4 89 34 24 90 F11C3C - ef0000 = 21C3C 53 */ 54 do { 55 DbgPrint("Module %wZ Loaded at 0x%p, we should patch!\n", &LdrEntry->BaseDllName, LdrEntry->DllBase); 56 if (!NT_SUCCESS(NtReadVirtualMemory(NtCurrentProcess(), Base + OFFSET_1, Buffer, 5, &Bytes)) || Bytes != 5) 57 break; 58 if (memcmp(Buffer, Match1, sizeof(Match1))) 59 break; 60 61 if (!NT_SUCCESS(NtReadVirtualMemory(NtCurrentProcess(), Base + OFFSET_2, Buffer, 5, &Bytes)) || Bytes != 5) 62 break; 63 if (memcmp(Buffer, Match2, sizeof(Match2))) 64 break; 65 66 if (!NT_SUCCESS(NtReadVirtualMemory(NtCurrentProcess(), Base + OFFSET_3, Buffer, 5, &Bytes)) || Bytes != 5) 67 break; 68 if (memcmp(Buffer, Match3, sizeof(Match3))) 69 break; 70 71 DbgPrint("Module %wZ Loaded at 0x%p, OK to patch!\n", &LdrEntry->BaseDllName, LdrEntry->DllBase); 72 if (!Write(Base + OFFSET_1, Replacement1, sizeof(Replacement1))) 73 break; 74 if (!Write(Base + OFFSET_2, Replacement2, sizeof(Replacement2))) 75 break; 76 if (!Write(Base + OFFSET_3, Replacement3, sizeof(Replacement3))) 77 break; 78 79 NtFlushInstructionCache(NtCurrentProcess(), Base, 0x22000); 80 81 DbgPrint("Module %wZ Loaded at 0x%p, patched!\n", &LdrEntry->BaseDllName, LdrEntry->DllBase); 82 } while (0); 83 } 84 85 static BOOLEAN PostfixUnicodeString(const UNICODE_STRING* String1, const UNICODE_STRING* String2) 86 { 87 PWCHAR pc1; 88 PWCHAR pc2; 89 ULONG NumChars; 90 91 if (String2->Length < String1->Length) 92 return FALSE; 93 94 if (!String1->Buffer || !String2->Buffer) 95 return FALSE; 96 97 NumChars = String1->Length / sizeof(WCHAR); 98 pc1 = String1->Buffer; 99 pc2 = String2->Buffer + (String2->Length / sizeof(WCHAR)) - NumChars; 100 101 while (NumChars--) 102 { 103 if (RtlUpcaseUnicodeChar(*pc1++) != RtlUpcaseUnicodeChar(*pc2++)) 104 return FALSE; 105 } 106 107 return TRUE; 108 } 109 110 #define SHIM_NS VMHorizonSetup 111 #include <setup_shim.inl> 112 113 #define SHIM_NUM_HOOKS 0 114 #define SHIM_NOTIFY_FN SHIM_OBJ_NAME(Notify) 115 116 BOOL WINAPI SHIM_OBJ_NAME(Notify)(DWORD fdwReason, PVOID ptr) 117 { 118 if (fdwReason == SHIM_REASON_DLL_LOAD) 119 { 120 static const UNICODE_STRING DllPrefix = RTL_CONSTANT_STRING(L"msi"); 121 static const UNICODE_STRING DllPostfix = RTL_CONSTANT_STRING(L".tmp"); 122 PLDR_DATA_TABLE_ENTRY LdrEntry = ptr; 123 124 BOOLEAN Prefix = RtlPrefixUnicodeString(&DllPrefix, &LdrEntry->BaseDllName, TRUE); 125 BOOLEAN Postfix = PostfixUnicodeString(&DllPostfix, &LdrEntry->BaseDllName); 126 ULONG ExtraChars = (LdrEntry->BaseDllName.Length - DllPrefix.Length - DllPostfix.Length) / sizeof(WCHAR); 127 128 /* msiN[N].tmp */ 129 if (Prefix && Postfix && ExtraChars <= 2) 130 { 131 PIMAGE_NT_HEADERS ImageNtHeader = RtlImageNtHeader(LdrEntry->DllBase); 132 if (ImageNtHeader && ImageNtHeader->OptionalHeader.CheckSum == 0x176241) 133 { 134 SHIM_MSG("Module %wZ is a match, applying fixups\n", &LdrEntry->BaseDllName); 135 FixupDll(LdrEntry); 136 } 137 } 138 } 139 return TRUE; 140 } 141 142 #include <implement_shim.inl> 143