Geoff Chappell, Software Analyst
The RtlCopyUnicodeString function copies a null-terminated Unicode string to new memory and initialises a UNICODE_STRING to describe the new copy.
BOOLEAN RtlCreateUnicodeString ( UNICODE_STRING *DestinationString, PCWSTR SourceString);
The required DestinationString argument addresses the UNICODE_STRING structure that the successful function initialises. This structure’s contents on input are immaterial.
The required SourceString argument is the address of a null-terminated string of Unicode characters to copy.
The function returns TRUE if successful, else FALSE.
The RtlCreateUnicodeString function is exported by name from the kernel in version 3.51 and higher, and from NTDLL in all known versions, i.e., 3.10 and higher. It is present in earlier versions of the kernel, but only as an internal routine.
The RtlCreateUnicodeString function is documented but has not always been. The first known documentation is from the Installable File System (IFS) Kit for Windows 2000, which was not widely circulated. Though Microsoft’s documentation is of the kernel-mode function as an export from the kernel, it is mostly applicable to the user-mode implementation too, both being plausibly compiled from the same source file.
Starting with the WDK for Windows Vista, Microsoft documents the availability of RtlCreateUnicodeString as “Windows 2000 and later.”
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 RtlCreateUnicodeString function will copy all the characters from SourceString, including the terminating null, to new memory and initialise the structure at DestinationString to describe this new copy.
If the characters to copy amount to more than 0xFFFE bytes or to zero (by overflow), then the string will be too large for description by a UNICODE_STRING, and the function fails. Microsoft defines this limit symbolically as UNICODE_STRING_MAX_BYTES. The function also fails if it cannot obtain this many bytes of memory from the paged pool (with tag 'GrtS') or the process heap in kernel and user modes respectively.
The function copies the characters from SourceString to the new memory and sets the Length, MaximumLength and Buffer members at DestinationString. Occurrence of an exception while copying or while setting some of the members of the UNICODE_STRING is failure for the function.
Defence against exceeding 0xFFFE bytes begins in version 5.2. Defence against copying zero bytes begins in version 6.0. Note that this guarding against overflowing to zero is an example of caution being taken to senseless extreme: it would require that the whole of memory has no more than one word that is zero.
Version 6.0 also introduced the exception handling. It too has some senselessness. The exception handling guards the reading of the source string only while copying it, not earlier to determine the string’s size. Neither is it much use while writing to the structure, since it guards against exceptions while setting the Length and MaximumLength but not the Buffer. Whatever its reason for existence, it’s certainly not robust enough to support the function’s use in kernel mode to capture a string from user-mode address space—and presumably is not intended to be. But what is it good for? Further research would be needed.
The kernel-mode implementation is in paged memory and must not be called at DISPATCH_LEVEL or higher. Microsoft’s documentation explicitly requires PASSIVE_LEVEL.