X Tutup
Skip to content

Commit c015543

Browse files
Add --runas command
1 parent 57cb780 commit c015543

File tree

2 files changed

+113
-1
lines changed

2 files changed

+113
-1
lines changed

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
CFLAGS:=-std=gnu99 -Wall -Os
3+
LDFLAGS:=-luserenv
34
GCC:=gcc
45
STRIP:=strip
56

@@ -11,5 +12,5 @@ STRIP:=${TRIPLET}-${STRIP}
1112
endif
1213

1314
all:
14-
${GCC} ${CFLAGS} ${ELEVATE_CFLAGS} -static src/elevate.c -o elevate.exe
15+
${GCC} ${CFLAGS} ${ELEVATE_CFLAGS} -static src/elevate.c -o elevate.exe ${LDFLAGS}
1516
${STRIP} elevate.exe

src/elevate.c

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
#include <stdio.h>
33
#include <windows.h>
4+
#include <userenv.h>
45

56
#ifndef SEE_MASK_NOASYNC
67
#define SEE_MASK_NOASYNC 0x00000100
@@ -24,6 +25,25 @@ static void bail(int code, char *msg) {
2425
exit(code);
2526
}
2627

28+
static void wbail(int code, char *msg) {
29+
LPVOID lpvMessageBuffer;
30+
31+
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
32+
FORMAT_MESSAGE_FROM_SYSTEM,
33+
NULL, GetLastError(),
34+
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
35+
(LPWSTR)&lpvMessageBuffer, 0, NULL);
36+
37+
wprintf(L"API = %s.\n", msg);
38+
wprintf(L"error code = %d.\n", GetLastError());
39+
wprintf(L"message = %s.\n", (LPWSTR)lpvMessageBuffer);
40+
41+
LocalFree(lpvMessageBuffer);
42+
43+
fprintf(stderr, "%s\n", msg);
44+
exit(code);
45+
}
46+
2747
static int getMajorOSVersion() {
2848
OSVERSIONINFO ovi;
2949

@@ -135,6 +155,95 @@ int msiexec(int argc, char** argv) {
135155
return exec(verb, "msiexec", parameters);
136156
}
137157

158+
void toWideChar (const char *s, wchar_t **ws) {
159+
int wchars_num = MultiByteToWideChar(CP_UTF8, 0, s, -1, NULL, 0);
160+
*ws = malloc(wchars_num * sizeof(wchar_t));
161+
MultiByteToWideChar(CP_UTF8, 0, s, -1, *ws, wchars_num);
162+
}
163+
164+
int runas(int argc, char** argv) {
165+
const int MAX_ARGUMENTS_LENGTH = 65536;
166+
char parameters[MAX_ARGUMENTS_LENGTH];
167+
char tmp[MAX_ARGUMENTS_LENGTH];
168+
169+
parameters[0] = '\0';
170+
171+
if (argc < 5) {
172+
fprintf(stderr, "Not enough arguments, expected 6, got %d\n", argc);
173+
msibail();
174+
}
175+
176+
const char* user = argv[2];
177+
const char* password = argv[3];
178+
const char* command = argv[4];
179+
180+
for (int i = 4; i < argc; i++) {
181+
SAFE_APPEND("%s\"%s\" ", argv[i]);
182+
}
183+
184+
WCHAR* wuser;
185+
WCHAR* wpassword;
186+
WCHAR* wcommand;
187+
WCHAR* wparameters;
188+
toWideChar(user, &wuser);
189+
toWideChar(password, &wpassword);
190+
toWideChar(command, &wcommand);
191+
toWideChar(parameters, &wparameters);
192+
193+
HANDLE hToken;
194+
LPVOID lpvEnv;
195+
196+
WCHAR szUserProfile[256];
197+
ZeroMemory(szUserProfile, sizeof(szUserProfile));
198+
199+
PROCESS_INFORMATION pi;
200+
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
201+
202+
STARTUPINFOW si;
203+
ZeroMemory(&si, sizeof(STARTUPINFOW));
204+
si.cb = sizeof(STARTUPINFOW);
205+
206+
if (!LogonUserW(wuser, L".", wpassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken)) {
207+
wbail(127, "LogonUser");
208+
}
209+
fprintf(stderr, "hToken = %p\n", hToken);
210+
211+
if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE)) {
212+
wbail(127, "CreateEnvironmentBlock");
213+
}
214+
215+
DWORD dwSize = sizeof(szUserProfile) / sizeof(WCHAR);
216+
217+
if (!GetUserProfileDirectoryW(hToken, szUserProfile, &dwSize)) {
218+
wbail(127, "GetUserProfileDirectory");
219+
}
220+
221+
if (!CreateProcessWithLogonW(wuser, L".", wpassword,
222+
LOGON_WITH_PROFILE, wcommand, wparameters,
223+
CREATE_UNICODE_ENVIRONMENT, lpvEnv, szUserProfile,
224+
&si, &pi)) {
225+
wbail(127, "CreateProcessWithLogonW");
226+
}
227+
228+
WaitForSingleObject(pi.hProcess, INFINITE);
229+
230+
DWORD code;
231+
if (GetExitCodeProcess(pi.hProcess, &code) == 0) {
232+
// Not sure when this could ever happen.
233+
wbail(127, "failed GetExitCodeProcess call");
234+
}
235+
236+
if (!DestroyEnvironmentBlock(lpvEnv)) {
237+
wbail(127, "failed DestroyEnvironmentBlock call");
238+
}
239+
240+
CloseHandle(hToken);
241+
CloseHandle(pi.hProcess);
242+
CloseHandle(pi.hThread);
243+
244+
return code;
245+
}
246+
138247
/**
139248
* Inspired by / with some code from the following MIT-licensed projects:
140249
* - https://github.com/atom/node-runas
@@ -156,6 +265,8 @@ int main(int argc, char** argv) {
156265

157266
if (strcmp("--msiexec", argv[1]) == 0) {
158267
return msiexec(argc, argv);
268+
} else if (strcmp("--runas", argv[1]) == 0) {
269+
return runas(argc, argv);
159270
} else {
160271
return elevate(argc, argv);
161272
}

0 commit comments

Comments
 (0)
X Tutup