Geoff Chappell, Software Analyst
The RtlInitUnicodeStringEx function initialises a UNICODE_STRING structure as describing a given null-terminated Unicode string.
NTSTATUS RtlInitUnicodeStringEx ( UNICODE_STRING *DestinationString, PCWSTR SourceString);
The required DestinationString argument provides the address of a UNICODE_STRING structure that the function is to initialise.
The optional SourceString argument is the address of a null-terminated Unicode string that is to be represented by the structure. This argument can be NULL to initialise the structure as representing no string.
The function returns STATUS_SUCCESS if successful, else a negative error code.
The RtlInitUnicodeStringEx function is exported by name from the kernel in version 5.2 and higher. It is older in user mode, being exported by name from NTDLL in version 5.1 and higher.
The RtlInitUnicodeStringEx function is not documented.
A C-language declaration is published in NTIFS.H from the Windows Driver Kit (WDK) since at least Windows Vista. Whether this declaration originated in an earlier Installable File System (IFS) Kit is not known, no such kit having been obtained for inspection. The declaration is guarded by conditional compilation that requires Windows XP and higher. This is the user-mode availability, even though NTIFS.H is ostensibly for kernel-mode programming.
What is documented is a routine named WdmlibRtlInitUnicodeStringEx from a statically linked library named WDMSEC.LIB. This routine has the same code as the exported function. Supplying it as a library routine had the merit of making it available to new drivers that find themselves running on old Windows versions that do not export the function. The library seems to have been distributed first with the Device Driver Kit (DDK) for Windows XP, including to provide for its use when developing drivers for Windows 2000. Though the routine is nowadays documented by Microsoft as “Available starting with Windows 2000”, it certainly was not available in the DDK for Windows 2000.
Even this documentation, i.e., of the WdmlibRtlInitUnicodeStringEx routine, looks to be very recent. The only date on it as observed online today, 17th March 2019, is 29th April 2018. It is not known in any DDK or WDK that Microsoft supplied with documentation files for offline reference. Neither is it known in any of the downloadable documentation packages for Visual Studio up to and including Visual Studio 2017. It seems fair to say at the very least that Microsoft did not trouble to make the documentation prominent. This seems important to stress because the function and the library routine surely have no reason for existence except to deal with a serious defect of the older, documented RtlInitUnicodeString. But what is the point to an improvement if it’s then kept quiet?
The only functional difference between RtlInitUnicodeStringEx and the older RtlInitUnicodeString is to make an error of a case for which the latter is defective. Microsoft’s own kernel-mode programming makes extensive use of RtlInitUnicodeStringEx as if superseding RtlInitUnicodeString.
The intention of the UNICODE_STRING structure is to keep together both the address and size of a Unicode string, presumably to save on passing them as separate arguments for subsequent work with the string and to save on repeated re-reading of the whole string to rediscover its size. Indeed, the structure keeps two sizes. The Length member is the size in bytes of the array of Unicode characters at Buffer. If this array is null-terminated, which it explicitly need not be, then Length does not count the null terminator. The MaximumLength member is the size in bytes of the memory from Buffer onwards.
The RtlInitUnicodeString function initialises a UNICODE_STRING so that it describes a buffer that contains exactly the given null-terminated Unicode string. Microsoft’s names DestinationString and SourceString for the function’s arguments are unfortunate for suggesting some sort of data transfer. No source string is copied, only its address.
If the SourceString argument is NULL, the DestinationString gets a minimal initialisation to represent nothing: Length and MaximumLength are zero and Buffer is NULL. Ordinarily, SourceString is not NULL, and DestinationString gets initialised such that Length and MaximumLength are respectively the sizes in bytes of the string not counting and counting its null terminator, and Buffer is the string’s address as given.
If, however, the given string has more than 0x7FFE characters, not counting its null terminator, it is too long to be represented faithfully by the 16-bit Length and MaximumLength, and so the function fails, returning STATUS_NAME_TOO_LONG.
It is unclear what is intended for the DestinationString when the function fails. The original implementation leaves it untouched. Microsoft’s usual practice seems anyway to be that failure leaves a function’s outputs undefined. Yet a small reworking for version 6.0 looks to have as its one effect that the function’s failure leaves the DestinationString with Buffer pointing to the SourceString but with zero for both the Length and MaximumLength.
Provided that both the UNICODE_STRING and the Unicode string that are addressed through the given arguments are in non-paged memory, the RtlnitUnicodeStringEx function can safely be called even at DISPATCH_LEVEL.
If only for now, documentation errors can only be in what Microsoft says of the function’s parallel implementation as the WdmlibRtlInitUnicodeStringEx library routine. If only as this documentation shows today, 17th March 2019, as WmdlibRtlInitUnicodeStringEx function (wdmsec.h) - Windows drivers | Microsoft Docs, it has a highlighted box whose primary effect on readers may be to encourage a realisation that the documentation has been cobbled together in haste:
Note If the source string is longer than MAX_USTRING - 1 bytes, WdmlibRtlInitUnicodeStringEx sets the Length member of the UNICODE_STRING structure pointed to by DestinationString to MAX_USTRING - 2, and sets the MaximumLength member of this structure to MAX_USTRING. In this case, the Length and MaximumLength values misrepresent the length of the null-terminated source string, and relying on the accuracy of these values is potentially dangerous.
Leave aside that no MAX_USTRING is defined in any header in a publicly distributed WDK or SDK and that even Google knows nearly nothing of it except from what appears to be leaked Microsoft source code. What Microsoft describes in this box is not what WdmlibRtlInitUnicodeStringEx does but what it exists to correct! Change WdmlibRtlInitUnicodeStringEx (back) to RtlInitUnicodeString and you have a very apt warning to include with documentation of RtlInitUnicodeString.