aboutsummaryrefslogtreecommitdiff
path: root/Application/EfiDSEFix/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Application/EfiDSEFix/src/main.cpp')
-rw-r--r--Application/EfiDSEFix/src/main.cpp245
1 files changed, 245 insertions, 0 deletions
diff --git a/Application/EfiDSEFix/src/main.cpp b/Application/EfiDSEFix/src/main.cpp
new file mode 100644
index 0000000..1c7e8da
--- /dev/null
+++ b/Application/EfiDSEFix/src/main.cpp
@@ -0,0 +1,245 @@
+#include "EfiDSEFix.h"
+#include <ntstatus.h>
+
+static
+VOID
+PrintUsage(
+ _In_ PCWCHAR ProgramName
+ )
+{
+ Printf(L"\nUsage: %ls [COMMAND]\n\n"
+ L"Commands:\n\n"
+ L"-c, --check%17lsTest backdoor hook\n"
+ L"-d, --disable%15lsDisable DSE\n"
+ L"-e, --enable%ls%2ls(Re)enable DSE\n"
+ L"-i, --info%18lsDump system info\n",
+ ProgramName, L"", L"",
+ (NtCurrentPeb()->OSBuildNumber >= 9200 ? L" [g_CiOptions]" : L" "),
+ L"", L"");
+}
+
+int wmain(int argc, wchar_t** argv)
+{
+ NT_ASSERT(argc != 0);
+ if (argc == 1 || argc > 3 || (argc == 3 && _wtoi(argv[2]) == 0))
+ {
+ // Print help text
+ PrintUsage(argv[0]);
+ return 0;
+ }
+
+ // Parse command line params
+ ULONG CiOptionsValue = 0;
+ if (wcsncmp(argv[1], L"-c", sizeof(L"-c") / sizeof(WCHAR) - 1) == 0 ||
+ wcsncmp(argv[1], L"--check", sizeof(L"--check") / sizeof(WCHAR) - 1) == 0)
+ {
+ Printf(L"Checking for working EFI SetVariable() backdoor...\n");
+ const NTSTATUS Status = TestSetVariableHook();
+ if (NT_SUCCESS(Status)) // Any errors have already been printed
+ Printf(L"Success!\n");
+ return Status;
+ }
+ if (wcsncmp(argv[1], L"-d", sizeof(L"-d") / sizeof(WCHAR) - 1) == 0 ||
+ wcsncmp(argv[1], L"--disable", sizeof(L"--disable") / sizeof(WCHAR) - 1) == 0)
+ {
+ CiOptionsValue = 0;
+ Printf(L"Disabling DSE...\n");
+ }
+ else if (wcsncmp(argv[1], L"-e", sizeof(L"-e") / sizeof(WCHAR) - 1) == 0 ||
+ wcsncmp(argv[1], L"--enable", sizeof(L"--enable") / sizeof(WCHAR) - 1) == 0)
+ {
+ if (NtCurrentPeb()->OSBuildNumber >= 9200)
+ {
+ CiOptionsValue = argc == 3 ? static_cast<ULONG>(_wtoi(argv[2])) : CODEINTEGRITY_OPTION_ENABLED;
+ Printf(L"(Re)enabling DSE [g_CiOptions value = 0x%X]...\n", CiOptionsValue);
+ }
+ else
+ {
+ CiOptionsValue = CODEINTEGRITY_OPTION_ENABLED;
+ Printf(L"(Re)enabling DSE...\n");
+ }
+ }
+ else if (wcsncmp(argv[1], L"-i", sizeof(L"-i") / sizeof(WCHAR) - 1) == 0 ||
+ wcsncmp(argv[1], L"--info", sizeof(L"--info") / sizeof(WCHAR) - 1) == 0)
+ {
+ return DumpSystemInformation();
+ }
+
+ // Trigger EFI driver exploit and write new value to g_CiOptions/g_CiEnabled
+ ULONG OldCiOptionsValue;
+ const NTSTATUS Status = AdjustCiOptions(CiOptionsValue, &OldCiOptionsValue);
+
+ // Print result
+ if (!NT_SUCCESS(Status))
+ {
+ Printf(L"AdjustCiOptions failed: %08X\n", Status);
+ }
+ else
+ {
+ Printf(L"Successfully %ls DSE.", CiOptionsValue == 0 ? L"disabled" : L"(re)enabled");
+ if (NtCurrentPeb()->OSBuildNumber >= 9200)
+ {
+ Printf(L" Original g_CiOptions value: 0x%X", OldCiOptionsValue);
+ }
+ Printf(L"\n");
+ }
+ return Status;
+}
+
+DECLSPEC_NOINLINE
+static
+VOID
+ParseCommandLine(
+ _In_ PWCHAR CommandLine,
+ _Out_opt_ PWCHAR* Argv,
+ _Out_opt_ PWCHAR Arguments,
+ _Out_ PULONG Argc,
+ _Out_ PULONG NumChars
+ )
+{
+ *NumChars = 0;
+ *Argc = 1;
+
+ // Copy the executable name and and count bytes
+ PWCHAR p = CommandLine;
+ if (Argv != nullptr)
+ *Argv++ = Arguments;
+
+ // Handle quoted executable names
+ BOOLEAN InQuotes = FALSE;
+ WCHAR c;
+ do
+ {
+ if (*p == '"')
+ {
+ InQuotes = !InQuotes;
+ c = *p++;
+ continue;
+ }
+
+ ++*NumChars;
+ if (Arguments != nullptr)
+ *Arguments++ = *p;
+ c = *p++;
+ } while (c != '\0' && (InQuotes || (c != ' ' && c != '\t')));
+
+ if (c == '\0')
+ --p;
+ else if (Arguments != nullptr)
+ *(Arguments - 1) = L'\0';
+
+ // Iterate over the arguments
+ InQuotes = FALSE;
+ for (; ; ++*NumChars)
+ {
+ if (*p != '\0')
+ {
+ while (*p == ' ' || *p == '\t')
+ ++p;
+ }
+ if (*p == '\0')
+ break; // End of arguments
+
+ if (Argv != nullptr)
+ *Argv++ = Arguments;
+ ++*Argc;
+
+ // Scan one argument
+ for (; ; ++p)
+ {
+ BOOLEAN CopyChar = TRUE;
+ ULONG NumSlashes = 0;
+
+ while (*p == '\\')
+ {
+ // Count the number of slashes
+ ++p;
+ ++NumSlashes;
+ }
+
+ if (*p == '"')
+ {
+ // If 2N backslashes before: start/end a quote. Otherwise copy literally
+ if ((NumSlashes & 1) == 0)
+ {
+ if (InQuotes && p[1] == '"')
+ ++p; // Double quote inside a quoted string
+ else
+ {
+ // Skip first quote and copy second
+ CopyChar = FALSE; // Don't copy quote
+ InQuotes = !InQuotes;
+ }
+ }
+ NumSlashes >>= 1;
+ }
+
+ // Copy slashes
+ while (NumSlashes--)
+ {
+ if (Arguments != nullptr)
+ *Arguments++ = '\\';
+ ++*NumChars;
+ }
+
+ // If we're at the end of the argument, go to the next
+ if (*p == '\0' || (!InQuotes && (*p == ' ' || *p == '\t')))
+ break;
+
+ // Copy character into argument
+ if (CopyChar)
+ {
+ if (Arguments != nullptr)
+ *Arguments++ = *p;
+ ++*NumChars;
+ }
+ }
+
+ if (Arguments != nullptr)
+ *Arguments++ = L'\0';
+ }
+}
+
+NTSTATUS
+NTAPI
+NtProcessStartupW(
+ _In_ PPEB Peb
+ )
+{
+ // On Windows XP (heh...) rcx does not contain a PEB pointer, but garbage
+ Peb = Peb != nullptr ? NtCurrentPeb() : NtCurrentTeb()->ProcessEnvironmentBlock; // And this turd is to get Resharper to shut up about assigning to Peb before reading from it. Note LHS == RHS
+
+ // Get the command line from the startup parameters. If there isn't one, use the executable name
+ PRTL_USER_PROCESS_PARAMETERS Params = RtlNormalizeProcessParams(Peb->ProcessParameters);
+ const PWCHAR CommandLineBuffer = Params->CommandLine.Buffer == nullptr || Params->CommandLine.Buffer[0] == L'\0'
+ ? Params->ImagePathName.Buffer
+ : Params->CommandLine.Buffer;
+
+ // Count the number of arguments and characters excluding quotes
+ ULONG Argc, NumChars;
+ ParseCommandLine(CommandLineBuffer,
+ nullptr,
+ nullptr,
+ &Argc,
+ &NumChars);
+
+ // Allocate a buffer for the arguments and a pointer array
+ const ULONG ArgumentArraySize = (Argc + 1) * sizeof(PVOID);
+ PWCHAR *Argv = static_cast<PWCHAR*>(
+ RtlAllocateHeap(RtlProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ ArgumentArraySize + NumChars * sizeof(WCHAR)));
+ if (Argv == nullptr)
+ return NtTerminateProcess(NtCurrentProcess, STATUS_NO_MEMORY);
+
+ // Copy the command line arguments
+ ParseCommandLine(CommandLineBuffer,
+ Argv,
+ reinterpret_cast<PWCHAR>(&Argv[Argc + 1]),
+ &Argc,
+ &NumChars);
+
+ // Call the main function and terminate with the exit status
+ const NTSTATUS Status = wmain(Argc, Argv);
+ return NtTerminateProcess(NtCurrentProcess, Status);
+}