1+ #include < Windows.h>
2+ #include < cstdio>
3+ #include < vector>
4+
5+ static bool IsProcessElevated ()
6+ {
7+ SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
8+ PSID SecurityIdentifier;
9+ if (!AllocateAndInitializeSid (&NtAuthority, 2 , SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0 , 0 , 0 , 0 , 0 , 0 , &SecurityIdentifier))
10+ return 0 ;
11+
12+ BOOL IsAdminMember;
13+ if (!CheckTokenMembership (NULL , SecurityIdentifier, &IsAdminMember))
14+ IsAdminMember = FALSE ;
15+
16+ FreeSid (SecurityIdentifier);
17+ return !!IsAdminMember;
18+ }
19+
20+ class RedirectWow
21+ {
22+ PVOID oldValue = NULL ;
23+ BOOL (WINAPI* wow64DisableRedirection)(PVOID);
24+ BOOL (WINAPI* wow64RevertRedirection)(PVOID);
25+
26+ public:
27+ RedirectWow ()
28+ {
29+ wow64DisableRedirection = (decltype (wow64DisableRedirection))GetProcAddress (GetModuleHandleW (L" kernel32" ), " Wow64DisableWow64FsRedirection" );
30+ wow64RevertRedirection = (decltype (wow64RevertRedirection))GetProcAddress (GetModuleHandleW (L" kernel32" ), " Wow64RevertWow64FsRedirection" );
31+ if (wow64DisableRedirection)
32+ wow64DisableRedirection (&oldValue);
33+ }
34+
35+ RedirectWow (const RedirectWow&) = delete ;
36+ RedirectWow (RedirectWow&&) = delete ;
37+ RedirectWow& operator =(const RedirectWow&) = delete ;
38+
39+ ~RedirectWow ()
40+ {
41+ if (oldValue)
42+ wow64RevertRedirection (oldValue);
43+ }
44+ };
45+
46+ int wmain (int argc, wchar_t * argv[])
47+ {
48+ RedirectWow redirectWow;
49+
50+ // Helper functions for functioning printf
51+ auto printf = [](const char * fmt, auto ... args)
52+ {
53+ char msg[1024 ] = " " ;
54+ sprintf_s (msg, fmt, args...);
55+ DWORD w = 0 ;
56+ WriteFile (GetStdHandle (STD_OUTPUT_HANDLE), msg, strlen (msg), &w, nullptr );
57+ };
58+ auto puts = [&printf](const char * str)
59+ {
60+ printf (" %s\n " , str);
61+ };
62+
63+ // Get rid of application from command line
64+ auto commandLine = GetCommandLineW ();
65+ {
66+ if (*commandLine == L' \" ' )
67+ {
68+ commandLine++;
69+ while (*commandLine++ != L' \" ' );
70+ commandLine++;
71+ }
72+ else
73+ {
74+ while (*commandLine != L' ' && *commandLine != L' \0 ' )
75+ commandLine++;
76+ }
77+ while (*commandLine == L' ' )
78+ commandLine++;
79+ if (!*commandLine)
80+ commandLine = nullptr ;
81+ }
82+
83+ if (!IsProcessElevated ())
84+ {
85+ // Restart sudo elevated
86+ SHELLEXECUTEINFOW ShExecInfo = { 0 };
87+ ShExecInfo.cbSize = sizeof (SHELLEXECUTEINFOW);
88+ ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
89+ ShExecInfo.hwnd = GetConsoleWindow ();
90+ ShExecInfo.lpVerb = L" runas" ;
91+ ShExecInfo.lpFile = argv[0 ];
92+ ShExecInfo.lpParameters = commandLine;
93+ ShExecInfo.lpDirectory = NULL ;
94+ ShExecInfo.nShow = SW_HIDE;
95+ ShExecInfo.hInstApp = NULL ;
96+ if (!ShellExecuteExW (&ShExecInfo))
97+ {
98+ auto lastError = GetLastError ();
99+ if (lastError == ERROR_CANCELLED)
100+ puts (" Elevation canceled by user" );
101+ else
102+ printf (" ShellExecuteExW failed (LastError: %u)\n " , GetLastError ());
103+ return EXIT_FAILURE;
104+ }
105+ WaitForSingleObject (ShExecInfo.hProcess , INFINITE);
106+ DWORD ExitCode = 0 ;
107+ if (!GetExitCodeProcess (ShExecInfo.hProcess , &ExitCode))
108+ ExitCode = 1 ;
109+ CloseHandle (ShExecInfo.hProcess );
110+ return ExitCode;
111+ }
112+ else
113+ {
114+ // Get rid of the hidden console and attach to the parent sudo's console
115+ FreeConsole ();
116+ AttachConsole (ATTACH_PARENT_PROCESS);
117+
118+ // Construct final command line for cmd
119+ std::vector<wchar_t > finalCommandLine;
120+ auto append = [&finalCommandLine](const wchar_t * str)
121+ {
122+ auto length = wcslen (str);
123+ for (size_t i = 0 ; i < length; i++)
124+ finalCommandLine.push_back (str[i]);
125+ };
126+ if (commandLine)
127+ {
128+ append (L" cmd.exe /C " );
129+ append (commandLine);
130+ }
131+ else
132+ {
133+ append (L" cmd.exe" );
134+ }
135+ finalCommandLine.push_back (L' \0 ' );
136+
137+ // Create cmd instance
138+ STARTUPINFOW si = { sizeof (si) };
139+ PROCESS_INFORMATION pi = { 0 };
140+ if (!CreateProcessW (nullptr , finalCommandLine.data (), nullptr , nullptr , FALSE , 0 , nullptr , nullptr , &si, &pi))
141+ {
142+ printf (" CreateProcessW failed (LastError: %u)\n " , GetLastError ());
143+ return EXIT_FAILURE;
144+ }
145+ WaitForSingleObject (pi.hProcess , INFINITE);
146+ DWORD ExitCode = 0 ;
147+ if (!GetExitCodeProcess (pi.hProcess , &ExitCode))
148+ ExitCode = 1 ;
149+ CloseHandle (pi.hProcess );
150+ CloseHandle (pi.hThread );
151+ return ExitCode;
152+ }
153+ }
0 commit comments