xref: /reactos/dll/appcompat/shims/layer/vmhorizon.c (revision b36d9bd9)
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