RtlAppendPathElement

Go to Home Page

Appends part of a path onto a stem. Essentially a ntdll version of PathAppend.

Syntax

NTSTATUS WINAPI RtlAppendPathElement (
    ULONG flags,
    PRTL_UNICODE_STRING_BUFFER pStrBuffer,
    PCUNICODE_STRING pAddend
)

Parameters

flags
Bit flags that determine the type of slash used to separate the path parts if neither the end of pStrBuffer or the start of pAddend have either type of slash. This can be none, one, or both of these:
RTL_APE_IGNORE_FORWARD_SLASHES (0x1)
Forces a backslash. This flag also suppresses trailing forward slashes from being added to the end
RTL_APE_USE_FIRST_SLASH (0x2)
Checks the firsts three characters of pStrBuffer for a slash. If one is found, that kind is used as the separator. If not, the default (backslash) is used
pStrBuffer
The dynamic buffer that contains the first portion of the path, and on exit receives the newly appended path
pAddend
The portion of the path to append

Return Value

STATUS_SUCCESS if all went well, standard NTSTATUS error code otherwise

Remarks

The first part of the path must be in the dynamic buffer portion of pStrBuffer. Use RtlpEnsureBufferSize to allocate and size the dynamic portion, (see below for an example).

The function uses RtlMultiAppendUnicodeStringBuffer to do the concatenation which automatically resizes the dynamic buffer to hold the full string.

If pStrBuffer has a trailing slash it will be preserved onto the end of the result, regardless of whether pAddend has a trailing slash or not. This behaviour can be suppressed if the trailing slash is a forward one by specifying RTL_APE_IGNORE_FORWARD_SLASHES.

The definition of RTL_UNICODE_STRING_BUFFER is:

typedef struct _RTL_BUFFER 
{
    PUCHAR Buffer;
    PUCHAR StaticBuffer;
    SIZE_T Size;
    SIZE_T StaticSize;
    SIZE_T ReservedForAllocatedSize;
    PVOID ReservedForIMalloc;
} RTL_BUFFER, *PRTL_BUFFER;

typedef struct _RTL_UNICODE_STRING_BUFFER
{  
    UNICODE_STRING String; 
    RTL_BUFFER ByteBuffer; 
    UCHAR MinimumStaticBufferForTerminalNul[sizeof(WCHAR)];
} RTL_UNICODE_STRING_BUFFER, *PRTL_UNICODE_STRING_BUFFER;

Example

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winternl.h>
#include <stdio.h>

typedef struct _RTL_BUFFER 
{
    PUCHAR Buffer;
    PUCHAR StaticBuffer;
    SIZE_T Size;
    SIZE_T StaticSize;
    SIZE_T ReservedForAllocatedSize;
    PVOID ReservedForIMalloc;
} RTL_BUFFER, *PRTL_BUFFER;

typedef struct _RTL_UNICODE_STRING_BUFFER
{  
    UNICODE_STRING String; 
    RTL_BUFFER ByteBuffer; 
    UCHAR MinimumStaticBufferForTerminalNul[sizeof(WCHAR)];
} RTL_UNICODE_STRING_BUFFER, *PRTL_UNICODE_STRING_BUFFER;

typedef NTSTATUS (NTAPI*pfnRtlAppendPathElement)(ULONG, PRTL_UNICODE_STRING_BUFFER, PCUNICODE_STRING);

