示例#1
0
static PPH_STRING EspGetServiceSidString(
    _In_ PPH_STRINGREF ServiceName
    )
{
    PSID serviceSid = NULL;
    UNICODE_STRING serviceNameUs;
    ULONG serviceSidLength = 0;
    PPH_STRING sidString = NULL;

    if (!RtlCreateServiceSid_I)
        return NULL;

    PhStringRefToUnicodeString(ServiceName, &serviceNameUs);

    if (RtlCreateServiceSid_I(&serviceNameUs, serviceSid, &serviceSidLength) == STATUS_BUFFER_TOO_SMALL)
    {
        serviceSid = PhAllocate(serviceSidLength);

        if (NT_SUCCESS(RtlCreateServiceSid_I(&serviceNameUs, serviceSid, &serviceSidLength)))
            sidString = PhSidToStringSid(serviceSid);

        PhFree(serviceSid);
    }

    return sidString;
}
示例#2
0
static PPH_STRING NetworkAdapterQueryName(
    _Inout_ PPH_NETADAPTER_SYSINFO_CONTEXT Context
    )
{
    NDIS_OID opcode;
    IO_STATUS_BLOCK isb;
    WCHAR adapterNameBuffer[MAX_PATH] = L"";

    // https://msdn.microsoft.com/en-us/library/windows/hardware/ff569584.aspx
    opcode = OID_GEN_FRIENDLY_NAME;

    if (NT_SUCCESS(NtDeviceIoControlFile(
        Context->DeviceHandle,
        NULL,
        NULL,
        NULL,
        &isb,
        IOCTL_NDIS_QUERY_GLOBAL_STATS,
        &opcode,
        sizeof(NDIS_OID),
        adapterNameBuffer,
        sizeof(adapterNameBuffer)
        )))
    {
        return PhCreateString(adapterNameBuffer);
    }

    // HACK: Query adapter description using undocumented function.
    if (Context->GetInterfaceDescriptionFromGuid_I)
    {
        GUID deviceGuid = GUID_NULL;
        UNICODE_STRING guidStringUs;

        PhStringRefToUnicodeString(&Context->AdapterEntry->InterfaceGuid->sr, &guidStringUs);

        if (NT_SUCCESS(RtlGUIDFromString(&guidStringUs, &deviceGuid)))
        {
            SIZE_T adapterDescriptionLength = 0;
            WCHAR adapterDescription[NDIS_IF_MAX_STRING_SIZE + 1] = L"";

            adapterDescriptionLength = sizeof(adapterDescription); // This is what the API expects apparently... 

            if (SUCCEEDED(Context->GetInterfaceDescriptionFromGuid_I(&deviceGuid, adapterDescription, &adapterDescriptionLength, NULL, NULL)))
            {
                return PhCreateString(adapterDescription);
            }
        }
    }

    return PhCreateString(L"Unknown");
}
示例#3
0
static VOID WINAPI RunAsServiceMain(
    _In_ DWORD dwArgc,
    _In_ LPTSTR *lpszArgv
    )
{
    PPH_STRING portName;
    UNICODE_STRING portNameUs;
    LARGE_INTEGER timeout;

    memset(&RunAsServiceStop, 0, sizeof(PHSVC_STOP));
    RunAsServiceStatusHandle = RegisterServiceCtrlHandlerEx(RunAsServiceName->Buffer, RunAsServiceHandlerEx, NULL);
    SetRunAsServiceStatus(SERVICE_RUNNING);

    portName = PhConcatStrings2(L"\\BaseNamedObjects\\", RunAsServiceName->Buffer);
    PhStringRefToUnicodeString(&portName->sr, &portNameUs);
    // Use a shorter timeout value to reduce the time spent running as SYSTEM.
    timeout.QuadPart = -5 * PH_TIMEOUT_SEC;

    PhSvcMain(&portNameUs, &timeout, &RunAsServiceStop);

    SetRunAsServiceStatus(SERVICE_STOPPED);
}
示例#4
0
/**
 * Starts a program as another user.
 *
 * \param hWnd A handle to the parent window.
 * \param Program The command line of the program to start.
 * \param UserName The user to start the program as. The user
 * name should be specified as: domain\\name. This parameter
 * can be NULL if \a ProcessIdWithToken is specified.
 * \param Password The password for the specified user. If there
 * is no password, specify an empty string. This parameter
 * can be NULL if \a ProcessIdWithToken is specified.
 * \param LogonType The logon type for the specified user. This
 * parameter can be 0 if \a ProcessIdWithToken is specified.
 * \param ProcessIdWithToken The ID of a process from which
 * to duplicate the token.
 * \param SessionId The ID of the session to run the program
 * under.
 * \param DesktopName The window station and desktop to run the
 * program under.
 * \param UseLinkedToken Uses the linked token if possible.
 *
 * \retval STATUS_CANCELLED The user cancelled the operation.
 *
 * \remarks This function will cause another instance of
 * Process Hacker to be executed if the current security context
 * does not have sufficient system access. This is done
 * through a UAC elevation prompt.
 */
