Last active
July 7, 2026 06:39
-
-
Save Davis-3450/5c795bf5a0a3d990617b2a9cbc6ea57b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| uint64_t sub_140001000() | |
| { | |
| int16_t* rsi = nullptr; | |
| int32_t rsi_1; | |
| while (true) | |
| { | |
| PWSTR _String_1 = data_140005140; | |
| if (!_String_1) | |
| { | |
| int32_t rbx_1 = 0; | |
| _String_1 = GetCommandLineW(); | |
| while (true) | |
| { | |
| uint32_t rax_2 = *_String_1; | |
| if (rax_2 == 0x22) | |
| { | |
| int32_t rax_3; | |
| rax_3 = !rbx_1; | |
| rbx_1 = rax_3; | |
| } | |
| else | |
| { | |
| if (!rax_2) | |
| break; | |
| bool cond:0_1 = rbx_1; | |
| rbx_1 = 1; | |
| if (!cond:0_1) | |
| { | |
| if (rax_2 == 9) | |
| break; | |
| rbx_1 = 0; | |
| if (rax_2 == 0x20) | |
| break; | |
| } | |
| } | |
| _String_1 = &_String_1[1]; | |
| } | |
| data_140005140 = _String_1; | |
| } | |
| if (rsi) | |
| { | |
| sub_140001c0d(rsi); | |
| _String_1 = data_140005140; | |
| } | |
| uint32_t rax_4; | |
| while (true) | |
| { | |
| rax_4 = *_String_1; | |
| if (rax_4 != 9 && rax_4 != 0x20) | |
| break; | |
| _String_1 = &_String_1[1]; | |
| data_140005140 = _String_1; | |
| } | |
| if (!rax_4) | |
| { | |
| _String_1 = nullptr; | |
| label_140001196: | |
| int32_t rax_11 = data_140005148; | |
| if ((rax_11 & 0xa) == 2) | |
| { | |
| sub_140001e09(u"/s option requires /w", 0, 0); | |
| rsi_1 = -0xf4241; | |
| if (!(*data_140005148 & 8)) | |
| rsi_1 = 1; | |
| break; | |
| } | |
| PWSTR _String = u"cmd.exe"; | |
| if (_String_1) | |
| _String = _String_1; | |
| if (rax_11 & 4) | |
| sub_140001d07(u"Your command line is '%ls'", _String); | |
| uint64_t _Size = (wcslen(_String) << 1) + 2; | |
| rsi_1 = 0; | |
| PWSTR lpCommandLine = sub_140001bdc(HEAP_NONE, _Size); | |
| memcpy(lpCommandLine, _String, _Size); | |
| int32_t rax_13 = sub_140001704(); | |
| int32_t rbx_4; | |
| if (!rax_13) | |
| { | |
| if (*data_140005148 & 2) | |
| rax_13 = sub_140001799(); | |
| if (*data_140005148 & 2 && rax_13) | |
| rbx_4 = rax_13; | |
| else | |
| { | |
| HANDLE var_e0 = nullptr; | |
| HANDLE var_f0 = nullptr; | |
| int32_t rax_15 = sub_1400019a9(&var_e0); | |
| rbx_4 = rax_15; | |
| if (!rax_15) | |
| { | |
| char rax_16 = data_140005148; | |
| int128_t var_b8; | |
| if (!(rax_16 & 2)) | |
| { | |
| label_140001375: | |
| __builtin_memset(&var_b8, 0, 0x70); | |
| var_b8 = 0x70; | |
| int64_t rdx_11 = 7; | |
| if (!(rax_16 & 1)) | |
| rdx_11 = 1; | |
| int128_t var_88; | |
| *(&var_88 + 0xc) = 1; | |
| int128_t var_78; | |
| var_78 = rdx_11; | |
| int32_t rbx_5 = 0; | |
| int128_t var_d8; | |
| int128_t var_58; | |
| if (!(rax_16 & 2)) | |
| { | |
| var_d8 = 0; | |
| InitializeProcThreadAttributeList(nullptr, 1, 0, &var_d8); | |
| LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = | |
| sub_140001bdc(HEAP_ZERO_MEMORY, var_d8); | |
| *(&var_58 + 8) = lpAttributeList; | |
| InitializeProcThreadAttributeList(lpAttributeList, 1, 0, &var_d8); | |
| rdx_11 = UpdateProcThreadAttribute(lpAttributeList, 0, 0x20000, | |
| &var_e0, 8, {0}); | |
| rax_16 = data_140005148; | |
| rbx_5 = 0x80014; | |
| if (rax_16 & 2) | |
| rbx_5 = 0; | |
| } | |
| __builtin_memset(&var_d8, 0, 0x14); | |
| if (rax_16 & 4) | |
| sub_140001d07(u"Creating specified process", rdx_11); | |
| int128_t var_120; | |
| *(&var_120 + 8) = rbx_5; | |
| enum WIN32_ERROR rbx_6 = NO_ERROR; | |
| BOOL rax_20 = CreateProcessAsUserW(var_f0, nullptr, lpCommandLine, | |
| nullptr, nullptr, 0, {0}, &var_b8, &var_d8); | |
| if (!rax_20) | |
| rbx_6 = GetLastError(); | |
| if (*data_140005148 & 2) | |
| CloseHandle(var_f0); | |
| else | |
| { | |
| DeleteProcThreadAttributeList(*(&var_58 + 8)); | |
| sub_140001c0d(*(&var_58 + 8)); | |
| } | |
| int64_t rdx_13 = CloseHandle(var_e0); | |
| if (!rax_20) | |
| { | |
| sub_140001e09(u"Process creation failed", rbx_6, 0); | |
| rbx_4 = 4; | |
| } | |
| else | |
| { | |
| char rax_22 = data_140005148; | |
| HANDLE var_e8; | |
| if (!(rax_22 & 2)) | |
| { | |
| var_e8 = nullptr; | |
| OpenProcessToken(var_d8, 0x28, &var_e8); | |
| sub_140001644(var_e8, data_140005148 >> 2 & 1); | |
| CloseHandle(var_e8); | |
| rdx_13 = ResumeThread(*(&var_d8 + 8)); | |
| rax_22 = data_140005148; | |
| } | |
| if (rax_22 & 4) | |
| { | |
| int32_t var_c8; | |
| rdx_13 = sub_140001d07(u"Created process ID: %lu", var_c8); | |
| rax_22 = data_140005148; | |
| } | |
| if (rax_22 & 8) | |
| { | |
| if (rax_22 & 4) | |
| sub_140001d07(u"Waiting for process to exit", rdx_13); | |
| WaitForSingleObject(var_d8, 0xffffffff); | |
| BOOL rax_23 = GetExitCodeProcess(var_d8, &var_e8); | |
| char rcx_29 = data_140005148; | |
| uint64_t rdx_19; | |
| if (!rax_23) | |
| { | |
| rdx_19 = 0xfff0bdba; | |
| if (!(rcx_29 & 8)) | |
| rdx_19 = 6; | |
| var_e8 = rdx_19; | |
| } | |
| else | |
| rdx_19 = var_e8; | |
| if (rcx_29 & 4) | |
| { | |
| sub_140001d07(u"Process exited with code %ld", rdx_19); | |
| rdx_19 = var_e8; | |
| } | |
| data_14000514c = rdx_19; | |
| } | |
| CloseHandle(var_d8); | |
| CloseHandle(*(&var_d8 + 8)); | |
| rbx_4 = 0; | |
| } | |
| } | |
| else | |
| { | |
| int32_t rax_17 = sub_140001b38(var_e0, &var_f0); | |
| if (!rax_17) | |
| { | |
| uint32_t rax_19 = WTSGetActiveConsoleSessionId(); | |
| var_b8 = rax_19; | |
| if (rax_19 != 0xffffffff) | |
| SetTokenInformation(var_f0, TokenSessionId, &var_b8, 4); | |
| sub_140001644(var_f0, data_140005148 >> 2 & 1); | |
| rax_16 = data_140005148; | |
| goto label_140001375; | |
| } | |
| rbx_4 = rax_17; | |
| CloseHandle(var_e0); | |
| } | |
| } | |
| } | |
| } | |
| else | |
| rbx_4 = rax_13; | |
| sub_140001c0d(lpCommandLine); | |
| if (rbx_4 != 0xffffffff) | |
| rsi_1 = rbx_4; | |
| if (!(*data_140005148 & 8)) | |
| break; | |
| if (rsi_1) | |
| { | |
| rsi_1 = 0xfff0bdc0 - rsi_1; | |
| break; | |
| } | |
| } | |
| else | |
| { | |
| uint64_t rdx_1 = 2; | |
| while (rax_4 > 0x20 || !TEST_BITQ(0x100000201, rax_4)) | |
| { | |
| data_140005140 = _String_1 + rdx_1; | |
| rax_4 = *(_String_1 + rdx_1); | |
| rdx_1 += 2; | |
| } | |
| int16_t* rax_7 = sub_140001bdc(HEAP_ZERO_MEMORY, rdx_1); | |
| rsi = rax_7; | |
| memcpy(rax_7, _String_1, rdx_1 - 2); | |
| if ((*rsi | 2) != 0x2f || !rsi[1]) | |
| { | |
| sub_140001c0d(rsi); | |
| goto label_140001196; | |
| } | |
| int32_t rax_10 = data_140005148; | |
| int16_t* rcx_3 = rsi; | |
| uint64_t r9_1; | |
| while (true) | |
| { | |
| rcx_3 = &rcx_3[1]; | |
| r9_1 = *rcx_3; | |
| int32_t rdx_3; | |
| if (r9_1 <= 0x72) | |
| { | |
| rdx_3 = 1; | |
| if (r9_1 != 0x6d) | |
| break; | |
| } | |
| else if (r9_1 == 0x73) | |
| rdx_3 = 2; | |
| else if (r9_1 == 0x76) | |
| rdx_3 = 4; | |
| else | |
| { | |
| if (r9_1 != 0x77) | |
| goto label_14000125d; | |
| rdx_3 = 8; | |
| } | |
| rax_10 |= rdx_3; | |
| data_140005148 = rax_10; | |
| } | |
| if (!r9_1) | |
| continue; | |
| else | |
| { | |
| int32_t rbx_3; | |
| if (r9_1 != 0x68) | |
| { | |
| label_14000125d: | |
| _String_1 = nullptr; | |
| sub_140001e8c(0, 0, u"Invalid option '%lc'", r9_1); | |
| rbx_3 = 1; | |
| } | |
| else | |
| { | |
| sub_140001c2f(u"\nsuperUser [options] [command_to_run]\n\nOptions (you can use " | |
| "either "-" or "/"):\n /h Display this help message.\n /m "); | |
| rbx_3 = -1; | |
| _String_1 = 1; | |
| } | |
| sub_140001c0d(rsi); | |
| rsi_1 = 0; | |
| if (!_String_1) | |
| rsi_1 = rbx_3; | |
| if (!(*data_140005148 & 8)) | |
| break; | |
| if (!_String_1) | |
| { | |
| rsi_1 = 0xfff0bdc0 - rbx_3; | |
| break; | |
| } | |
| } | |
| } | |
| rsi_1 = data_14000514c; | |
| break; | |
| } | |
| return rsi_1; | |
| } | |
| int64_t sub_140001644(HANDLE arg1, int32_t arg2) | |
| { | |
| int32_t result; | |
| for (int64_t i = 0; i != 0x120; i += 8) | |
| { | |
| result = sub_14000169e(arg1, *(i + &data_140005000)); | |
| if (arg2 && !result) | |
| result = sub_140001d07( | |
| u"Could not set privilege [%ls], you most likely don't have it.", | |
| *(i + &data_140005000)); | |
| } | |
| return result; | |
| } | |
| uint64_t sub_14000169e(HANDLE arg1, PWSTR arg2) | |
| { | |
| int32_t rdi = 0; | |
| LUID luid; | |
| if (LookupPrivilegeValueW(nullptr, arg2, &luid)) | |
| { | |
| TOKEN_PRIVILEGES NewState; | |
| NewState.PrivilegeCount = 1; | |
| int64_t rax_1; | |
| rax_1 = luid.LowPart; | |
| *(&rax_1 + 4) = luid.HighPart; | |
| NewState.Privileges[0].Luid.LowPart = rax_1; | |
| NewState.Privileges[0].Luid.HighPart = *(&rax_1 + 4); | |
| NewState.Privileges[0].Attributes = 2; | |
| AdjustTokenPrivileges(arg1, 0, &NewState, 0, {0}); | |
| rdi = !GetLastError(); | |
| } | |
| return rdi; | |
| } | |
| int64_t sub_140001704() | |
| { | |
| HANDLE var_18 = nullptr; | |
| enum WIN32_ERROR rsi_1; | |
| int32_t rdi_1; | |
| if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &var_18)) | |
| { | |
| rdi_1 = 1; | |
| rsi_1 = GetLastError(); | |
| } | |
| else | |
| { | |
| if (sub_14000169e(var_18, &(*0x140003712)[0x12])) /* u"Failed to acquire SeDebugPrivilege" | |
| */ | |
| { | |
| CloseHandle(var_18); | |
| return 0; | |
| } | |
| rsi_1 = GetLastError(); | |
| CloseHandle(var_18); | |
| rdi_1 = 2; | |
| } | |
| sub_140001e09(u"Failed to acquire SeDebugPrivilege", rsi_1, rdi_1); | |
| return 2; | |
| } | |
| uint64_t sub_140001799() | |
| { | |
| struct WTS_PROCESS_INFOW* var_28 = nullptr; | |
| uint32_t count = 0; | |
| int32_t rdi_1; | |
| HANDLE var_40; | |
| if (!WTSEnumerateProcessesW(nullptr, 0, 1, &var_28, &count)) | |
| { | |
| GetLastError(); | |
| var_40 = nullptr; | |
| sub_140001e09(u"Failed to create system context", 0xa0001000, 1); | |
| rdi_1 = 5; | |
| } | |
| else | |
| { | |
| uint32_t ProcessId = -1; | |
| if (count) | |
| { | |
| void** rbx_2 = &var_28->pUserSid; | |
| uint32_t i; | |
| do | |
| { | |
| if (!ADJ(rbx_2)->SessionId) | |
| { | |
| WCHAR* pProcessName = ADJ(rbx_2)->pProcessName; | |
| if (pProcessName && !_wcsicmp(u"services.exe", pProcessName)) | |
| { | |
| PSID pUserSid = ADJ(rbx_2)->pUserSid; | |
| if (pUserSid && IsWellKnownSid(pUserSid, WinLocalSystemSid)) | |
| { | |
| ProcessId = ADJ(rbx_2)->ProcessId; | |
| break; | |
| } | |
| } | |
| } | |
| rbx_2 = &rbx_2[3]; | |
| i = count; | |
| count -= 1; | |
| } while (i != 1); | |
| } | |
| WTSFreeMemory(var_28); | |
| var_40 = nullptr; | |
| if (ProcessId == 0xffffffff) | |
| { | |
| sub_140001e09(u"Failed to create system context", 0xa0001000, 1); | |
| rdi_1 = 5; | |
| } | |
| else | |
| { | |
| HANDLE rax_3 = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, ProcessId); | |
| if (!rax_3) | |
| { | |
| sub_140001e09(u"Failed to create system context", GetLastError(), 2); | |
| rdi_1 = 5; | |
| } | |
| else | |
| { | |
| HANDLE var_30 = nullptr; | |
| int32_t rsi; | |
| enum WIN32_ERROR rdi; | |
| if (!OpenProcessToken(rax_3, TOKEN_DUPLICATE, &var_30)) | |
| { | |
| rsi = 3; | |
| rdi = GetLastError(); | |
| } | |
| else | |
| { | |
| uint32_t* var_58; | |
| var_58 = 2; | |
| rdi = NO_ERROR; | |
| if (!DuplicateTokenEx(var_30, 0x24, nullptr, SecurityImpersonation, var_58, | |
| &var_40)) | |
| { | |
| rdi = GetLastError(); | |
| var_40 = nullptr; | |
| } | |
| CloseHandle(var_30); | |
| rsi = 4; | |
| } | |
| CloseHandle(rax_3); | |
| HANDLE rcx_6 = var_40; | |
| if (!rcx_6) | |
| { | |
| sub_140001e09(u"Failed to create system context", rdi, rsi); | |
| rdi_1 = 5; | |
| } | |
| else if (!sub_14000169e(rcx_6, u"SeAssignPrimaryTokenPrivilege")) | |
| { | |
| rsi += 1; | |
| label_14000197a: | |
| rdi = GetLastError(); | |
| CloseHandle(var_40); | |
| sub_140001e09(u"Failed to create system context", rdi, rsi); | |
| rdi_1 = 5; | |
| } | |
| else | |
| { | |
| rdi_1 = 0; | |
| if (!SetThreadToken(nullptr, var_40)) | |
| { | |
| rsi += 2; | |
| goto label_14000197a; | |
| } | |
| CloseHandle(var_40); | |
| } | |
| } | |
| } | |
| } | |
| return rdi_1; | |
| } | |
| uint64_t sub_1400019a9(int64_t* arg1) | |
| { | |
| int128_t buffer; | |
| __builtin_memset(&buffer, 0, 0x24); | |
| SetLastError(NO_ERROR); | |
| int32_t rbp = 1; | |
| SC_HANDLE rax = OpenSCManagerW(nullptr, nullptr, 1); | |
| SC_HANDLE rax_1 = OpenServiceW(rax, u"TrustedInstaller", 0x14); | |
| if (!rax_1) | |
| goto label_140001a94; | |
| uint32_t pcbBytesNeeded; | |
| enum WIN32_ERROR r14; | |
| char r15; | |
| if (!QueryServiceStatusEx(rax_1, SC_STATUS_PROCESS_INFO, &buffer, 0x24, &pcbBytesNeeded)) | |
| { | |
| label_140001a8f: | |
| rbp = 2; | |
| label_140001a94: | |
| enum WIN32_ERROR rax_6 = GetLastError(); | |
| r14 = 0xa0001001; | |
| if (rax_6) | |
| r14 = rax_6; | |
| r15 = 0; | |
| } | |
| else | |
| { | |
| rbp = 1; | |
| while (true) | |
| { | |
| int32_t rax_3 = *(&buffer + 4); | |
| if (!(rbp & 1) || rax_3 != 1) | |
| { | |
| rbp = 2; | |
| if (rax_3 == 1) | |
| goto label_140001a94; | |
| r14 = NO_ERROR; | |
| r15 = 1; | |
| break; | |
| } | |
| if (!StartServiceW(rax_1, 0, nullptr)) | |
| goto label_140001a8f; | |
| rbp = 0; | |
| if (!QueryServiceStatusEx(rax_1, SC_STATUS_PROCESS_INFO, &buffer, 0x24, | |
| &pcbBytesNeeded)) | |
| goto label_140001a8f; | |
| continue; | |
| } | |
| } | |
| CloseServiceHandle(rax); | |
| CloseServiceHandle(rax_1); | |
| *arg1 = 0; | |
| int32_t rdi_1; | |
| if (!r15) | |
| { | |
| sub_140001e09(u"Failed to open TrustedInstaller process", r14, rbp); | |
| rdi_1 = 3; | |
| } | |
| else | |
| { | |
| rdi_1 = 0; | |
| int128_t var_58; | |
| HANDLE rax_7 = OpenProcess(0x480, 0, *(&var_58 + 0xc)); | |
| *arg1 = rax_7; | |
| if (!rax_7) | |
| { | |
| enum WIN32_ERROR rax_8 = GetLastError(); | |
| if (!*arg1) | |
| { | |
| sub_140001e09(u"Failed to open TrustedInstaller process", rax_8, rbp + 1); | |
| rdi_1 = 3; | |
| } | |
| } | |
| } | |
| return rdi_1; | |
| } | |
| int64_t sub_140001b38(HANDLE arg1, int64_t* arg2) | |
| { | |
| HANDLE* phNewToken = arg2; | |
| enum WIN32_ERROR rdi = NO_ERROR; | |
| *arg2 = 0; | |
| HANDLE var_20 = nullptr; | |
| int32_t rbx; | |
| if (!OpenProcessToken(arg1, TOKEN_DUPLICATE, &var_20)) | |
| { | |
| rbx = 1; | |
| rdi = GetLastError(); | |
| } | |
| else | |
| { | |
| if (!DuplicateTokenEx(var_20, 0x1a9, nullptr, SecurityIdentification, TokenPrimary, | |
| phNewToken)) | |
| { | |
| rdi = GetLastError(); | |
| *phNewToken = nullptr; | |
| } | |
| CloseHandle(var_20); | |
| rbx = 2; | |
| } | |
| if (*phNewToken) | |
| return 0; | |
| sub_140001e09(u"Failed to create child process token", rdi, rbx); | |
| return 5; | |
| } | |
| int64_t sub_140001bdc(enum HEAP_FLAGS arg1, uint64_t arg2) | |
| { | |
| int64_t result = HeapAlloc(GetProcessHeap(), arg1, arg2); | |
| if (result) | |
| return result; | |
| abort(); | |
| /* no return */ | |
| } | |
| int64_t sub_140001c0d(int64_t arg1) | |
| { | |
| /* tailcall */ | |
| return HeapFree(GetProcessHeap(), HEAP_NONE, arg1); | |
| } | |
| int64_t sub_140001c2f(wchar16* arg1) | |
| { | |
| int128_t zmm6; | |
| /* tailcall */ | |
| return sub_140001c51(sub_140001ed4(1), arg1, zmm6); | |
| } | |
| uint64_t sub_140001c51(FILE* arg1, wchar16* arg2, int128_t arg3 @ zmm6) | |
| { | |
| uint32_t rax = GetConsoleOutputCP(); | |
| uint32_t rdi = 0; | |
| int32_t cbMultiByte = WideCharToMultiByte(rax, 0, arg2, 0xffffffff, nullptr, 0, {0}, arg3); | |
| if (cbMultiByte > 0) | |
| { | |
| rdi = 0; | |
| PSTR rax_1 = sub_140001bdc(HEAP_NONE, cbMultiByte); | |
| if (WideCharToMultiByte(rax, 0, arg2, 0xffffffff, rax_1, cbMultiByte, {0}) > 0) | |
| rdi = ~fputs(rax_1, arg1) >> 0x1f; | |
| sub_140001c0d(rax_1); | |
| } | |
| return rdi; | |
| } | |
| wchar16* sub_140001d07(wchar16* arg1, int64_t arg2) | |
| { | |
| int64_t arg_10 = arg2; | |
| int64_t r8; | |
| int64_t arg_18 = r8; | |
| int64_t r9; | |
| int64_t arg_20 = r9; | |
| int64_t* var_10 = &arg_10; | |
| wchar16* result = sub_140001d5c(arg1, &arg_10); | |
| if (!result) | |
| return result; | |
| sub_140001dc1(sub_140001ed4(1), u"[D] %ls\n", result); | |
| return sub_140001c0d(result); | |
| } | |
| wchar16* sub_140001d5c(wchar16* arg1, va_list arg2) | |
| { | |
| int32_t rax = _vscwprintf(arg1, arg2); | |
| if (rax >= 0) | |
| { | |
| uint64_t r14_1 = rax; | |
| wchar16* _Buffer = sub_140001bdc(HEAP_NONE, (r14_1 << 1) + 2); | |
| if (_vsnwprintf_s(_Buffer, r14_1 + 1, -1, arg1, arg2) >= 0) | |
| return _Buffer; | |
| sub_140001c0d(_Buffer); | |
| } | |
| return nullptr; | |
| } | |
| wchar16* sub_140001dc1(FILE* arg1, wchar16* arg2, int64_t arg3) | |
| { | |
| int64_t arg_18 = arg3; | |
| int64_t r9; | |
| int64_t arg_20 = r9; | |
| int64_t* var_18 = &arg_18; | |
| wchar16* result = sub_140001d5c(arg2, &arg_18); | |
| if (!result) | |
| return result; | |
| int128_t zmm6; | |
| sub_140001c51(arg1, result, zmm6); | |
| return sub_140001c0d(result); | |
| } | |
| wchar16* sub_140001e09(int64_t arg1, int32_t arg2, int32_t arg3) | |
| { | |
| wchar16 var_78; | |
| __builtin_memcpy(&var_78, u"[E] %ls (code: 0x%08lX, pos: %d)\n", 0x40); | |
| int32_t var_38 = 0xa; | |
| void var_6a; | |
| if (!arg2) | |
| var_6a = 0xa; | |
| else if (!arg3) | |
| { | |
| int16_t var_4c_1 = 0x29; | |
| void var_4a; | |
| var_4a = 0xa; | |
| } | |
| int32_t var_88 = arg3; | |
| return sub_140001dc1(sub_140001ed4(2), &var_78, arg1); | |
| } | |
| wchar16* sub_140001e8c(int32_t arg1, int32_t arg2, wchar16* arg3, int64_t arg4) | |
| { | |
| int64_t arg_20 = arg4; | |
| int64_t* var_20 = &arg_20; | |
| wchar16* result = sub_140001d5c(arg3, &arg_20); | |
| if (!result) | |
| return result; | |
| sub_140001e09(result, arg1, arg2); | |
| return sub_140001c0d(result); | |
| } | |
| void* sub_140001ed4(int32_t arg1) | |
| { | |
| return &__iob_func()[arg1 * 6]; | |
| } | |
| int64_t sub_140001ef4() | |
| { | |
| int32_t r9 = data_140005184; | |
| data_14000516c = data_140005188; | |
| int32_t result = | |
| __wgetmainargs(&data_140005150, &data_140005160, &data_140005158, r9, &data_14000516c); | |
| data_140005168 = result; | |
| return result; | |
| } | |
| int32_t sub_140001f40() | |
| { | |
| TEB* gsbase; | |
| void* StackBase = gsbase->NtTib.Self->NtTib.StackBase; | |
| int32_t r12 = 0; | |
| while (true) | |
| { | |
| int64_t rax_1 = 0; | |
| bool z_1; | |
| if (0 == data_140005190) | |
| { | |
| data_140005190 = StackBase; | |
| z_1 = true; | |
| } | |
| else | |
| { | |
| rax_1 = data_140005190; | |
| z_1 = false; | |
| } | |
| if (z_1) | |
| break; | |
| if (rax_1 == StackBase) | |
| { | |
| r12 = 1; | |
| break; | |
| } | |
| Sleep(0x3e8); | |
| } | |
| if (data_140005198 != 1) | |
| { | |
| int32_t rax_3 = data_140005198; | |
| if (rax_3) | |
| data_140005174 = 1; | |
| else | |
| { | |
| data_140005198 = 1; | |
| int64_t* i = &data_140003d10; | |
| void* const var_10_1 = &data_140003d10; | |
| int32_t var_18_1 = rax_3; | |
| while (i < &data_140003d28) | |
| { | |
| if (rax_3) | |
| break; | |
| int64_t rcx_1 = *i; | |
| if (rcx_1) | |
| { | |
| rax_3 = rcx_1(); | |
| int32_t var_18_2 = rax_3; | |
| } | |
| i = &i[1]; | |
| int64_t* i_1 = i; | |
| } | |
| if (rax_3) | |
| return 0xff; | |
| } | |
| } | |
| else | |
| _amsg_exit(0x1f); | |
| if (data_140005198 == 1) | |
| { | |
| _initterm(&data_140003cf8, &data_140003d08); | |
| data_140005198 = 2; | |
| } | |
| if (!r12) | |
| { | |
| data_140005190; | |
| data_140005190 = 0; | |
| } | |
| if (data_140005178 && sub_1400022a8(&data_140005178)) | |
| data_140005178(0, 2, 0); | |
| data_140005158; | |
| data_140005160; | |
| data_140005150; | |
| int32_t _Except = sub_140001000(); | |
| data_140005170 = _Except; | |
| if (!data_140005154) | |
| { | |
| exit(_Except); | |
| /* no return */ | |
| } | |
| if (data_140005174) | |
| return _Except; | |
| _cexit(); | |
| return data_140005170; | |
| } | |
| void sub_1400020ab(int32_t arg1 @ rax, int64_t arg2, int64_t arg3, int64_t arg4, int64_t arg5) | |
| { | |
| data_140005170 = arg1; | |
| if (!data_140005154) | |
| { | |
| _exit(arg1); | |
| /* no return */ | |
| } | |
| if (!data_140005174) | |
| { | |
| _cexit(); | |
| data_140005170; | |
| } | |
| } | |
| int64_t sub_1400020f0() | |
| { | |
| int32_t rax; | |
| rax = false; | |
| data_140005154 = rax; | |
| __set_app_type(sub_140002348(1)); | |
| int32_t rax_2 = data_1400051b0; | |
| data_1400051a8 = -1; | |
| data_1400051a0 = -1; | |
| *_fmode = rax_2; | |
| *_commode = data_14000519c; | |
| if (!data_140005128) | |
| __setusermatherr(sub_1400022ec); | |
| return 0; | |
| } | |
| int64_t _start() | |
| { | |
| sub_140002390(); | |
| /* tailcall */ | |
| return sub_140001f40(); | |
| } | |
| int64_t sub_1400021d4(int64_t* arg1) | |
| { | |
| int32_t* rax = *arg1; | |
| if (*rax == 0xe06d7363 && rax[6] == 4) | |
| { | |
| int32_t rax_1 = rax[8]; | |
| if (rax_1 == 0x19930520 || rax_1 == 0x19930521 || rax_1 == 0x19930522 || rax_1 == 0x1994000) | |
| { | |
| terminate(); | |
| /* no return */ | |
| } | |
| } | |
| return 0; | |
| } | |
| int64_t sub_140002218() | |
| { | |
| SetUnhandledExceptionFilter(sub_1400021d4); | |
| return 0; | |
| } | |
| int64_t _ValidateImageBase(int16_t* arg1) | |
| { | |
| if (*arg1 != 0x5a4d) | |
| return 0; | |
| int32_t* rcx_1 = *(arg1 + 0x3c) + arg1; | |
| int64_t result = 0; | |
| if (*rcx_1 == 0x4550) | |
| result = rcx_1[6] == 0x20b; | |
| return result; | |
| } | |
| void* sub_140002260(void* arg1, int64_t arg2) | |
| { | |
| int32_t r9 = 0; | |
| void* r8 = *(arg1 + 0x3c) + arg1; | |
| uint32_t r11 = *(r8 + 6); | |
| void* result = *(r8 + 0x14) + r8 + 0x18; | |
| if (r11) | |
| { | |
| do | |
| { | |
| uint64_t rdx = *(result + 0xc); | |
| if (arg2 >= rdx && arg2 < *(result + 8) + rdx) | |
| return result; | |
| r9 += 1; | |
| result += 0x28; | |
| } while (r9 < r11); | |
| } | |
| return 0; | |
| } | |
| void* sub_1400022a8(int64_t arg1) | |
| { | |
| void* result = _ValidateImageBase(&__dos_header); | |
| if (result) | |
| { | |
| result = sub_140002260(&__dos_header, arg1 - &__dos_header); | |
| if (result) | |
| return ~(*(result + 0x24) >> 0x1f) & 1; | |
| } | |
| return result; | |
| } | |
| int64_t sub_1400022ec() __pure | |
| { | |
| return 0; | |
| } | |
| int32_t* sub_1400022f0(int16_t* arg1) | |
| { | |
| int32_t* result = nullptr; | |
| if (arg1 && arg1 != -1 && *arg1 == 0x5a4d && *(arg1 + 0x3c) >= 0 && *(arg1 + 0x3c) < 0x10000000) | |
| { | |
| int32_t* result_1 = *(arg1 + 0x3c) + arg1; | |
| int32_t* result_2 = result_1; | |
| if (*result_1 != 0x4550) | |
| result_1 = nullptr; | |
| result = result_1; | |
| int32_t* result_3 = result_1; | |
| } | |
| return result; | |
| } | |
| uint64_t sub_140002348(int32_t arg1) | |
| { | |
| HMODULE rax = GetModuleHandleW(nullptr); | |
| if (rax) | |
| { | |
| int32_t* rax_1 = sub_1400022f0(rax); | |
| if (rax_1) | |
| { | |
| if (rax_1[0x17] == 2) | |
| return 2; | |
| if (rax_1[0x17] == 3) | |
| return 1; | |
| } | |
| } | |
| return arg1; | |
| } | |
| int64_t sub_140002390() | |
| { | |
| int64_t rax = data_140005130; | |
| FILETIME systemTimeAsFileTime; | |
| __builtin_memset(&systemTimeAsFileTime, 0, 8); | |
| int64_t result; | |
| if (rax == 0x2b992ddfa232) | |
| { | |
| GetSystemTimeAsFileTime(&systemTimeAsFileTime); | |
| int64_t rbx; | |
| rbx = systemTimeAsFileTime.dwLowDateTime; | |
| *(&rbx + 4) = systemTimeAsFileTime.dwHighDateTime; | |
| int64_t rbx_3 = rbx ^ GetCurrentProcessId() ^ GetCurrentThreadId() ^ GetTickCount(); | |
| int64_t performanceCount; | |
| QueryPerformanceCounter(&performanceCount); | |
| int64_t r11_6 = (performanceCount ^ rbx_3) & 0xffffffffffff; | |
| result = 0x2b992ddfa233; | |
| if (r11_6 == 0x2b992ddfa232) | |
| r11_6 = 0x2b992ddfa233; | |
| data_140005130 = r11_6; | |
| data_140005138 = ~r11_6; | |
| } | |
| else | |
| { | |
| result = ~rax; | |
| data_140005138 = result; | |
| } | |
| return result; | |
| } | |
| int64_t sub_140002443(int64_t* arg1) | |
| { | |
| return _XcptFilter(**arg1, arg1); | |
| } | |
| uint64_t sub_14000245f(int64_t* arg1) | |
| { | |
| int32_t rcx; | |
| rcx = **arg1 == 0xc0000005; | |
| return rcx; | |
| } | |
| int64_t memcpy(void* _Dst, void const* _Src, uint64_t _Size) | |
| { | |
| /* tailcall */ | |
| return memcpy(_Dst, _Src, _Size); | |
| } | |
| uint64_t wcslen(wchar16 const* _String) | |
| { | |
| /* tailcall */ | |
| return wcslen(_String); | |
| } | |
| BOOL WTSEnumerateProcessesW(HANDLE hServer, uint32_t Reserved, uint32_t Version, struct WTS_PROCESS_INFOW** ppProcessInfo, uint32_t* pCount) | |
| { | |
| /* tailcall */ | |
| return WTSEnumerateProcessesW(hServer, Reserved, Version, ppProcessInfo, pCount); | |
| } | |
| int32_t _wcsicmp(wchar16 const* _String1, wchar16 const* _String2) | |
| { | |
| /* tailcall */ | |
| return _wcsicmp(_String1, _String2); | |
| } | |
| void WTSFreeMemory(void* pMemory) | |
| { | |
| /* tailcall */ | |
| return WTSFreeMemory(pMemory); | |
| } | |
| void abort() __noreturn | |
| { | |
| /* tailcall */ | |
| return abort(); | |
| } | |
| int32_t fputs(char const* _Buffer, FILE* _Stream) | |
| { | |
| /* tailcall */ | |
| return fputs(_Buffer, _Stream); | |
| } | |
| int32_t _vscwprintf(wchar16 const* const _Format, va_list _ArgList) | |
| { | |
| /* tailcall */ | |
| return _vscwprintf(_Format, _ArgList); | |
| } | |
| int32_t _vsnwprintf_s(wchar16* const _Buffer, uint64_t const _BufferCount, uint64_t const _MaxCount, wchar16 const* const _Format, va_list _ArgList) | |
| { | |
| /* tailcall */ | |
| return _vsnwprintf_s(_Buffer, _BufferCount, _MaxCount, _Format, _ArgList); | |
| } | |
| EXCEPTION_DISPOSITION __C_specific_handler(struct _EXCEPTION_RECORD* ExceptionRecord, void* EstablisherFrame, struct _CONTEXT* ContextRecord, struct _DISPATCHER_CONTEXT* DispatcherContext) | |
| { | |
| /* tailcall */ | |
| return __C_specific_handler(ExceptionRecord, EstablisherFrame, ContextRecord, | |
| DispatcherContext); | |
| } | |
| int32_t _XcptFilter(uint32_t xcptnum, EXCEPTION_POINTERS* pxcptinfoptrs) | |
| { | |
| /* tailcall */ | |
| return _XcptFilter(xcptnum, pxcptinfoptrs); | |
| } | |
| void _initterm(_PVFV* _First, _PVFV* _Last) | |
| { | |
| /* tailcall */ | |
| return _initterm(_First, _Last); | |
| } | |
| void _amsg_exit(int32_t rterrnum) | |
| { | |
| /* tailcall */ | |
| return _amsg_exit(rterrnum); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Reconstructed from decompiled binary: superUser.exe | |
| // This tool runs a command with elevated privileges, either as SYSTEM | |
| // (by duplicating token from services.exe) or as TrustedInstaller. | |
| #include <windows.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <wchar.h> | |
| #include <wtsapi32.h> | |
| #include <sddl.h> | |
| // --------------------------------------------------------------------------- | |
| // Global state (originally at fixed addresses in .data) | |
| // --------------------------------------------------------------------------- | |
| static wchar_t* g_CmdLinePos; // data_140005140 – current position in command line | |
| static DWORD g_Flags; // data_140005148 – bitmask of options | |
| static DWORD g_ExitCode; // data_14000514c – exit code of spawned process | |
| static BOOL g_IsConsoleApp = TRUE; // data_140005154 (set in CRT init) | |
| #define FLAG_M (1 << 0) // 0x01 – '/m' (use system token / TrustedInstaller) | |
| #define FLAG_S (1 << 1) // 0x02 – '/s' (requires /w) | |
| #define FLAG_V (1 << 2) // 0x04 – '/v' (verbose) | |
| #define FLAG_W (1 << 3) // 0x08 – '/w' (wait for process) | |
| // --------------------------------------------------------------------------- | |
| // Helper functions – signatures derived from decompiled code | |
| // --------------------------------------------------------------------------- | |
| static void* HeapAllocZero(DWORD flags, SIZE_T size); // sub_140001bdc | |
| static void HeapFreeMem(void* mem); // sub_140001c0d | |
| static void PrintToConsole(FILE* stream, wchar_t* fmt, ...); // sub_140001dc1 etc. | |
| static void LogError(wchar_t* msg, DWORD code, int pos); // sub_140001e09 | |
| static BOOL SetPrivilege(HANDLE token, wchar_t* privName); // sub_14000169e | |
| static DWORD AcquireDebugPrivilege(void); // sub_140001704 | |
| static DWORD GetSystemToken(HANDLE* phToken); // sub_140001799 | |
| static DWORD OpenTrustedInstallerToken(HANDLE* phToken); // sub_1400019a9 | |
| static DWORD DuplicateTokenForChild(HANDLE hSource, HANDLE* phToken); // sub_140001b38 | |
| static void AdjustAllPrivileges(HANDLE token, BOOL report); // sub_140001644 | |
| // List of privileges to enable (hardcoded array at data_140005000) | |
| static const wchar_t* g_Privileges[] = { | |
| SE_DEBUG_NAME, | |
| SE_IMPERSONATE_NAME, | |
| SE_TCB_NAME, | |
| SE_ASSIGNPRIMARYTOKEN_NAME, | |
| SE_INCREASE_QUOTA_NAME, | |
| // ... total 0x120/8 = 36 entries | |
| }; | |
| // --------------------------------------------------------------------------- | |
| // Main entry point (originally sub_140001000) | |
| // --------------------------------------------------------------------------- | |
| int __cdecl wmain(int argc, wchar_t* argv[]) | |
| { | |
| // Initial command line parsing (skip executable name) | |
| if (g_CmdLinePos == NULL) | |
| { | |
| wchar_t* cmdLine = GetCommandLineW(); | |
| BOOL inQuotes = FALSE; | |
| // Skip executable path – handle quotes and spaces | |
| while (*cmdLine) | |
| { | |
| if (*cmdLine == L'"') | |
| inQuotes = !inQuotes; | |
| else if (!inQuotes && (*cmdLine == L' ' || *cmdLine == L'\t')) | |
| break; | |
| cmdLine++; | |
| } | |
| g_CmdLinePos = cmdLine; | |
| } | |
| wchar_t* arg = NULL; | |
| while (TRUE) | |
| { | |
| // Free previous argument buffer | |
| if (arg != NULL) | |
| { | |
| HeapFreeMem(arg); | |
| arg = NULL; | |
| } | |
| // Skip leading whitespace | |
| while (*g_CmdLinePos == L' ' || *g_CmdLinePos == L'\t') | |
| g_CmdLinePos++; | |
| if (*g_CmdLinePos == L'\0') | |
| { | |
| // No more arguments – proceed to execution phase | |
| goto execute_command; | |
| } | |
| // Extract next argument (up to whitespace or quote) | |
| wchar_t* start = g_CmdLinePos; | |
| size_t len = 0; | |
| BOOL inQuote = FALSE; | |
| while (start[len] != L'\0') | |
| { | |
| if (start[len] == L'"') | |
| inQuote = !inQuote; | |
| else if (!inQuote && (start[len] == L' ' || start[len] == L'\t')) | |
| break; | |
| len++; | |
| } | |
| // Allocate and copy the argument | |
| arg = (wchar_t*)HeapAllocZero(HEAP_ZERO_MEMORY, (len + 1) * sizeof(wchar_t)); | |
| memcpy(arg, start, len * sizeof(wchar_t)); | |
| arg[len] = L'\0'; | |
| g_CmdLinePos = start + len + (start[len] != L'\0' ? 1 : 0); | |
| // Check if it's an option (starts with '/' or '-') | |
| if ((arg[0] == L'/' || arg[0] == L'-') && arg[1] != L'\0') | |
| { | |
| // Parse option characters | |
| for (wchar_t* p = &arg[1]; *p; p++) | |
| { | |
| switch (*p) | |
| { | |
| case L'm': g_Flags |= FLAG_M; break; | |
| case L's': g_Flags |= FLAG_S; break; | |
| case L'v': g_Flags |= FLAG_V; break; | |
| case L'w': g_Flags |= FLAG_W; break; | |
| case L'h': | |
| // Print help and exit with 0 if /w not required | |
| PrintToConsole(stdout, | |
| L"\nsuperUser [options] [command_to_run]\n\n" | |
| L"Options (you can use either \"-\" or \"/\"):\n" | |
| L" /h Display this help message.\n" | |
| L" /m Use SYSTEM / TrustedInstaller method.\n" | |
| L" /s Stealth? (requires /w)\n" | |
| L" /v Verbose output.\n" | |
| L" /w Wait for spawned process.\n"); | |
| HeapFreeMem(arg); | |
| arg = NULL; | |
| // In original code, setting _String_1=1 prevents setting error exit, | |
| // and if /w is not set, it returns 0 immediately. | |
| if (!(g_Flags & FLAG_W)) | |
| return 0; | |
| else | |
| return g_ExitCode; // data_14000514c | |
| default: | |
| LogError(L"Invalid option '%lc'", (DWORD)*p, 0); | |
| HeapFreeMem(arg); | |
| return 1; | |
| } | |
| } | |
| // Continue parsing next argument | |
| continue; | |
| } | |
| else | |
| { | |
| // Not an option – this is the command to run. | |
| // Break out of argument parsing. | |
| break; | |
| } | |
| } | |
| execute_command: | |
| // Command line to execute | |
| wchar_t* command = (arg != NULL) ? arg : L"cmd.exe"; | |
| // /s requires /w | |
| if ((g_Flags & (FLAG_S | FLAG_W)) == FLAG_S) | |
| { | |
| LogError(L"/s option requires /w", 0, 0); | |
| HeapFreeMem(command); | |
| return ERROR_INVALID_PARAMETER; | |
| } | |
| if (g_Flags & FLAG_V) | |
| PrintToConsole(stdout, L"Your command line is '%ls'", command); | |
| // Step 1: Acquire SeDebugPrivilege for the current process | |
| DWORD status = AcquireDebugPrivilege(); | |
| if (status != 0) | |
| { | |
| HeapFreeMem(command); | |
| return status; | |
| } | |
| HANDLE hSourceToken = NULL; | |
| HANDLE hDupToken = NULL; | |
| DWORD processCreationStatus = 0; | |
| // Step 2: Obtain an elevated token (SYSTEM or TrustedInstaller) | |
| if (g_Flags & FLAG_M) | |
| { | |
| // Try to get SYSTEM token via services.exe | |
| status = GetSystemToken(&hSourceToken); | |
| if (status != 0) | |
| processCreationStatus = status; | |
| } | |
| if (!(g_Flags & FLAG_M) || (g_Flags & FLAG_M && status == 0)) | |
| { | |
| // Fallback / default: use TrustedInstaller token | |
| status = OpenTrustedInstallerToken(&hSourceToken); | |
| if (status != 0) | |
| processCreationStatus = status; | |
| } | |
| if (processCreationStatus != 0) | |
| { | |
| HeapFreeMem(command); | |
| return processCreationStatus; | |
| } | |
| // Step 3: If /m, duplicate the token for child process and adjust session | |
| if (g_Flags & FLAG_M) | |
| { | |
| status = DuplicateTokenForChild(hSourceToken, &hDupToken); | |
| if (status != 0) | |
| { | |
| CloseHandle(hSourceToken); | |
| HeapFreeMem(command); | |
| return status; | |
| } | |
| // Set token session ID to the active console session | |
| DWORD sessionId = WTSGetActiveConsoleSessionId(); | |
| if (sessionId != 0xFFFFFFFF) | |
| SetTokenInformation(hDupToken, TokenSessionId, &sessionId, sizeof(sessionId)); | |
| // Enable all privileges in the duplicated token | |
| AdjustAllPrivileges(hDupToken, (g_Flags >> 2) & 1); | |
| } | |
| // Step 4: Prepare process creation | |
| STARTUPINFO si = { sizeof(si) }; | |
| PROCESS_INFORMATION pi = { 0 }; | |
| DWORD creationFlags = 0; | |
| // If /s not set, we may need a parent process attribute (TrustedInstaller) | |
| LPPROC_THREAD_ATTRIBUTE_LIST lpAttrList = NULL; | |
| if (!(g_Flags & FLAG_S)) | |
| { | |
| SIZE_T attrSize = 0; | |
| InitializeProcThreadAttributeList(NULL, 1, 0, &attrSize); | |
| lpAttrList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAllocZero(HEAP_ZERO_MEMORY, attrSize); | |
| InitializeProcThreadAttributeList(lpAttrList, 1, 0, &attrSize); | |
| UpdateProcThreadAttribute(lpAttrList, 0, | |
| PROC_THREAD_PARENT_PROCESS, | |
| &hSourceToken, sizeof(HANDLE), NULL, NULL); | |
| creationFlags |= EXTENDED_STARTUPINFO_PRESENT; | |
| } | |
| if (g_Flags & FLAG_V) | |
| PrintToConsole(stdout, L"Creating specified process"); | |
| // Step 5: Create the process | |
| BOOL bSuccess; | |
| if (g_Flags & FLAG_M) | |
| { | |
| // Use the duplicated token (SYSTEM or TrustedInstaller via session adjust) | |
| bSuccess = CreateProcessAsUserW( | |
| hDupToken, | |
| NULL, | |
| command, | |
| NULL, | |
| NULL, | |
| FALSE, | |
| creationFlags | CREATE_SUSPENDED, // CREATE_SUSPENDED (0x4) if not /s? Actually code sets rbx_5 depending on /m: if /m set rbx_5=0 else 0x80014 | |
| NULL, | |
| NULL, | |
| &si, | |
| &pi); | |
| } | |
| else | |
| { | |
| // Default method: use current token, but parent set to TrustedInstaller | |
| bSuccess = CreateProcessAsUserW( | |
| NULL, | |
| NULL, | |
| command, | |
| NULL, | |
| NULL, | |
| FALSE, | |
| creationFlags | CREATE_SUSPENDED, | |
| NULL, | |
| NULL, | |
| &si, | |
| &pi); | |
| } | |
| DWORD lastError = GetLastError(); | |
| if (!bSuccess) | |
| { | |
| LogError(L"Process creation failed", lastError, 0); | |
| processCreationStatus = 4; | |
| } | |
| else | |
| { | |
| // If not /m, adjust privileges of the new process token and resume | |
| if (!(g_Flags & FLAG_M)) | |
| { | |
| HANDLE hNewToken; | |
| if (OpenProcessToken(pi.hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hNewToken)) | |
| { | |
| AdjustAllPrivileges(hNewToken, (g_Flags >> 2) & 1); | |
| CloseHandle(hNewToken); | |
| } | |
| ResumeThread(pi.hThread); | |
| } | |
| if (g_Flags & FLAG_V) | |
| PrintToConsole(stdout, L"Created process ID: %lu", pi.dwProcessId); | |
| if (g_Flags & FLAG_W) | |
| { | |
| if (g_Flags & FLAG_V) | |
| PrintToConsole(stdout, L"Waiting for process to exit"); | |
| WaitForSingleObject(pi.hProcess, INFINITE); | |
| DWORD exitCode; | |
| if (GetExitCodeProcess(pi.hProcess, &exitCode)) | |
| { | |
| g_ExitCode = exitCode; | |
| if (g_Flags & FLAG_V) | |
| PrintToConsole(stdout, L"Process exited with code %ld", exitCode); | |
| } | |
| else | |
| { | |
| g_ExitCode = 0xFFF0BDBA; // arbitrary error | |
| if (g_Flags & FLAG_V) | |
| PrintToConsole(stdout, L"Failed to get exit code"); | |
| } | |
| } | |
| CloseHandle(pi.hProcess); | |
| CloseHandle(pi.hThread); | |
| } | |
| // Cleanup | |
| if (lpAttrList) | |
| { | |
| DeleteProcThreadAttributeList(lpAttrList); | |
| HeapFreeMem(lpAttrList); | |
| } | |
| if (g_Flags & FLAG_M) | |
| CloseHandle(hDupToken); | |
| CloseHandle(hSourceToken); | |
| HeapFreeMem(command); | |
| // Final exit code logic | |
| if (g_Flags & FLAG_W) | |
| { | |
| // If waiting, return the stored exit code (or 0 if we succeeded) | |
| if (processCreationStatus == 0) | |
| return g_ExitCode; | |
| else | |
| return 0xFFF0BDC0 - processCreationStatus; // wrap error | |
| } | |
| else | |
| { | |
| return processCreationStatus; | |
| } | |
| } | |
| // --------------------------------------------------------------------------- | |
| // Helper implementations | |
| // --------------------------------------------------------------------------- | |
| static void* HeapAllocZero(DWORD flags, SIZE_T size) | |
| { | |
| void* p = HeapAlloc(GetProcessHeap(), flags, size); | |
| if (!p) abort(); | |
| return p; | |
| } | |
| static void HeapFreeMem(void* mem) | |
| { | |
| if (mem) HeapFree(GetProcessHeap(), 0, mem); | |
| } | |
| static void PrintToConsole(FILE* stream, wchar_t* fmt, ...) | |
| { | |
| va_list args; | |
| va_start(args, fmt); | |
| int len = _vscwprintf(fmt, args); | |
| if (len > 0) | |
| { | |
| wchar_t* buf = (wchar_t*)HeapAllocZero(HEAP_ZERO_MEMORY, (len + 1) * sizeof(wchar_t)); | |
| _vsnwprintf_s(buf, len + 1, _TRUNCATE, fmt, args); | |
| fputws(buf, stream); | |
| HeapFreeMem(buf); | |
| } | |
| va_end(args); | |
| } | |
| static void LogError(wchar_t* msg, DWORD code, int pos) | |
| { | |
| wchar_t fullMsg[256]; | |
| if (code == 0) | |
| swprintf_s(fullMsg, L"[E] %ls (code: 0x%08lX, pos: %d)\n", msg, code, pos); | |
| else | |
| swprintf_s(fullMsg, L"[E] %ls\n", msg); | |
| fputws(fullMsg, stderr); | |
| } | |
| static BOOL SetPrivilege(HANDLE token, wchar_t* privName) | |
| { | |
| LUID luid; | |
| if (!LookupPrivilegeValueW(NULL, privName, &luid)) | |
| return FALSE; | |
| TOKEN_PRIVILEGES tp; | |
| tp.PrivilegeCount = 1; | |
| tp.Privileges[0].Luid = luid; | |
| tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; | |
| AdjustTokenPrivileges(token, FALSE, &tp, sizeof(tp), NULL, NULL); | |
| return (GetLastError() == ERROR_SUCCESS); | |
| } | |
| static void AdjustAllPrivileges(HANDLE token, BOOL report) | |
| { | |
| for (int i = 0; i < ARRAYSIZE(g_Privileges); i++) | |
| { | |
| if (!SetPrivilege(token, (wchar_t*)g_Privileges[i])) | |
| { | |
| if (report) | |
| PrintToConsole(stderr, L"Could not set privilege [%ls]", g_Privileges[i]); | |
| } | |
| } | |
| } | |
| static DWORD AcquireDebugPrivilege(void) | |
| { | |
| HANDLE hToken; | |
| if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) | |
| return 1; | |
| BOOL ok = SetPrivilege(hToken, SE_DEBUG_NAME); | |
| DWORD err = GetLastError(); | |
| CloseHandle(hToken); | |
| if (!ok) | |
| { | |
| LogError(L"Failed to acquire SeDebugPrivilege", err, 1); | |
| return 2; | |
| } | |
| return 0; | |
| } | |
| static DWORD GetSystemToken(HANDLE* phToken) | |
| { | |
| DWORD count = 0; | |
| WTS_PROCESS_INFOW* pInfo = NULL; | |
| if (!WTSEnumerateProcessesW(NULL, 0, 1, &pInfo, &count)) | |
| { | |
| LogError(L"Failed to create system context", 0xA0001000, 1); | |
| return 5; | |
| } | |
| DWORD targetPid = 0xFFFFFFFF; | |
| for (DWORD i = 0; i < count; i++) | |
| { | |
| if (pInfo[i].SessionId == 0 && | |
| pInfo[i].pProcessName && | |
| _wcsicmp(pInfo[i].pProcessName, L"services.exe") == 0 && | |
| pInfo[i].pUserSid && | |
| IsWellKnownSid(pInfo[i].pUserSid, WinLocalSystemSid)) | |
| { | |
| targetPid = pInfo[i].ProcessId; | |
| break; | |
| } | |
| } | |
| WTSFreeMemory(pInfo); | |
| if (targetPid == 0xFFFFFFFF) | |
| { | |
| LogError(L"Failed to create system context", 0xA0001000, 1); | |
| return 5; | |
| } | |
| HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, targetPid); | |
| if (!hProcess) | |
| { | |
| LogError(L"Failed to create system context", GetLastError(), 2); | |
| return 5; | |
| } | |
| HANDLE hToken; | |
| if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, &hToken)) | |
| { | |
| LogError(L"Failed to create system context", GetLastError(), 3); | |
| CloseHandle(hProcess); | |
| return 5; | |
| } | |
| HANDLE hDup; | |
| if (!DuplicateTokenEx(hToken, | |
| TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID, | |
| NULL, | |
| SecurityImpersonation, | |
| TokenPrimary, | |
| &hDup)) | |
| { | |
| LogError(L"Failed to create system context", GetLastError(), 4); | |
| CloseHandle(hToken); | |
| CloseHandle(hProcess); | |
| return 5; | |
| } | |
| CloseHandle(hToken); | |
| CloseHandle(hProcess); | |
| *phToken = hDup; | |
| // Also need SeAssignPrimaryTokenPrivilege and to set thread token | |
| if (!SetPrivilege(hDup, SE_ASSIGNPRIMARYTOKEN_NAME) || | |
| !SetThreadToken(NULL, hDup)) | |
| { | |
| LogError(L"Failed to create system context", GetLastError(), 5); | |
| CloseHandle(hDup); | |
| return 5; | |
| } | |
| return 0; | |
| } | |
| static DWORD OpenTrustedInstallerToken(HANDLE* phToken) | |
| { | |
| SC_HANDLE hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); | |
| SC_HANDLE hSvc = OpenServiceW(hSCM, L"TrustedInstaller", SERVICE_QUERY_STATUS | SERVICE_START); | |
| if (!hSvc) | |
| { | |
| LogError(L"Failed to open TrustedInstaller process", GetLastError(), 1); | |
| CloseServiceHandle(hSCM); | |
| return 3; | |
| } | |
| SERVICE_STATUS_PROCESS ssp; | |
| DWORD needed; | |
| if (!QueryServiceStatusEx(hSvc, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(ssp), &needed)) | |
| { | |
| LogError(L"Failed to open TrustedInstaller process", GetLastError(), 2); | |
| CloseServiceHandle(hSvc); | |
| CloseServiceHandle(hSCM); | |
| return 3; | |
| } | |
| // Wait for service to be running | |
| for (;;) | |
| { | |
| if (ssp.dwCurrentState == SERVICE_RUNNING) | |
| break; | |
| if (ssp.dwCurrentState == SERVICE_STOPPED) | |
| { | |
| if (!StartServiceW(hSvc, 0, NULL)) | |
| { | |
| LogError(L"Failed to open TrustedInstaller process", GetLastError(), 2); | |
| CloseServiceHandle(hSvc); | |
| CloseServiceHandle(hSCM); | |
| return 3; | |
| } | |
| } | |
| Sleep(100); | |
| if (!QueryServiceStatusEx(hSvc, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(ssp), &needed)) | |
| { | |
| LogError(L"Failed to open TrustedInstaller process", GetLastError(), 2); | |
| CloseServiceHandle(hSvc); | |
| CloseServiceHandle(hSCM); | |
| return 3; | |
| } | |
| } | |
| CloseServiceHandle(hSvc); | |
| CloseServiceHandle(hSCM); | |
| HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE, | |
| FALSE, ssp.dwProcessId); | |
| if (!hProcess) | |
| { | |
| LogError(L"Failed to open TrustedInstaller process", GetLastError(), 3); | |
| return 3; | |
| } | |
| *phToken = hProcess; | |
| return 0; | |
| } | |
| static DWORD DuplicateTokenForChild(HANDLE hSource, HANDLE* phToken) | |
| { | |
| HANDLE hToken; | |
| if (!OpenProcessToken(hSource, TOKEN_DUPLICATE, &hToken)) | |
| { | |
| LogError(L"Failed to create child process token", GetLastError(), 1); | |
| return 5; | |
| } | |
| if (!DuplicateTokenEx(hToken, | |
| TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID, | |
| NULL, | |
| SecurityIdentification, | |
| TokenPrimary, | |
| phToken)) | |
| { | |
| LogError(L"Failed to create child process token", GetLastError(), 2); | |
| CloseHandle(hToken); | |
| return 5; | |
| } | |
| CloseHandle(hToken); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment