[GFLAGS] Implement imagefile options 939/head
authorMark Jansen <mark.jansen@reactos.org>
Sat, 13 Oct 2018 15:11:51 +0000 (17:11 +0200)
committerMark Jansen <mark.jansen@reactos.org>
Fri, 19 Oct 2018 21:13:51 +0000 (23:13 +0200)
modules/rosapps/applications/cmdutils/gflags/CMakeLists.txt
modules/rosapps/applications/cmdutils/gflags/gflags.c
modules/rosapps/applications/cmdutils/gflags/gflags.h
modules/rosapps/applications/cmdutils/gflags/imagefile.c [new file with mode: 0644]

index ac2af7a..f97f1f5 100644 (file)
@@ -9,6 +9,7 @@
 #include "gflags.h"
 
 static BOOL UsePageHeap = FALSE;
+static BOOL UseImageFile = FALSE;
 
 const WCHAR ImageExecOptionsString[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options";
 
@@ -77,6 +78,11 @@ static BOOL ParseCmdline(int argc, LPWSTR argv[])
                 UsePageHeap = TRUE;
                 return PageHeap_ParseCmdline(i + 1, argc, argv);
             }
+            if (argv[i][1] == L'i' && argv[i][2] == UNICODE_NULL)
+            {
+                UseImageFile = TRUE;
+                return ImageFile_ParseCmdline(i + 1, argc, argv);
+            }
         }
         else
         {
@@ -85,9 +91,9 @@ static BOOL ParseCmdline(int argc, LPWSTR argv[])
         }
     }
 
-    if (!UsePageHeap)
+    if (!UsePageHeap && !UseImageFile)
     {
-        wprintf(L"Only page heap flags are supported\n");
+        wprintf(L"Only page heap / image file flags are supported\n");
         return FALSE;
     }
 
@@ -99,11 +105,21 @@ int wmain(int argc, LPWSTR argv[])
 {
     if (!ParseCmdline(argc, argv))
     {
-        wprintf(L"Usage: gflags /p [image.exe] [/enable|/disable [/full]]\n"
+        wprintf(L"Usage: gflags [/p [image.exe] [/enable|/disable [/full]]]\n"
+                L"              [/i <image.exe> [<Flags>]]\n"
                 L"    image.exe:  Image you want to deal with\n"
                 L"    /enable:    enable page heap for the image\n"
                 L"    /disable:   disable page heap for the image\n"
-                L"    /full:      activate full debug page heap\n");
+                L"    /full:      activate full debug page heap\n"
+                L"    <Flags>:    A 32 bit hex number (0x00000001) that specifies\n"
+                L"                one or more global flags to set.\n"
+                L"                Without any flags, the current settings are shown.\n"
+                L"                Specify FFFFFFFF to delete the GlobalFlags entry.\n"
+                L"                Additionally, instead of a single hex number,\n"
+                L"                specify a list of abbreviations prefixed with\n"
+                L"                a '+' to add, and '-' to remove a bit.\n"
+                L"                Valid abbreviations:\n");
+        PrintFlags(~0, DEST_IMAGE);
         return 1;
     }
 
@@ -111,5 +127,9 @@ int wmain(int argc, LPWSTR argv[])
     {
         return PageHeap_Execute();
     }
+    else if (UseImageFile)
+    {
+        return ImageFile_Execute();
+    }
     return 2;
 }
index 37674b6..d9c86a2 100644 (file)
@@ -20,11 +20,18 @@ const WCHAR ImageExecOptionsString[];
 
 /* Option specific commandline parsing */
 BOOL PageHeap_ParseCmdline(INT i, int argc, LPWSTR argv[]);
+BOOL ImageFile_ParseCmdline(INT i, int argc, LPWSTR argv[]);
 
 /* Execute parsed options */
 INT PageHeap_Execute();