int main()
{
WCHAR strings[][50] = {
        L".\\Windows\\System32",
        L".\\Windows\\System32\\",
        L"./Windows/System32",
        L"./Windows/System32/",
        L"./Windows\\System32",
        L"./Windows\\System32/",
        L"C:/program files/microsoft",
        L"C:/program files/microsoft/",
        L"C:\\",
        L"C:/",
        L"C:",
        L"\\\\?\\Z:/MyPath",
        L"\\??\\pipe\\",
        L"\\??\\pipe/",
        L"\\??\\UNC\\server\\share",
        L"\\??\\UNC\\server\\share/",
        L"folder",
        L"folder/",
        L"folder\\"
    };
    HMODULE hNt = GetModuleHandle(L"ntdll.dll");
    pfnRtlAppendPathElement rtlAppendPathElement = (pfnRtlAppendPathElement)GetProcAddress(hNt, "RtlAppendPathElement");
    UNICODE_STRING addend;
    RtlInitUnicodeString(&addend, L"kernel32.dll");
    for(int i = 0; i < ARRAYSIZE(strings); ++i)
    {
        wprintf(L"Appending \"%wZ\" to \"%s\":\n", &addend, strings[i]);
        for(ULONG rtpeFlags = 0; rtpeFlags < 4; ++rtpeFlags) // flags of 0, 1, and 2 are valid
        {
            RTL_UNICODE_STRING_BUFFER strBuffer = {0};
            RtlpEnsureBufferSize(0, &strBuffer.ByteBuffer, sizeof(strings[i]));
            memcpy(strBuffer.ByteBuffer.Buffer, strings[i], sizeof(strings[i]));
            RtlInitUnicodeString(&strBuffer.String, (PWCHAR)strBuffer.ByteBuffer.Buffer);
            rtlAppendPathElement(rtpeFlags, &strBuffer, &addend);
            wprintf(L"%i%c: flags %#x, \"%wZ\"\n", i + 1, L'a' + rtpeFlags, rtpeFlags, &strBuffer.String);
            RtlFreeUnicodeString(&strBuffer.String);
        }
        _putws(L"");
    }
    return 0;
}
OUTPUT
------
Appending "kernel32.dll" to ".\Windows\System32":
1a: flags 0, ".\Windows\System32.kernel32.dll"
1b: flags 0x1, ".\Windows\System32\kernel32.dll"
1c: flags 0x2, ".\Windows\System32\kernel32.dll"
1d: flags 0x3, ".\Windows\System32\kernel32.dll"

Appending "kernel32.dll" to ".\Windows\System32\":
2a: flags 0, ".\Windows\System32\kernel32.dll\"
2b: flags 0x1, ".\Windows\System32\kernel32.dll\"
2c: flags 0x2, ".\Windows\System32\kernel32.dll\"
2d: flags 0x3, ".\Windows\System32\kernel32.dll\"

Appending "kernel32.dll" to "./Windows/System32":
3a: flags 0, "./Windows/System32.kernel32.dll"
3b: flags 0x1, "./Windows/System32\kernel32.dll"
3c: flags 0x2, "./Windows/System32/kernel32.dll"
3d: flags 0x3, "./Windows/System32\kernel32.dll"

Appending "kernel32.dll" to "./Windows/System32/":
4a: flags 0, "./Windows/System32/kernel32.dll/"
4b: flags 0x1, "./Windows/System32/\kernel32.dll"
4c: flags 0x2, "./Windows/System32/kernel32.dll/"
4d: flags 0x3, "./Windows/System32/\kernel32.dll"

Appending "kernel32.dll" to "./Windows\System32":
5a: flags 0, "./Windows\System32.kernel32.dll"
5b: flags 0x1, "./Windows\System32\kernel32.dll"
5c: flags 0x2, "./Windows\System32/kernel32.dll"
5d: flags 0x3, "./Windows\System32\kernel32.dll"

Appending "kernel32.dll" to "./Windows\System32/":
6a: flags 0, "./Windows\System32/kernel32.dll/"
6b: flags 0x1, "./Windows\System32/\kernel32.dll"
6c: flags 0x2, "./Windows\System32/kernel32.dll/"
6d: flags 0x3, "./Windows\System32/\kernel32.dll"

Appending "kernel32.dll" to "C:/program files/microsoft":
7a: flags 0, "C:/program files/microsoftCkernel32.dll"
7b: flags 0x1, "C:/program files/microsoft\kernel32.dll"
7c: flags 0x2, "C:/program files/microsoft/kernel32.dll"
7d: flags 0x3, "C:/program files/microsoft\kernel32.dll"