NTSTATUS PhExecuteRunAsCommand2(
    _In_ HWND hWnd,
    _In_ PWSTR Program,
    _In_opt_ PWSTR UserName,
    _In_opt_ PWSTR Password,
    _In_opt_ ULONG LogonType,
    _In_opt_ HANDLE ProcessIdWithToken,
    _In_ ULONG SessionId,
    _In_ PWSTR DesktopName,
    _In_ BOOLEAN UseLinkedToken
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    PH_RUNAS_SERVICE_PARAMETERS parameters;
    WCHAR serviceName[32];
    PPH_STRING portName;
    UNICODE_STRING portNameUs;

    memset(&parameters, 0, sizeof(PH_RUNAS_SERVICE_PARAMETERS));
    parameters.ProcessId = HandleToUlong(ProcessIdWithToken);
    parameters.UserName = UserName;
    parameters.Password = Password;
    parameters.LogonType = LogonType;
    parameters.SessionId = SessionId;
    parameters.CommandLine = Program;
    parameters.DesktopName = DesktopName;
    parameters.UseLinkedToken = UseLinkedToken;

    // Try to use an existing instance of the service if possible.
    if (RunAsOldServiceName[0] != 0)
    {
        PhAcquireQueuedLockExclusive(&RunAsOldServiceLock);

        portName = PhConcatStrings2(L"\\BaseNamedObjects\\", RunAsOldServiceName);
        PhStringRefToUnicodeString(&portName->sr, &portNameUs);

        if (NT_SUCCESS(PhSvcConnectToServer(&portNameUs, 0)))
        {
            parameters.ServiceName = RunAsOldServiceName;
            status = PhSvcCallInvokeRunAsService(&parameters);
            PhSvcDisconnectFromServer();

            PhDereferenceObject(portName);
            PhReleaseQueuedLockExclusive(&RunAsOldServiceLock);

            return status;
        }

        PhDereferenceObject(portName);
        PhReleaseQueuedLockExclusive(&RunAsOldServiceLock);
    }

    // An existing instance was not available. Proceed normally.

    memcpy(serviceName, L"ProcessHacker", 13 * sizeof(WCHAR));
    PhGenerateRandomAlphaString(&serviceName[13], 16);
    PhAcquireQueuedLockExclusive(&RunAsOldServiceLock);
    memcpy(RunAsOldServiceName, serviceName, sizeof(serviceName));
    PhReleaseQueuedLockExclusive(&RunAsOldServiceLock);

    parameters.ServiceName = serviceName;

    if (PhGetOwnTokenAttributes().Elevated)
    {
        status = PhExecuteRunAsCommand(&parameters);
    }
    else
    {
        if (PhUiConnectToPhSvc(hWnd, FALSE))
        {
            status = PhSvcCallExecuteRunAsCommand(&parameters);
            PhUiDisconnectFromPhSvc();
        }
        else
        {
            status = STATUS_CANCELLED;
        }
    }

    return status;
}
示例#5
0
/**
 * Executes the run-as service.
 *
 * \param Parameters The run-as parameters.
 *
 * \remarks This function requires administrator-level access.
 */