+INT ImageFile_Execute();
 
 /* Common functions */
 DWORD ReadSZFlagsFromRegistry(HKEY SubKey, PWSTR Value);
 BOOL OpenImageFileExecOptions(IN REGSAM SamDesired, IN OPTIONAL PCWSTR ImageName, OUT HKEY* Key);
 
+#define DEST_REGISTRY       1
+#define DEST_KERNEL         2
+#define DEST_IMAGE          4
+
+void PrintFlags(IN DWORD GlobalFlags, IN OPTIONAL WORD Dest);
diff --git a/modules/rosapps/applications/cmdutils/gflags/imagefile.c b/modules/rosapps/applications/cmdutils/gflags/imagefile.c
new file mode 100644 (file)
index 0000000..ba51c50
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * PROJECT:     Global Flags utility
+ * LICENSE:     GPL-2.0 (https://spdx.org/licenses/GPL-2.0)
+ * PURPOSE:     Global Flags utility image file options
+ * COPYRIGHT:   Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
+ */
+
+#include "gflags.h"
+
+static PWSTR ImageFile = NULL;
+static DWORD OptionsAdd = 0;
+static DWORD OptionsRemove = 0;
+static BOOL OptionsSet = FALSE;
+
+typedef struct FlagInfo
+{
+    DWORD dwFlag;
+    const wchar_t* szAbbr;
+    WORD wDest;
+    const wchar_t* szDesc;
+} FlagInfo;
+
+#define FLG_DISABLE_DBGPRINT                0x8000000
+#define FLG_CRITSEC_EVENT_CREATION          0x10000000
+#define FLG_STOP_ON_UNHANDLED_EXCEPTION     0x20000000
+#define FLG_ENABLE_HANDLE_EXCEPTIONS        0x40000000
+#define FLG_DISABLE_PROTDLLS                0x80000000
+
+
+static const FlagInfo g_Flags[] =
+{
+    {FLG_STOP_ON_EXCEPTION, L"soe", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Stop on exception"},
+    {FLG_SHOW_LDR_SNAPS, L"sls", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Show loader snaps"},
+    {FLG_DEBUG_INITIAL_COMMAND, L"dic", (DEST_REGISTRY), L"Debug initial command"},
+    {FLG_STOP_ON_HUNG_GUI, L"shg", (DEST_KERNEL), L"Stop on hung GUI"},
+    {FLG_HEAP_ENABLE_TAIL_CHECK, L"htc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap tail checking"},
+    {FLG_HEAP_ENABLE_FREE_CHECK, L"hfc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap free checking"},
+    {FLG_HEAP_VALIDATE_PARAMETERS, L"hpc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap parameter checking"},
+    {FLG_HEAP_VALIDATE_ALL, L"hvc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap validation on call"},
+    {FLG_APPLICATION_VERIFIER, L"vrf", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable application verifier"},
+    // FLG_MONITOR_SILENT_PROCESS_EXIT
+    {FLG_POOL_ENABLE_TAGGING, L"ptg", (DEST_REGISTRY), L"Enable pool tagging"},
+    {FLG_HEAP_ENABLE_TAGGING, L"htg", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap tagging"},
+    {FLG_USER_STACK_TRACE_DB, L"ust", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Create user mode stack trace database"},
+    {FLG_KERNEL_STACK_TRACE_DB, L"kst", (DEST_REGISTRY), L"Create kernel mode stack trace database"},
+    {FLG_MAINTAIN_OBJECT_TYPELIST, L"otl", (DEST_REGISTRY), L"Maintain a list of objects for each type"},
+    {FLG_HEAP_ENABLE_TAG_BY_DLL, L"htd", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap tagging by DLL"},
+    {FLG_DISABLE_STACK_EXTENSION, L"dse", (DEST_IMAGE), L"Disable stack extension"},
+
+    {FLG_ENABLE_CSRDEBUG, L"d32", (DEST_REGISTRY), L"Enable debugging of Win32 subsystem"},
+    {FLG_ENABLE_KDEBUG_SYMBOL_LOAD, L"ksl", (DEST_REGISTRY | DEST_KERNEL), L"Enable loading of kernel debugger symbols"},
+    {FLG_DISABLE_PAGE_KERNEL_STACKS, L"dps", (DEST_REGISTRY), L"Disable paging of kernel stacks"},
+    {FLG_ENABLE_SYSTEM_CRIT_BREAKS, L"scb", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable system critical breaks"},
+    {FLG_HEAP_DISABLE_COALESCING, L"dhc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Disable heap coalesce on free"},
+    {FLG_ENABLE_CLOSE_EXCEPTIONS, L"ece", (DEST_REGISTRY | DEST_KERNEL), L"Enable close exception"},
+    {FLG_ENABLE_EXCEPTION_LOGGING, L"eel", (DEST_REGISTRY | DEST_KERNEL), L"Enable exception logging"},
+    {FLG_ENABLE_HANDLE_TYPE_TAGGING, L"eot", (DEST_REGISTRY | DEST_KERNEL), L"Enable object handle type tagging"},
+    {FLG_HEAP_PAGE_ALLOCS, L"hpa", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable page heap"},
+    {FLG_DEBUG_INITIAL_COMMAND_EX, L"dwl", (DEST_REGISTRY), L"Debug WinLogon"},
+    {FLG_DISABLE_DBGPRINT, L"ddp", (DEST_REGISTRY | DEST_KERNEL), L"Buffer DbgPrint Output"},
+    {FLG_CRITSEC_EVENT_CREATION, L"cse", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Early critical section event creation"},
+    {FLG_STOP_ON_UNHANDLED_EXCEPTION, L"sue", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Stop on unhandled user-mode exception"},
+    {FLG_ENABLE_HANDLE_EXCEPTIONS, L"bhd", (DEST_REGISTRY | DEST_KERNEL), L"Enable bad handles detection"},
+    {FLG_DISABLE_PROTDLLS, L"dpd", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Disable protected DLL verification"},
+};
+
+void PrintFlags(IN DWORD GlobalFlags, IN OPTIONAL WORD Dest)
+{
+    DWORD n;
+
+    for (n = 0; n < ARRAYSIZE(g_Flags); ++n)
+    {
+        if (!Dest || (g_Flags[n].wDest & Dest))
+        {
+            if (g_Flags[n].dwFlag & GlobalFlags)
+            {
+                wprintf(L"    %s - %s\n", g_Flags[n].szAbbr, g_Flags[n].szDesc);
+            }
+        }
+    }
+}
+
+static void ShowStatus(DWORD GlobalFlags, DWORD Ignored)
+{
+    if (GlobalFlags)
+    {
+        wprintf(L"Current Registry Settings for %s executable are: %08x\n", ImageFile, GlobalFlags);
+        PrintFlags(GlobalFlags, 0);
+    }
+    else
+    {
+        wprintf(L"No Registry Settings for %s executable\n", ImageFile);
+    }
+    if (Ignored)
+    {
+        wprintf(L"The following settings were ignored: %08x\n", Ignored);
+        PrintFlags(Ignored, 0);
+    }
+}
+
+static DWORD ValidateFlags(DWORD GlobalFlags, WORD Dest)
+{
+    DWORD n;
+    DWORD Valid = 0;
+
+    for (n = 0; n < ARRAYSIZE(g_Flags); ++n)
+    {
+        if (g_Flags[n].wDest & Dest)
+        {
+            Valid |= g_Flags[n].dwFlag;
+        }
+    }
+
+    return GlobalFlags & Valid;
+}
+
+static DWORD FindFlag(PCWSTR Name, WORD Dest)
+{
+    DWORD n;
+
+    for (n = 0; n < ARRAYSIZE(g_Flags); ++n)
+    {
+        if (g_Flags[n].wDest & Dest)
+        {
+            if (!wcsicmp(Name, g_Flags[n].szAbbr))
+            {
+                return g_Flags[n].dwFlag;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static VOID ModifyStatus(VOID)
+{
+    LONG Ret;
+    DWORD GlobalFlags, Requested, Ignored;
+    HKEY IFEOKey;
+    WCHAR Buffer[11];
+
+    if (!OpenImageFileExecOptions(KEY_WRITE | KEY_READ, ImageFile, &IFEOKey))
+    {
+        return;
+    }
+
+    if (OptionsSet)
+    {
+        Requested = OptionsAdd;
+    }
+    else
+    {
+        Requested = ReadSZFlagsFromRegistry(IFEOKey, L"GlobalFlag");
+        Requested &= ~OptionsRemove;
+        Requested |= OptionsAdd;
+    }
+
+    GlobalFlags = ValidateFlags(Requested, DEST_IMAGE);
+    Ignored = GlobalFlags ^ Requested;
+
+    if (GlobalFlags)
+    {
+        wsprintf(Buffer, L"0x%08x", GlobalFlags);
+        Ret = RegSetValueExW(IFEOKey, L"GlobalFlag", 0, REG_SZ, (BYTE*)Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR));
+        if (Ret != ERROR_SUCCESS)
+        {
+            wprintf(L"MS: RegSetValueEx failed (%d)\n", Ret);
+        }
+        else
+        {
+            ShowStatus(GlobalFlags, Ignored);
+        }
+    }
+    else
+    {
+        Ret = RegDeleteValueW(IFEOKey, L"GlobalFlag");
+        if (Ret != ERROR_SUCCESS)
+        {
+            wprintf(L"MS: RegDeleteValue failed (%d)\n", Ret);
+        }
+        else
+        {
+            ShowStatus(GlobalFlags, Ignored);
+        }
+    }
+    CloseHandle(IFEOKey);
+}
+
+
+static VOID DisplayStatus(VOID)
+{
+    HKEY IFEOKey;
+    DWORD GlobalFlags;
+
+    if (!OpenImageFileExecOptions(KEY_READ, ImageFile, &IFEOKey))
+    {
+        return;
+    }
+
+    GlobalFlags = ReadSZFlagsFromRegistry(IFEOKey, L"GlobalFlag");
+    ShowStatus(GlobalFlags, 0);
+
+    CloseHandle(IFEOKey);
+}
+
+
+BOOL ImageFile_ParseCmdline(INT i, int argc, LPWSTR argv[])
+{
+    for (; i < argc; i++)
+    {
+        if (ImageFile == NULL)
+        {
+            ImageFile = argv[i];
+        }
+        else if (argv[i][0] == '+')
+        {
+            if (OptionsSet)
+            {
+                wprintf(L"Unexpected argument - '%s'\n", argv[i]);
+                return FALSE;
+            }
+            OptionsAdd |= FindFlag(argv[i] + 1, DEST_IMAGE);
+        }
+        else if (argv[i][0] == '-')
+        {
+            if (OptionsSet)
+            {
+                wprintf(L"Unexpected argument - '%s'\n", argv[i]);
+                return FALSE;
+            }
+            OptionsRemove |= FindFlag(argv[i] + 1, DEST_IMAGE);
+        }
+        else
+        {
+            OptionsSet = TRUE;
+            OptionsAdd = wcstoul(argv[i], NULL, 16);
+            if (OptionsAdd == ~0)
+                OptionsAdd = 0;
+        }
+    }
+
+    if (ImageFile == NULL)
+    {
+        wprintf(L"No Image specified\n");
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+INT ImageFile_Execute()
+{
+    if (!OptionsAdd && !OptionsRemove && !OptionsSet)
+    {
+        DisplayStatus();
+    }
+    else
+    {
+        ModifyStatus();
+    }
+
+    return 0;
+}