Appending "kernel32.dll" to "C:/program files/microsoft/":
8a: flags 0, "C:/program files/microsoft/kernel32.dll/"
8b: flags 0x1, "C:/program files/microsoft/\kernel32.dll"
8c: flags 0x2, "C:/program files/microsoft/kernel32.dll/"
8d: flags 0x3, "C:/program files/microsoft/\kernel32.dll"

Appending "kernel32.dll" to "C:\":
9a: flags 0, "C:\kernel32.dll\"
9b: flags 0x1, "C:\kernel32.dll\"
9c: flags 0x2, "C:\kernel32.dll\"
9d: flags 0x3, "C:\kernel32.dll\"

Appending "kernel32.dll" to "C:/":
10a: flags 0, "C:/kernel32.dll/"
10b: flags 0x1, "C:/\kernel32.dll"
10c: flags 0x2, "C:/kernel32.dll/"
10d: flags 0x3, "C:/\kernel32.dll"

Appending "kernel32.dll" to "C:":
11a: flags 0, "C:\kernel32.dll"
11b: flags 0x1, "C:\kernel32.dll"
11c: flags 0x2, "C:\kernel32.dll"
11d: flags 0x3, "C:\kernel32.dll"

Appending "kernel32.dll" to "\\?\Z:/MyPath":
12a: flags 0, "\\?\Z:/MyPath\kernel32.dll"
12b: flags 0x1, "\\?\Z:/MyPath\kernel32.dll"
12c: flags 0x2, "\\?\Z:/MyPath\kernel32.dll"
12d: flags 0x3, "\\?\Z:/MyPath\kernel32.dll"

Appending "kernel32.dll" to "\??\pipe\":
13a: flags 0, "\??\pipe\kernel32.dll\"
13b: flags 0x1, "\??\pipe\kernel32.dll\"
13c: flags 0x2, "\??\pipe\kernel32.dll\"
13d: flags 0x3, "\??\pipe\kernel32.dll\"

Appending "kernel32.dll" to "\??\pipe/":
14a: flags 0, "\??\pipe/kernel32.dll/"
14b: flags 0x1, "\??\pipe/\kernel32.dll"
14c: flags 0x2, "\??\pipe/kernel32.dll/"
14d: flags 0x3, "\??\pipe/\kernel32.dll"

Appending "kernel32.dll" to "\??\UNC\server\share":
15a: flags 0, "\??\UNC\server\share\kernel32.dll"
15b: flags 0x1, "\??\UNC\server\share\kernel32.dll"
15c: flags 0x2, "\??\UNC\server\share\kernel32.dll"
15d: flags 0x3, "\??\UNC\server\share\kernel32.dll"

Appending "kernel32.dll" to "\??\UNC\server\share/":
16a: flags 0, "\??\UNC\server\share/kernel32.dll/"
16b: flags 0x1, "\??\UNC\server\share/\kernel32.dll"
16c: flags 0x2, "\??\UNC\server\share/kernel32.dll/"
16d: flags 0x3, "\??\UNC\server\share/\kernel32.dll"

Appending "kernel32.dll" to "folder":
17a: flags 0, "folder\kernel32.dll"
17b: flags 0x1, "folder\kernel32.dll"
17c: flags 0x2, "folder\kernel32.dll"
17d: flags 0x3, "folder\kernel32.dll"

Appending "kernel32.dll" to "folder/":
18a: flags 0, "folder/kernel32.dll/"
18b: flags 0x1, "folder/\kernel32.dll"
18c: flags 0x2, "folder/kernel32.dll/"
18d: flags 0x3, "folder/\kernel32.dll"

Appending "kernel32.dll" to "folder\":
19a: flags 0, "folder\kernel32.dll\"
19b: flags 0x1, "folder\kernel32.dll\"
19c: flags 0x2, "folder\kernel32.dll\"
19d: flags 0x3, "folder\kernel32.dll\"