NTSTATUS PhExecuteRunAsCommand(
    _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters
    )
{
    NTSTATUS status;
    ULONG win32Result;
    PPH_STRING commandLine;
    SC_HANDLE scManagerHandle;
    SC_HANDLE serviceHandle;
    PPH_STRING portName;
    UNICODE_STRING portNameUs;
    ULONG attempts;
    LARGE_INTEGER interval;

    if (!(scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE)))
        return PhGetLastWin32ErrorAsNtStatus();

    commandLine = PhFormatString(L"\"%s\" -ras \"%s\"", PhApplicationFileName->Buffer, Parameters->ServiceName);

    serviceHandle = CreateService(
        scManagerHandle,
        Parameters->ServiceName,
        Parameters->ServiceName,
        SERVICE_ALL_ACCESS,
        SERVICE_WIN32_OWN_PROCESS,
        SERVICE_DEMAND_START,
        SERVICE_ERROR_IGNORE,
        commandLine->Buffer,
        NULL,
        NULL,
        NULL,
        L"LocalSystem",
        L""
        );
    win32Result = GetLastError();

    PhDereferenceObject(commandLine);

    CloseServiceHandle(scManagerHandle);

    if (!serviceHandle)
    {
        return NTSTATUS_FROM_WIN32(win32Result);
    }

    PhSetDesktopWinStaAccess();

    StartService(serviceHandle, 0, NULL);
    DeleteService(serviceHandle);

    portName = PhConcatStrings2(L"\\BaseNamedObjects\\", Parameters->ServiceName);
    PhStringRefToUnicodeString(&portName->sr, &portNameUs);
    attempts = 10;

    // Try to connect several times because the server may take
    // a while to initialize.
    do
    {
        status = PhSvcConnectToServer(&portNameUs, 0);

        if (NT_SUCCESS(status))
            break;

        interval.QuadPart = -50 * PH_TIMEOUT_MS;
        NtDelayExecution(FALSE, &interval);
    } while (--attempts != 0);

    PhDereferenceObject(portName);

    if (NT_SUCCESS(status))
    {
        status = PhSvcCallInvokeRunAsService(Parameters);
        PhSvcDisconnectFromServer();
    }

    if (serviceHandle)
        CloseServiceHandle(serviceHandle);

    return status;
}
示例#6
0
static VOID RemoveAppCompatEntry(
    _In_ HANDLE ParentKey
    )
{
    static PH_STRINGREF keyName = PH_STRINGREF_INIT(L"ProcessHacker.exe");
    ULONG bufferLength;
    KEY_FULL_INFORMATION fullInfo;

    memset(&fullInfo, 0, sizeof(KEY_FULL_INFORMATION));

    if (!NT_SUCCESS(NtQueryKey(
        ParentKey,
        KeyFullInformation,
        &fullInfo,
        sizeof(KEY_FULL_INFORMATION),
        &bufferLength
        )))
    {
        return;
    }

    for (ULONG i = 0; i < fullInfo.Values; i++)
    {
        PPH_STRING value;
        PKEY_VALUE_FULL_INFORMATION buffer;

        bufferLength = sizeof(KEY_VALUE_FULL_INFORMATION);
        buffer = PhAllocate(bufferLength);
        memset(buffer, 0, bufferLength);

        if (NT_SUCCESS(NtEnumerateValueKey(
            ParentKey,
            i,
            KeyValueFullInformation,
            buffer,
            bufferLength,
            &bufferLength
            )))
        {
            PhFree(buffer);
            break;
        }

        //bufferLength = bufferLength;
        buffer = PhReAllocate(buffer, bufferLength);
        memset(buffer, 0, bufferLength);

        if (!NT_SUCCESS(NtEnumerateValueKey(
            ParentKey,
            i,
            KeyValueFullInformation,
            buffer,
            bufferLength,
            &bufferLength
            )))
        {
            PhFree(buffer);
            break;
        }

        if (value = PhCreateStringEx(buffer->Name, buffer->NameLength))
        {
            UNICODE_STRING us;

            PhStringRefToUnicodeString(&value->sr, &us);

            if (PhEndsWithStringRef(&value->sr, &keyName, TRUE))
            {
                NtDeleteValueKey(ParentKey, &us);
            }

            PhDereferenceObject(value);
        }

        PhFree(buffer);
    }
}
示例#7
0
BOOLEAN PhaGetProcessKnownCommandLine(
    __in PPH_STRING CommandLine,
    __in PH_KNOWN_PROCESS_TYPE KnownProcessType,
    __out PPH_KNOWN_PROCESS_COMMAND_LINE KnownCommandLine
    )
{
    switch (KnownProcessType & KnownProcessTypeMask)
    {
    case ServiceHostProcessType:
        {
            // svchost.exe -k <GroupName>

            static PH_COMMAND_LINE_OPTION options[] =
            {
                { 1, L"k", MandatoryArgumentType }
            };

            KnownCommandLine->ServiceHost.GroupName = NULL;

            PhParseCommandLine(
                &CommandLine->sr,
                options,
                sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION),
                PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS,
                PhpSvchostCommandLineCallback,
                KnownCommandLine
                );

            if (KnownCommandLine->ServiceHost.GroupName)
            {
                PhaDereferenceObject(KnownCommandLine->ServiceHost.GroupName);
                return TRUE;
            }
            else
            {
                return FALSE;
            }
        }
        break;
    case RunDllAsAppProcessType:
        {
            // rundll32.exe <DllName>,<ProcedureName> ...

            SIZE_T i;
            ULONG_PTR lastIndexOfComma;
            PPH_STRING dllName;
            PPH_STRING procedureName;

            i = 0;

            // Get the rundll32.exe part.

            dllName = PhParseCommandLinePart(&CommandLine->sr, &i);

            if (!dllName)
                return FALSE;

            PhDereferenceObject(dllName);

            // Get the DLL name part.

            while (i < CommandLine->Length / 2 && CommandLine->Buffer[i] == ' ')
                i++;

            dllName = PhParseCommandLinePart(&CommandLine->sr, &i);

            if (!dllName)
                return FALSE;

            PhaDereferenceObject(dllName);

            // The procedure name begins after the last comma.

            lastIndexOfComma = PhFindLastCharInString(dllName, 0, ',');

            if (lastIndexOfComma == -1)
                return FALSE;

            procedureName = PhaSubstring(
                dllName,
                lastIndexOfComma + 1,
                dllName->Length / 2 - lastIndexOfComma - 1
                );
            dllName = PhaSubstring(dllName, 0, lastIndexOfComma);

            // If the DLL name isn't an absolute path, assume it's in system32.
            // TODO: Use a proper search function.

            if (RtlDetermineDosPathNameType_U(dllName->Buffer) == RtlPathTypeRelative)
            {
                dllName = PhaConcatStrings(
                    3,
                    ((PPH_STRING)PHA_DEREFERENCE(PhGetSystemDirectory()))->Buffer,
                    L"\\",
                    dllName->Buffer
                    );
            }

            KnownCommandLine->RunDllAsApp.FileName = dllName;
            KnownCommandLine->RunDllAsApp.ProcedureName = procedureName;
        }
        break;
    case ComSurrogateProcessType:
        {
            // dllhost.exe /processid:<Guid>

            static PH_STRINGREF inprocServer32Name = PH_STRINGREF_INIT(L"InprocServer32");

            SIZE_T i;
            ULONG_PTR indexOfProcessId;
            PPH_STRING argPart;
            PPH_STRING guidString;
            UNICODE_STRING guidStringUs;
            GUID guid;
            HANDLE clsidKeyHandle;
            HANDLE inprocServer32KeyHandle;
            PPH_STRING fileName;

            i = 0;

            // Get the dllhost.exe part.

            argPart = PhParseCommandLinePart(&CommandLine->sr, &i);

            if (!argPart)
                return FALSE;

            PhDereferenceObject(argPart);

            // Get the argument part.

            while (i < (ULONG)CommandLine->Length / 2 && CommandLine->Buffer[i] == ' ')
                i++;

            argPart = PhParseCommandLinePart(&CommandLine->sr, &i);

            if (!argPart)
                return FALSE;

            PhaDereferenceObject(argPart);

            // Find "/processid:"; the GUID is just after that.

            PhUpperString(argPart);
            indexOfProcessId = PhFindStringInString(argPart, 0, L"/PROCESSID:");

            if (indexOfProcessId == -1)
                return FALSE;

            guidString = PhaSubstring(
                argPart,
                indexOfProcessId + 11,
                (ULONG)argPart->Length / 2 - indexOfProcessId - 11
                );
            PhStringRefToUnicodeString(&guidString->sr, &guidStringUs);

            if (!NT_SUCCESS(RtlGUIDFromString(
                &guidStringUs,
                &guid
                )))
                return FALSE;

            KnownCommandLine->ComSurrogate.Guid = guid;
            KnownCommandLine->ComSurrogate.Name = NULL;
            KnownCommandLine->ComSurrogate.FileName = NULL;

            // Lookup the GUID in the registry to determine the name and file name.

            if (NT_SUCCESS(PhOpenKey(
                &clsidKeyHandle,
                KEY_READ,
                PH_KEY_CLASSES_ROOT,
                &PhaConcatStrings2(L"CLSID\\", guidString->Buffer)->sr,
                0
                )))
            {
                KnownCommandLine->ComSurrogate.Name =
                    PHA_DEREFERENCE(PhQueryRegistryString(clsidKeyHandle, NULL));

                if (NT_SUCCESS(PhOpenKey(
                    &inprocServer32KeyHandle,
                    KEY_READ,
                    clsidKeyHandle,
                    &inprocServer32Name,
                    0
                    )))
                {
                    KnownCommandLine->ComSurrogate.FileName =
                        PHA_DEREFERENCE(PhQueryRegistryString(inprocServer32KeyHandle, NULL));

                    if (fileName = PHA_DEREFERENCE(PhExpandEnvironmentStrings(
                        &KnownCommandLine->ComSurrogate.FileName->sr
                        )))
                    {
                        KnownCommandLine->ComSurrogate.FileName = fileName;
                    }

                    NtClose(inprocServer32KeyHandle);
                }

                NtClose(clsidKeyHandle);
            }
        }
        break;
    default:
        return FALSE;
    }

    return TRUE;
}
示例#8
0
int __cdecl main(int argc, char *argv[])
{
    static PH_COMMAND_LINE_OPTION options[] =
    {
        { FI_ARG_HELP, L"h", NoArgumentType },
        { FI_ARG_ACTION, L"a", MandatoryArgumentType },
        { FI_ARG_NATIVE, L"N", NoArgumentType },
        { FI_ARG_PATTERN, L"p", MandatoryArgumentType },
        { FI_ARG_CASESENSITIVE, L"C", NoArgumentType },
        { FI_ARG_OUTPUT, L"o", MandatoryArgumentType },
        { FI_ARG_FORCE, L"f", NoArgumentType },
        { FI_ARG_LENGTH, L"L", MandatoryArgumentType }
    };
    PH_STRINGREF commandLine;
    NTSTATUS status = STATUS_SUCCESS;

    if (!NT_SUCCESS(PhInitializePhLibEx(0, 0, 0)))
        return 1;

    PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine);

    if (!PhParseCommandLine(
        &commandLine,
        options,
        sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION),
        PH_COMMAND_LINE_IGNORE_FIRST_PART,
        FiCommandLineCallback,
        NULL
        ) || FiArgHelp)
    {
        FiPrintHelp();
        return 0;
    }

    if (!FiArgFileName && (
        FiArgAction &&
        PhEqualString2(FiArgAction, L"dir", TRUE)
        ))
    {
        FiArgFileName = PhCreateStringFromUnicodeString(&NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath);
    }

    if (!FiArgAction)
    {
        FiPrintHelp();
        return 1;
    }
    else if (PhEqualString2(FiArgAction, L"map", TRUE))
    {
        WCHAR deviceNameBuffer[7] = L"\\??\\ :";
        ULONG i;
        WCHAR targetNameBuffer[0x100];
        UNICODE_STRING targetName;

        targetName.Buffer = targetNameBuffer;
        targetName.MaximumLength = sizeof(targetNameBuffer);

        for (i = 0; i < 26; i++)
        {
            HANDLE linkHandle;
            OBJECT_ATTRIBUTES oa;
            UNICODE_STRING deviceName;

            deviceNameBuffer[4] = (WCHAR)('A' + i);
            deviceName.Buffer = deviceNameBuffer;
            deviceName.Length = 6 * sizeof(WCHAR);

            InitializeObjectAttributes(
                &oa,
                &deviceName,
                OBJ_CASE_INSENSITIVE,
                NULL,
                NULL
                );

            if (NT_SUCCESS(NtOpenSymbolicLinkObject(
                &linkHandle,
                SYMBOLIC_LINK_QUERY,
                &oa
                )))
            {
                if (NT_SUCCESS(NtQuerySymbolicLinkObject(
                    linkHandle,
                    &targetName,
                    NULL
                    )))
                {
                    wprintf(L"%c: %.*s\n", 'A' + i, targetName.Length / 2, targetName.Buffer);
                }

                NtClose(linkHandle);
            }
        }
    }
    else if (!FiArgFileName)
    {
        wprintf(L"Error: file name missing.\n");
        FiPrintHelp();
        return 1;
    }
    else if (PhEqualString2(FiArgAction, L"hash", TRUE))
    {
        HANDLE fileHandle;
        LARGE_INTEGER fileSize;
        IO_STATUS_BLOCK isb;
        ULONG mode;

        if (!FiArgOutput)
            mode = HASH_MD5;
        else if (PhEqualString2(FiArgOutput, L"md5", TRUE))
            mode = HASH_MD5;
        else if (PhEqualString2(FiArgOutput, L"sha1", TRUE))
            mode = HASH_SHA1;
        else if (PhEqualString2(FiArgOutput, L"crc32", TRUE))
            mode = HASH_CRC32;
        else
        {
            wprintf(L"Invalid hash algorithm. Possibilities: md5, sha1, crc32\n");
            return 1;
        }

        if (FiCreateFile(
            &fileHandle,
            FILE_GENERIC_READ,
            FiArgFileName,
            0,
            FILE_SHARE_READ | FILE_SHARE_DELETE,
            FILE_OPEN,
            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY
            ))
        {
            if (NT_SUCCESS(status = PhGetFileSize(fileHandle, &fileSize)))
            {
                MD5_CTX md5Context;
                A_SHA_CTX shaContext;
                ULONG crc;
                UCHAR buffer[PAGE_SIZE * 4];
                ULONG64 bytesRemaining;

                bytesRemaining = fileSize.QuadPart;

                switch (mode)
                {
                case HASH_MD5:
                    MD5Init(&md5Context);
                    break;
                case HASH_SHA1:
                    A_SHAInit(&shaContext);
                    break;
                case HASH_CRC32:
                    crc = 0;
                    break;
                }

                while (bytesRemaining)
                {
                    status = NtReadFile(
                        fileHandle,
                        NULL,
                        NULL,
                        NULL,
                        &isb,
                        buffer,
                        sizeof(buffer),
                        NULL,
                        NULL
                        );

                    if (!NT_SUCCESS(status))
                        break;

                    switch (mode)
                    {
                    case HASH_MD5:
                        MD5Update(&md5Context, buffer, (ULONG)isb.Information);
                        break;
                    case HASH_SHA1:
                        A_SHAUpdate(&shaContext, buffer, (ULONG)isb.Information);
                        break;
                    case HASH_CRC32:
                        crc = PhCrc32(crc, buffer, isb.Information);
                        break;
                    }

                    bytesRemaining -= (ULONG)isb.Information;
                }

                if (status == STATUS_END_OF_FILE)
                    status = STATUS_SUCCESS;

                switch (mode)
                {
                case HASH_MD5:
                    {
                        MD5Final(&md5Context);
                        wprintf(L"%s", PhBufferToHexString(md5Context.digest, 16)->Buffer);
                    }
                    break;
                case HASH_SHA1:
                    {
                        UCHAR hash[20];

                        A_SHAFinal(&shaContext, hash);
                        wprintf(L"%s", PhBufferToHexString(hash, 20)->Buffer);
                    }
                    break;
                case HASH_CRC32:
                    {
                        wprintf(L"%08x", crc);
                    }
                    break;
                }

                if (!NT_SUCCESS(status))
                    wprintf(L"Warning: I/O error encountered: %s\n", PhGetNtMessage(status)->Buffer);
            }

            NtClose(fileHandle);
        }

        if (!NT_SUCCESS(status))
        {
            wprintf(L"Error: %s\n", PhGetNtMessage(status)->Buffer);
            return 1;
        }
    }
    else if (PhEqualString2(FiArgAction, L"execute", TRUE))
    {
        if (FiArgNative)
        {
            if (!NT_SUCCESS(status = PhCreateProcess(
                FiFormatFileName(FiArgFileName)->Buffer,
                FiArgOutput ? &FiArgOutput->sr : NULL,
                NULL,
                NULL,
                NULL,
                0,
                NULL,
                NULL,
                NULL,
                NULL
                )))
            {
                wprintf(L"Error: %s\n", PhGetNtMessage(status)->Buffer);
                return 1;
            }
        }
        else
        {
            if (!NT_SUCCESS(status = PhCreateProcessWin32(
                FiArgFileName->Buffer,
                PhGetString(FiArgOutput),
                NULL,
                NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath.Buffer,
                PH_CREATE_PROCESS_NEW_CONSOLE,
                NULL,
                NULL,
                NULL
                )))
            {
                wprintf(L"Error: %s\n", PhGetNtMessage(status)->Buffer);
                return 1;
            }
        }
    }
    else if (PhEqualString2(FiArgAction, L"del", TRUE))
    {
        HANDLE fileHandle;

        if (FiCreateFile(
            &fileHandle,
            DELETE | SYNCHRONIZE,
            FiArgFileName,
            0,
            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
            FILE_OPEN,
            FILE_SYNCHRONOUS_IO_NONALERT
            ))
        {
            FILE_DISPOSITION_INFORMATION dispositionInfo;
            IO_STATUS_BLOCK isb;

            dispositionInfo.DeleteFile = TRUE;
            if (!NT_SUCCESS(status = NtSetInformationFile(fileHandle, &isb, &dispositionInfo,
                sizeof(FILE_DISPOSITION_INFORMATION), FileDispositionInformation)))
            {
                wprintf(L"Error deleting file: %s\n", PhGetNtMessage(status)->Buffer);
            }

            NtClose(fileHandle);
        }
    }
    else if (PhEqualString2(FiArgAction, L"touch", TRUE))
    {
        HANDLE fileHandle;

        if (FiCreateFile(
            &fileHandle,
            FILE_READ_ATTRIBUTES | SYNCHRONIZE,
            FiArgFileName,
            0,
            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
            FILE_OPEN_IF,
            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
            ))
        {
            NtClose(fileHandle);
        }
    }
    else if (PhEqualString2(FiArgAction, L"mkdir", TRUE))
    {
        HANDLE fileHandle;

        if (FiCreateFile(
            &fileHandle,
            FILE_READ_ATTRIBUTES | SYNCHRONIZE,
            FiArgFileName,
            FILE_ATTRIBUTE_DIRECTORY,
            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
            FILE_CREATE,
            FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
            ))
        {
            NtClose(fileHandle);
        }
    }
    else if (PhEqualString2(FiArgAction, L"rename", TRUE))
    {
        HANDLE fileHandle;
        PPH_STRING newFileName;

        if (!FiArgOutput)
        {
            wprintf(L"Error: new file name missing.\n");
            FiPrintHelp();
            return 1;
        }

        newFileName = FiFormatFileName(FiArgOutput);

        if (FiCreateFile(
            &fileHandle,
            DELETE | SYNCHRONIZE,
            FiArgFileName,
            0,
            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
            FILE_OPEN,
            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
            ))
        {
            PFILE_RENAME_INFORMATION renameInfo;
            ULONG renameInfoSize;
            IO_STATUS_BLOCK isb;

            renameInfoSize = FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) + (ULONG)newFileName->Length;
            renameInfo = PhAllocate(renameInfoSize);
            renameInfo->ReplaceIfExists = FiArgForce;
            renameInfo->RootDirectory = NULL;
            renameInfo->FileNameLength = (ULONG)newFileName->Length;
            memcpy(renameInfo->FileName, newFileName->Buffer, newFileName->Length);

            status = NtSetInformationFile(fileHandle, &isb, renameInfo, renameInfoSize, FileRenameInformation);
            PhFree(renameInfo);

            if (!NT_SUCCESS(status))
            {
                wprintf(L"Error renaming file: %s\n", PhGetNtMessage(status)->Buffer);
            }

            NtClose(fileHandle);
        }
    }
    else if (PhEqualString2(FiArgAction, L"copy", TRUE))
    {
        HANDLE fileHandle;
        HANDLE outFileHandle;
        LARGE_INTEGER fileSize;
        FILE_BASIC_INFORMATION basicInfo;

        if (!FiArgOutput)
        {
            wprintf(L"Error: output file name missing.\n");
            FiPrintHelp();
            return 1;
        }

        if (FiCreateFile(
            &fileHandle,
            FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE,
            FiArgFileName,
            0,
            FILE_SHARE_READ | FILE_SHARE_DELETE,
            FILE_OPEN,
            FILE_NON_DIRECTORY_FILE | FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT
            ) && FiCreateFile(
            &outFileHandle,
            FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | SYNCHRONIZE,
            FiArgOutput,
            0,
            FILE_SHARE_READ | FILE_SHARE_DELETE,
            !FiArgForce ? FILE_CREATE : FILE_OVERWRITE_IF,
            FILE_NON_DIRECTORY_FILE | FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT
            ))
        {
#define COPY_BUFFER_SIZE 0x10000
            IO_STATUS_BLOCK isb;
            PVOID buffer;
            ULONG64 bytesToCopy = FiArgLength;

            if (NT_SUCCESS(PhGetFileSize(fileHandle, &fileSize)))
            {
                PhSetFileSize(outFileHandle, &fileSize);
            }

            buffer = PhAllocatePage(COPY_BUFFER_SIZE, NULL);

            if (!buffer)
            {
                wprintf(L"Error allocating buffer.\n");
                return 1;
            }

            while (bytesToCopy)
            {
                status = NtReadFile(
                    fileHandle,
                    NULL,
                    NULL,
                    NULL,
                    &isb,
                    buffer,
                    bytesToCopy >= COPY_BUFFER_SIZE ? COPY_BUFFER_SIZE : (ULONG)bytesToCopy,
                    NULL,
                    NULL
                    );

                if (status == STATUS_END_OF_FILE)
                {
                    break;
                }
                else if (!NT_SUCCESS(status))
                {
                    wprintf(L"Error reading from file: %s\n", PhGetNtMessage(status)->Buffer);
                    break;
                }

                status = NtWriteFile(
                    outFileHandle,
                    NULL,
                    NULL,
                    NULL,
                    &isb,
                    buffer,
                    (ULONG)isb.Information, // number of bytes read
                    NULL,
                    NULL
                    );

                if (!NT_SUCCESS(status))
                {
                    wprintf(L"Error writing to output file: %s\n", PhGetNtMessage(status)->Buffer);
                    break;
                }

                bytesToCopy -= (ULONG)isb.Information;
            }

            PhFreePage(buffer);

            // Copy basic attributes over.
            if (NT_SUCCESS(NtQueryInformationFile(
                fileHandle,
                &isb,
                &basicInfo,
                sizeof(FILE_BASIC_INFORMATION),
                FileBasicInformation
                )))
            {
                NtSetInformationFile(
                    outFileHandle,
                    &isb,
                    &basicInfo,
                    sizeof(FILE_BASIC_INFORMATION),
                    FileBasicInformation
                    );
            }

            NtClose(fileHandle);
            NtClose(outFileHandle);
        }
    }
    else if (PhEqualString2(FiArgAction, L"dir", TRUE))
    {
        HANDLE fileHandle;
        UNICODE_STRING pattern;
        PPH_STRING totalSize, totalAllocSize;

        if (FiCreateFile(
            &fileHandle,
            FILE_LIST_DIRECTORY | SYNCHRONIZE,
            FiArgFileName,
            0,
            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
            FILE_OPEN,
            FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
            ))
        {
            FipDirFileCount = 0;
            FipDirDirCount = 0;
            FipDirTotalSize = 0;
            FipDirTotalAllocSize = 0;

            if (FiArgPattern)
                PhStringRefToUnicodeString(&FiArgPattern->sr, &pattern);

            PhEnumDirectoryFile(
                fileHandle,
                FiArgPattern ? &pattern : NULL,
                FipEnumDirectoryFileForDir,
                NULL
                );
            NtClose(fileHandle);

            totalSize = PhFormatUInt64(FipDirTotalSize, TRUE);
            totalAllocSize = PhFormatUInt64(FipDirTotalAllocSize, TRUE);

            wprintf(
                L"%12I64u file(s)  %11s bytes\n"
                L"%12I64u dir(s)   %11s bytes allocated\n",
                FipDirFileCount,
                totalSize->Buffer,
                FipDirDirCount,
                totalAllocSize->Buffer
                );

            PhDereferenceObject(totalSize);
            PhDereferenceObject(totalAllocSize);
        }
    }
    else if (PhEqualString2(FiArgAction, L"streams", TRUE))
    {
        HANDLE fileHandle;
        PVOID streams;
        PFILE_STREAM_INFORMATION stream;

        if (FiCreateFile(
            &fileHandle,
            FILE_READ_ATTRIBUTES | SYNCHRONIZE,
            FiArgFileName,
            0,
            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
            FILE_OPEN,
            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
            ))
        {
            if (NT_SUCCESS(PhEnumFileStreams(fileHandle, &streams)))
            {
                stream = PH_FIRST_STREAM(streams);

                while (stream)
                {
                    PPH_STRING size, allocationSize;

                    size = PhFormatUInt64(stream->StreamSize.QuadPart, TRUE);
                    allocationSize = PhFormatUInt64(stream->StreamAllocationSize.QuadPart, TRUE);

                    wprintf(
                        L"%11s %11s %.*s\n",
                        size->Buffer,
                        allocationSize->Buffer,
                        stream->StreamNameLength / 2,
                        stream->StreamName
                        );

                    PhDereferenceObject(size);
                    PhDereferenceObject(allocationSize);

                    stream = PH_NEXT_STREAM(stream);
                }
            }

            NtClose(fileHandle);
        }
    }
    else
    {
        wprintf(L"Error: invalid action \"%s\".\n", FiArgAction->Buffer);
        FiPrintHelp();
        return 1;
    }
}
示例#9
0
BOOLEAN FiCreateFile(
    _Out_ PHANDLE FileHandle,
    _In_ ACCESS_MASK DesiredAccess,
    _In_ PPH_STRING FileName,
    _In_opt_ ULONG FileAttributes,
    _In_ ULONG ShareAccess,
    _In_ ULONG CreateDisposition,
    _In_opt_ ULONG Options
    )
{
    NTSTATUS status;
    HANDLE fileHandle;
    OBJECT_ATTRIBUTES oa;
    IO_STATUS_BLOCK isb;
    PPH_STRING fileName;
    UNICODE_STRING fileNameUs;

    if (!FileAttributes)
        FileAttributes = FILE_ATTRIBUTE_NORMAL;
    if (!Options)
        Options = FILE_SYNCHRONOUS_IO_NONALERT;

    // Not needed, because we handle Win32 paths anyway.
    //if (!(FiArgNative))
    //{
    //    status = PhCreateFileWin32(
    //        FileHandle,
    //        FileName->Buffer,
    //        DesiredAccess,
    //        FileAttributes,
    //        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    //        CreateDisposition,
    //        Options
    //        );

    //    if (!NT_SUCCESS(status))
    //    {
    //        wprintf(L"Error creating/opening file: %s\n", PhGetNtMessage(status)->Buffer);
    //        return FALSE;
    //    }

    //    return TRUE;
    //}

    fileName = FiFormatFileName(FileName);

    if (!PhStringRefToUnicodeString(&fileName->sr, &fileNameUs))
    {
        PhDereferenceObject(fileName);
        return FALSE;
    }

    InitializeObjectAttributes(
        &oa,
        &fileNameUs,
        (!FiArgCaseSensitive ? OBJ_CASE_INSENSITIVE : 0),
        NULL,
        NULL
        );

    status = NtCreateFile(
        &fileHandle,
        DesiredAccess,
        &oa,
        &isb,
        NULL,
        FileAttributes,
        ShareAccess,
        CreateDisposition,
        Options,
        NULL,
        0
        );

    if (!NT_SUCCESS(status))
    {
        wprintf(L"Error creating/opening file: %s\n", PhGetNtMessage(status)->Buffer);
        return FALSE;
    }

    *FileHandle = fileHandle;

    return TRUE;
}
示例#10
0
PPH_LIST QueryDotNetAppDomainsForPid_V4(
    _In_ BOOLEAN Wow64,
    _In_ HANDLE ProcessHandle,
    _In_ HANDLE ProcessId
    )
{
    HANDLE legacyPrivateBlockHandle = NULL;
    PVOID ipcControlBlockTable = NULL;
    LARGE_INTEGER sectionOffset = { 0 };
    SIZE_T viewSize = 0;
    OBJECT_ATTRIBUTES objectAttributes;
    UNICODE_STRING sectionNameUs;
    PPH_LIST appDomainsList = NULL;

    if (!PhStringRefToUnicodeString(&GeneratePrivateNameV4(ProcessId)->sr, &sectionNameUs))
        goto CleanupExit;

    InitializeObjectAttributes(
        &objectAttributes,
        &sectionNameUs,
        OBJ_CASE_INSENSITIVE,
        NULL,
        NULL
        );

    if (!NT_SUCCESS(NtOpenSection(
        &legacyPrivateBlockHandle,
        SECTION_MAP_READ,
        &objectAttributes
        )))
    {
        goto CleanupExit;
    }

    if (!NT_SUCCESS(NtMapViewOfSection(
        legacyPrivateBlockHandle,
        NtCurrentProcess(),
        &ipcControlBlockTable,
        0,
        viewSize,
        &sectionOffset,
        &viewSize,
        ViewShare,
        0,
        PAGE_READONLY
        )))
    {
        goto CleanupExit;
    }

    if (Wow64)
    {
        LegacyPrivateIPCControlBlock_Wow64* legacyPrivateBlock;
        AppDomainEnumerationIPCBlock_Wow64* appDomainEnumBlock;

        legacyPrivateBlock = (LegacyPrivateIPCControlBlock_Wow64*)ipcControlBlockTable;
        appDomainEnumBlock = &legacyPrivateBlock->AppDomainBlock;

        // Check the IPCControlBlock is initialized.
        if ((legacyPrivateBlock->FullIPCHeader.Header.Flags & IPC_FLAG_INITIALIZED) != IPC_FLAG_INITIALIZED)
        {
            goto CleanupExit;
        }

        // Check the IPCControlBlock version is valid.
        if (legacyPrivateBlock->FullIPCHeader.Header.Version > VER_LEGACYPRIVATE_IPC_BLOCK)
        {
            goto CleanupExit;
        }

        appDomainsList = EnumerateAppDomainIpcBlockWow64(
            ProcessHandle,
            appDomainEnumBlock
            );
    }
    else
    {
        LegacyPrivateIPCControlBlock* legacyPrivateBlock;
        AppDomainEnumerationIPCBlock* appDomainEnumBlock;

        legacyPrivateBlock = (LegacyPrivateIPCControlBlock*)ipcControlBlockTable;
        appDomainEnumBlock = &legacyPrivateBlock->AppDomainBlock;

        // Check the IPCControlBlock is initialized.
        if ((legacyPrivateBlock->FullIPCHeader.Header.Flags & IPC_FLAG_INITIALIZED) != IPC_FLAG_INITIALIZED)
        {
            goto CleanupExit;
        }

        // Check the IPCControlBlock version is valid.
        if (legacyPrivateBlock->FullIPCHeader.Header.Version > VER_LEGACYPRIVATE_IPC_BLOCK)
        {
            goto CleanupExit;
        }

        appDomainsList = EnumerateAppDomainIpcBlock(
            ProcessHandle,
            appDomainEnumBlock
            );
    }

CleanupExit:

    if (ipcControlBlockTable)
    {
        NtUnmapViewOfSection(NtCurrentProcess(), ipcControlBlockTable);
    }

    if (legacyPrivateBlockHandle)
    {
        NtClose(legacyPrivateBlockHandle);
    }

    return appDomainsList;
}
示例#11
0
BOOLEAN OpenDotNetPublicControlBlock_V4(
    _In_ BOOLEAN IsImmersive,
    _In_ HANDLE ProcessHandle,
    _In_ HANDLE ProcessId,
    _Out_ HANDLE* BlockTableHandle,
    _Out_ PVOID* BlockTableAddress
    )
{
    BOOLEAN result = FALSE;
    PVOID boundaryDescriptorHandle = NULL;
    HANDLE privateNamespaceHandle = NULL;
    HANDLE blockTableHandle = NULL;
    HANDLE tokenHandle = NULL;
    PSID everyoneSIDHandle = NULL;
    PVOID blockTableAddress = NULL;
    LARGE_INTEGER sectionOffset = { 0 };
    SIZE_T viewSize = 0;
    UNICODE_STRING prefixNameUs;
    UNICODE_STRING sectionNameUs;
    UNICODE_STRING boundaryNameUs;
    OBJECT_ATTRIBUTES namespaceObjectAttributes;
    OBJECT_ATTRIBUTES sectionObjectAttributes;
    PTOKEN_APPCONTAINER_INFORMATION appContainerInfo = NULL;
    SID_IDENTIFIER_AUTHORITY SIDWorldAuth = SECURITY_WORLD_SID_AUTHORITY;

    if (!PhStringRefToUnicodeString(&GenerateBoundaryDescriptorName(ProcessId)->sr, &boundaryNameUs))
        goto CleanupExit;

    if (!(boundaryDescriptorHandle = RtlCreateBoundaryDescriptor(&boundaryNameUs, 0)))
        goto CleanupExit;

    if (!NT_SUCCESS(RtlAllocateAndInitializeSid(&SIDWorldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &everyoneSIDHandle)))
        goto CleanupExit;

    if (!NT_SUCCESS(RtlAddSIDToBoundaryDescriptor(&boundaryDescriptorHandle, everyoneSIDHandle)))
        goto CleanupExit;

    if (WINDOWS_HAS_IMMERSIVE && IsImmersive)
    {
        if (NT_SUCCESS(NtOpenProcessToken(&tokenHandle, TOKEN_QUERY, ProcessHandle)))
        {
            ULONG returnLength = 0;

            if (NtQueryInformationToken(
                tokenHandle,
                TokenAppContainerSid,
                NULL,
                0,
                &returnLength
                ) != STATUS_BUFFER_TOO_SMALL)
            {
                goto CleanupExit;
            }

            appContainerInfo = PhAllocate(returnLength);

            if (!NT_SUCCESS(NtQueryInformationToken(
                tokenHandle,
                TokenAppContainerSid,
                appContainerInfo,
                returnLength,
                &returnLength
                )))
            {
                goto CleanupExit;
            }

            if (!NT_SUCCESS(RtlAddSIDToBoundaryDescriptor(&boundaryDescriptorHandle, appContainerInfo->TokenAppContainer)))
                goto CleanupExit;
        }
    }

    RtlInitUnicodeString(&prefixNameUs, CorSxSReaderPrivateNamespacePrefix);
    InitializeObjectAttributes(
        &namespaceObjectAttributes,
        &prefixNameUs,
        OBJ_CASE_INSENSITIVE,
        boundaryDescriptorHandle,
        NULL
        );

    if (!NT_SUCCESS(NtOpenPrivateNamespace(
        &privateNamespaceHandle,
        MAXIMUM_ALLOWED,
        &namespaceObjectAttributes,
        boundaryDescriptorHandle
        )))
    {
        goto CleanupExit;
    }

    RtlInitUnicodeString(&sectionNameUs, CorSxSVistaPublicIPCBlock);
    InitializeObjectAttributes(
        &sectionObjectAttributes,
        &sectionNameUs,
        OBJ_CASE_INSENSITIVE,
        privateNamespaceHandle,
        NULL
        );

    if (!NT_SUCCESS(NtOpenSection(
        &blockTableHandle,
        SECTION_MAP_READ,
        &sectionObjectAttributes
        )))
    {
        goto CleanupExit;
    }

    if (!NT_SUCCESS(NtMapViewOfSection(
        blockTableHandle,
        NtCurrentProcess(),
        &blockTableAddress,
        0,
        viewSize,
        &sectionOffset,
        &viewSize,
        ViewShare,
        0,
        PAGE_READONLY
        )))
    {
        goto CleanupExit;
    }

    *BlockTableHandle = blockTableHandle;
    *BlockTableAddress = blockTableAddress;

    result = TRUE;

CleanupExit:

    if (!result)
    {
        if (blockTableHandle)
        {
            NtClose(blockTableHandle);
        }

        if (blockTableAddress)
        {
            NtUnmapViewOfSection(NtCurrentProcess(), blockTableAddress);
        }

        *BlockTableHandle = NULL;
        *BlockTableAddress = NULL;
    }

    if (tokenHandle)
    {
        NtClose(tokenHandle);
    }

    if (appContainerInfo)
    {
        PhFree(appContainerInfo);
    }

    if (privateNamespaceHandle)
    {
        NtClose(privateNamespaceHandle);
    }

    if (everyoneSIDHandle)
    {
        RtlFreeSid(everyoneSIDHandle);
    }

    if (boundaryDescriptorHandle)
    {
        RtlDeleteBoundaryDescriptor(boundaryDescriptorHandle);
    }

    return result;
}
示例#12
0
BOOLEAN OpenDotNetPublicControlBlock_V2(
    _In_ HANDLE ProcessId,
    _Out_ HANDLE* BlockTableHandle,
    _Out_ PVOID* BlockTableAddress
    )
{
    BOOLEAN result = FALSE;
    HANDLE blockTableHandle = NULL;
    PVOID blockTableAddress = NULL;
    UNICODE_STRING sectionNameUs;
    OBJECT_ATTRIBUTES objectAttributes;
    LARGE_INTEGER sectionOffset = { 0 };
    SIZE_T viewSize = 0;

    if (!PhStringRefToUnicodeString(&GenerateLegacyPublicName(ProcessId)->sr, &sectionNameUs))
        return FALSE;

    InitializeObjectAttributes(
        &objectAttributes,
        &sectionNameUs,
        OBJ_CASE_INSENSITIVE,
        NULL,
        NULL
        );

    if (!NT_SUCCESS(NtOpenSection(
        &blockTableHandle,
        SECTION_MAP_READ,
        &objectAttributes
        )))
    {
        return FALSE;
    }

    if (NT_SUCCESS(NtMapViewOfSection(
        blockTableHandle,
        NtCurrentProcess(),
        &blockTableAddress,
        0,
        viewSize,
        &sectionOffset,
        &viewSize,
        ViewShare,
        0,
        PAGE_READONLY
        )))
    {
        *BlockTableHandle = blockTableHandle;
        *BlockTableAddress = blockTableAddress;

        return TRUE;
    }

    if (blockTableHandle)
        NtClose(blockTableHandle);

    if (blockTableAddress)
        NtUnmapViewOfSection(NtCurrentProcess(), blockTableAddress);

    return FALSE;
}
示例#13
0
PPH_LIST QueryDotNetAppDomainsForPid_V2(
    _In_ BOOLEAN Wow64,
    _In_ HANDLE ProcessHandle,
    _In_ HANDLE ProcessId
    )
{
    LARGE_INTEGER sectionOffset = { 0 };
    SIZE_T viewSize = 0;
    OBJECT_ATTRIBUTES objectAttributes;
    UNICODE_STRING sectionNameUs;
    HANDLE legacyPrivateBlockHandle = NULL;
    PVOID ipcControlBlockTable = NULL;
    PPH_LIST appDomainsList = NULL;

    __try
    {
        if (!PhStringRefToUnicodeString(&GeneratePrivateName(ProcessId)->sr, &sectionNameUs))
            __leave;

        InitializeObjectAttributes(
            &objectAttributes,
            &sectionNameUs,
            0,
            NULL,
            NULL
            );

        if (!NT_SUCCESS(NtOpenSection(
            &legacyPrivateBlockHandle,
            SECTION_MAP_READ,
            &objectAttributes
            )))
        {
            __leave;
        }

        if (!NT_SUCCESS(NtMapViewOfSection(
            legacyPrivateBlockHandle,
            NtCurrentProcess(),
            &ipcControlBlockTable,
            0,
            viewSize,
            &sectionOffset,
            &viewSize,
            ViewShare,
            0,
            PAGE_READONLY
            )))
        {
            __leave;
        }

        if (Wow64)
        {
            LegacyPrivateIPCControlBlock_Wow64* legacyPrivateBlock;
            AppDomainEnumerationIPCBlock_Wow64* appDomainEnumBlock;

            legacyPrivateBlock = (LegacyPrivateIPCControlBlock_Wow64*)ipcControlBlockTable;

            // NOTE: .NET 2.0 processes do not have the IPC_FLAG_INITIALIZED flag.

            // Check the IPCControlBlock version is valid.
            if (legacyPrivateBlock->FullIPCHeader.Header.Version > VER_LEGACYPRIVATE_IPC_BLOCK)
            {
                __leave;
            }

            appDomainEnumBlock = GetLegacyBlockTableEntry(
                Wow64,
                ipcControlBlockTable,
                eLegacyPrivateIPC_AppDomain
                );

            appDomainsList = EnumerateAppDomainIpcBlockWow64(
                ProcessHandle,
                appDomainEnumBlock
                );
        }
        else
        {
            LegacyPrivateIPCControlBlock* legacyPrivateBlock;
            AppDomainEnumerationIPCBlock* appDomainEnumBlock;

            legacyPrivateBlock = (LegacyPrivateIPCControlBlock*)ipcControlBlockTable;

            // NOTE: .NET 2.0 processes do not have the IPC_FLAG_INITIALIZED flag.

            // Check the IPCControlBlock version is valid.
            if (legacyPrivateBlock->FullIPCHeader.Header.Version > VER_LEGACYPRIVATE_IPC_BLOCK)
            {
                __leave;
            }

            appDomainEnumBlock = GetLegacyBlockTableEntry(
                Wow64,
                ipcControlBlockTable,
                eLegacyPrivateIPC_AppDomain
                );

            appDomainsList = EnumerateAppDomainIpcBlock(
                ProcessHandle,
                appDomainEnumBlock
                );
        }
    }
    __finally
    {
        if (ipcControlBlockTable)
        {
            NtUnmapViewOfSection(NtCurrentProcess(), ipcControlBlockTable);
        }

        if (legacyPrivateBlockHandle)
        {
            NtClose(legacyPrivateBlockHandle);
        }
    }

    return appDomainsList;
}