1 /*
2  * PROJECT:     Global Flags utility
3  * LICENSE:     GPL-2.0 (https://spdx.org/licenses/GPL-2.0)
4  * PURPOSE:     Global Flags utility image file options
5  * COPYRIGHT:   Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #include "gflags.h"
9 
10 static PWSTR ImageFile = NULL;
11 static DWORD OptionsAdd = 0;
12 static DWORD OptionsRemove = 0;
13 static BOOL OptionsSet = FALSE;
14 
15 typedef struct FlagInfo
16 {
17     DWORD dwFlag;
18     const wchar_t* szAbbr;
19     WORD wDest;
20     const wchar_t* szDesc;
21 } FlagInfo;
22 
23 #define FLG_DISABLE_DBGPRINT                0x8000000
24 #define FLG_CRITSEC_EVENT_CREATION          0x10000000
25 #define FLG_STOP_ON_UNHANDLED_EXCEPTION     0x20000000
26 #define FLG_ENABLE_HANDLE_EXCEPTIONS        0x40000000
27 #define FLG_DISABLE_PROTDLLS                0x80000000
28 
29 
30 static const FlagInfo g_Flags[] =
31 {
32     {FLG_STOP_ON_EXCEPTION, L"soe", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Stop on exception"},
33     {FLG_SHOW_LDR_SNAPS, L"sls", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Show loader snaps"},
34     {FLG_DEBUG_INITIAL_COMMAND, L"dic", (DEST_REGISTRY), L"Debug initial command"},
35     {FLG_STOP_ON_HUNG_GUI, L"shg", (DEST_KERNEL), L"Stop on hung GUI"},
36     {FLG_HEAP_ENABLE_TAIL_CHECK, L"htc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap tail checking"},
37     {FLG_HEAP_ENABLE_FREE_CHECK, L"hfc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap free checking"},
38     {FLG_HEAP_VALIDATE_PARAMETERS, L"hpc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap parameter checking"},
39     {FLG_HEAP_VALIDATE_ALL, L"hvc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap validation on call"},
40     {FLG_APPLICATION_VERIFIER, L"vrf", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable application verifier"},
41     // FLG_MONITOR_SILENT_PROCESS_EXIT
42     {FLG_POOL_ENABLE_TAGGING, L"ptg", (DEST_REGISTRY), L"Enable pool tagging"},
43     {FLG_HEAP_ENABLE_TAGGING, L"htg", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap tagging"},
44     {FLG_USER_STACK_TRACE_DB, L"ust", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Create user mode stack trace database"},
45     {FLG_KERNEL_STACK_TRACE_DB, L"kst", (DEST_REGISTRY), L"Create kernel mode stack trace database"},
46     {FLG_MAINTAIN_OBJECT_TYPELIST, L"otl", (DEST_REGISTRY), L"Maintain a list of objects for each type"},
47     {FLG_HEAP_ENABLE_TAG_BY_DLL, L"htd", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap tagging by DLL"},
48     {FLG_DISABLE_STACK_EXTENSION, L"dse", (DEST_IMAGE), L"Disable stack extension"},
49 
50     {FLG_ENABLE_CSRDEBUG, L"d32", (DEST_REGISTRY), L"Enable debugging of Win32 subsystem"},
51     {FLG_ENABLE_KDEBUG_SYMBOL_LOAD, L"ksl", (DEST_REGISTRY | DEST_KERNEL), L"Enable loading of kernel debugger symbols"},
52     {FLG_DISABLE_PAGE_KERNEL_STACKS, L"dps", (DEST_REGISTRY), L"Disable paging of kernel stacks"},
53     {FLG_ENABLE_SYSTEM_CRIT_BREAKS, L"scb", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable system critical breaks"},
54     {FLG_HEAP_DISABLE_COALESCING, L"dhc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Disable heap coalesce on free"},
55     {FLG_ENABLE_CLOSE_EXCEPTIONS, L"ece", (DEST_REGISTRY | DEST_KERNEL), L"Enable close exception"},
56     {FLG_ENABLE_EXCEPTION_LOGGING, L"eel", (DEST_REGISTRY | DEST_KERNEL), L"Enable exception logging"},
57     {FLG_ENABLE_HANDLE_TYPE_TAGGING, L"eot", (DEST_REGISTRY | DEST_KERNEL), L"Enable object handle type tagging"},
58     {FLG_HEAP_PAGE_ALLOCS, L"hpa", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable page heap"},
59     {FLG_DEBUG_INITIAL_COMMAND_EX, L"dwl", (DEST_REGISTRY), L"Debug WinLogon"},
60     {FLG_DISABLE_DBGPRINT, L"ddp", (DEST_REGISTRY | DEST_KERNEL), L"Buffer DbgPrint Output"},
61     {FLG_CRITSEC_EVENT_CREATION, L"cse", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Early critical section event creation"},
62     {FLG_STOP_ON_UNHANDLED_EXCEPTION, L"sue", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Stop on unhandled user-mode exception"},
63     {FLG_ENABLE_HANDLE_EXCEPTIONS, L"bhd", (DEST_REGISTRY | DEST_KERNEL), L"Enable bad handles detection"},
64     {FLG_DISABLE_PROTDLLS, L"dpd", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Disable protected DLL verification"},
65 };
66 
67 void PrintFlags(IN DWORD GlobalFlags, IN OPTIONAL WORD Dest)
68 {
69     DWORD n;
70 
71     for (n = 0; n < ARRAYSIZE(g_Flags); ++n)
72     {
73         if (!Dest || (g_Flags[n].wDest & Dest))
74         {
75             if (g_Flags[n].dwFlag & GlobalFlags)
76             {
77                 wprintf(L"    %s - %s\n", g_Flags[n].szAbbr, g_Flags[n].szDesc);
78             }
79         }
80     }
81 }
82 
83 static void ShowStatus(DWORD GlobalFlags, DWORD Ignored)
84 {
85     if (GlobalFlags)
86     {
87         wprintf(L"Current Registry Settings for %s executable are: %08x\n", ImageFile, GlobalFlags);
88         PrintFlags(GlobalFlags, 0);
89     }
90     else
91     {
92         wprintf(L"No Registry Settings for %s executable\n", ImageFile);
93     }
94     if (Ignored)
95     {
96         wprintf(L"The following settings were ignored: %08x\n", Ignored);
97         PrintFlags(Ignored, 0);
98     }
99 }
100 
101 static DWORD ValidateFlags(DWORD GlobalFlags, WORD Dest)
102 {
103     DWORD n;
104     DWORD Valid = 0;
105 
106     for (n = 0; n < ARRAYSIZE(g_Flags); ++n)
107     {
108         if (g_Flags[n].wDest & Dest)
109         {
110             Valid |= g_Flags[n].dwFlag;
111         }
112     }
113 
114     return GlobalFlags & Valid;
115 }
116 
117 static DWORD FindFlag(PCWSTR Name, WORD Dest)
118 {
119     DWORD n;
120 
121     for (n = 0; n < ARRAYSIZE(g_Flags); ++n)
122     {
123         if (g_Flags[n].wDest & Dest)
124         {
125             if (!wcsicmp(Name, g_Flags[n].szAbbr))
126             {
127                 return g_Flags[n].dwFlag;
128             }
129         }
130     }
131 
132     return 0;
133 }
134 
135 static VOID ModifyStatus(VOID)
136 {
137     LONG Ret;
138     DWORD GlobalFlags, Requested, Ignored;
139     HKEY IFEOKey;
140     WCHAR Buffer[11];
141 
142     if (!OpenImageFileExecOptions(KEY_WRITE | KEY_READ, ImageFile, &IFEOKey))
143     {
144         return;
145     }
146 
147     if (OptionsSet)
148     {
149         Requested = OptionsAdd;
150     }
151     else
152     {
153         Requested = ReadSZFlagsFromRegistry(IFEOKey, L"GlobalFlag");
154         Requested &= ~OptionsRemove;
155         Requested |= OptionsAdd;
156     }
157 
158     GlobalFlags = ValidateFlags(Requested, DEST_IMAGE);
159     Ignored = GlobalFlags ^ Requested;
160 
161     if (GlobalFlags)
162     {
163         wsprintf(Buffer, L"0x%08x", GlobalFlags);
164         Ret = RegSetValueExW(IFEOKey, L"GlobalFlag", 0, REG_SZ, (BYTE*)Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR));
165         if (Ret != ERROR_SUCCESS)
166         {
167             wprintf(L"MS: RegSetValueEx failed (%d)\n", Ret);
168         }
169         else
170         {
171             ShowStatus(GlobalFlags, Ignored);
172         }
173     }
174     else
175     {
176         Ret = RegDeleteValueW(IFEOKey, L"GlobalFlag");
177         if (Ret != ERROR_SUCCESS)
178         {
179             wprintf(L"MS: RegDeleteValue failed (%d)\n", Ret);
180         }
181         else
182         {
183             ShowStatus(GlobalFlags, Ignored);
184         }
185     }
186     CloseHandle(IFEOKey);
187 }
188 
189 
190 static VOID DisplayStatus(VOID)
191 {
192     HKEY IFEOKey;
193     DWORD GlobalFlags;
194 
195     if (!OpenImageFileExecOptions(KEY_READ, ImageFile, &IFEOKey))
196     {
197         return;
198     }
199 
200     GlobalFlags = ReadSZFlagsFromRegistry(IFEOKey, L"GlobalFlag");
201     ShowStatus(GlobalFlags, 0);
202 
203     CloseHandle(IFEOKey);
204 }
205 
206 
207 BOOL ImageFile_ParseCmdline(INT i, int argc, LPWSTR argv[])
208 {
209     for (; i < argc; i++)
210     {
211         if (ImageFile == NULL)
212         {
213             ImageFile = argv[i];
214         }
215         else if (argv[i][0] == '+')
216         {
217             if (OptionsSet)
218             {
219                 wprintf(L"Unexpected argument - '%s'\n", argv[i]);
220                 return FALSE;
221             }
222             OptionsAdd |= FindFlag(argv[i] + 1, DEST_IMAGE);
223         }
224         else if (argv[i][0] == '-')
225         {
226             if (OptionsSet)
227             {
228                 wprintf(L"Unexpected argument - '%s'\n", argv[i]);
229                 return FALSE;
230             }
231             OptionsRemove |= FindFlag(argv[i] + 1, DEST_IMAGE);
232         }
233         else
234         {
235             OptionsSet = TRUE;
236             OptionsAdd = wcstoul(argv[i], NULL, 16);
237             if (OptionsAdd == ~0)
238                 OptionsAdd = 0;
239         }
240     }
241 
242     if (ImageFile == NULL)
243     {
244         wprintf(L"No Image specified\n");
245         return FALSE;
246     }
247 
248     return TRUE;
249 }
250 
251 INT ImageFile_Execute()
252 {
253     if (!OptionsAdd && !OptionsRemove && !OptionsSet)
254     {
255         DisplayStatus();
256     }
257     else
258     {
259         ModifyStatus();
260     }
261 
262     return 0;
263 }
264