[ACLAYERS] Add a compatibility shim + layer for the VMWare Horizon setup.
[reactos.git] / reactos / dll / appcompat / shims / layer / vmhorizon.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Shim library
4 * FILE: dll/appcompat/shims/layer/vmhorizon.c
5 * PURPOSE: Shim for VMWare Horizon setup
6 * PROGRAMMER: Thomas Faber (thomas.faber@reactos.org)
7 * Mark Jansen (mark.jansen@reactos.org)
8 */
9
10 #define WIN32_NO_STATUS
11 #include <windows.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>