Mysterious ExUuidCreate function

I was inspired to write this post after being confused by behaviour of ExUuidCreate function in Windows Vista.

This function is used to generate GUIDs at kernel mode. According to documentation: “ExUuidCreate returns STATUS_SUCCESS if successful; otherwise, if the system is not ready to generate a new UUID, it returns STATUS_RETRY.”

Practically, if you call this function say in driver which is loading by boot loader (if the driver has “Start” registry value equal to 0 due to SERVICE_BOOT_START flag set when creating service using CreateService) you can observe strange behaviour, especially in Vista.

Under strange behaviour I mean the following: function fails, but it actually copies the data into buffer. In other words, function creates GUID although it is failing :) To illustrate this problem, I created a small NT driver which is loading by boot loader (i.e., its “Start” value is set to zero). Driver just calling the function multiple time on a separate thread until the call to ExUuidCreate succeeds.

The thread function is implemented as following:

/**   A thread function which is —Āalling ExUuidCreate(...)    * @param lpParam pointer to user data

* @return always 0x13
*/
VOID PollingThread(unsigned char * lpParam)
{
	KEVENT WaitEvent			= {0};			/// wait object
	BOOLEAN bIsSucceded			= FALSE;		/// is operation succedded
	unsigned char bGUID[16]		= {0};			/// buffer to hold guid
	LARGE_INTEGER liInterval	= {0};			/// timeout buffer
	liInterval.QuadPart			= -10000000;	/// one second wait

	/// init event object
	KeInitializeEvent(&WaitEvent, SynchronizationEvent, FALSE);

	while (!bIsSucceded)
	{
		/// try to obtain guid value
		bIsSucceded = (ExUuidCreate((UUID*)&bGUID) == STATUS_SUCCESS);

		/// if function has failed ...
		if (bIsSucceded == FALSE)
		{
			KdPrint(("The call to ExUuidCreate(...) failed."));

			if (IsEmpty(bGUID))
			{
				KdPrint(("All bytes in GUID are zero. \r\n"));
			}
			else
			{
				KdPrint(("GUID is actually generated: "));

				PrintHexValues(bGUID);
			}
		}
		else
		{
			KdPrint(("The call to ExUuidCreate(...) succeded. Bytes: "));

			PrintHexValues(bGUID);
		}

		/// is used to put thread into sleep state for 1 minute
		KeWaitForSingleObject(&WaitEvent, Executive, KernelMode, TRUE, &liInterval);
	}

	/// exit the thread
	PsTerminateSystemThread(0x13);
}

As you can see, the code is very simple. When being executed in Vista under normal conditions, for example, when the OS is already loaded, the code outputs the following results:

00000000 0.00000000 The call to ExUuidCreate(...) succeded. Bytes:
00000001 0.00029110 20ea90276610dd11bbe2000c291a2f

However, if the machine gets rebooted, one can notice in debugger, that the function ExUuidCreate fails, but the data actually is copied into the buffer:

The most interesting happens if you try to debug this function. Reboot OS in debug mode, attach WinDbg, and wait until loader loads the driver. Wait until the thread PollingThread is created, and the call to ExUuidCreate is done. Turn on Disassembly window in WinDbg, and analyze code: (Standard function prolog which is committing stack and initializes local variables)

819b68d1 8bff            mov     edi,edi
819b68d3 55              push    ebp
819b68d4 8bec            mov     ebp,esp
819b68d6 83e4f8          and     esp,0FFFFFFF8h
819b68d9 83ec14          sub     esp,14h
819b68dc 8364240400      and     dword ptr [esp+4],0
819b68e1 53              push    ebx
819b68e2 56              push    esi
819b68e3 57              push    edi

(Obtaining references to global variable ExpUuidCachedValues and storing them in eax, ecx, ebx)

819b68f0 a140a3b181      mov     eax,dword ptr [nt!ExpUuidCachedValues (81b1a340)]
819b68f5 8b0d4ca3b181    mov     ecx,dword ptr [nt!ExpUuidCachedValues+0xc (81b1a34c)]
819b68fb 8b1d44a3b181    mov     ebx,dword ptr [nt!ExpUuidCachedValues+0x4 (81b1a344)]
819b6901 89442418        mov     dword ptr [esp+18h],eax ss:0010:87304d38=00000008

This part is interesting, more interesting is to answer the question, what is the role of ExpUuidCachedValues in GUID generation process? So lets do more research,

1: kd> db 81b1a340
81b1a340  00 00 00 00 00 00 00 00-ff ff ff ff 00 00 80 6e  ...............n
81b1a350  6f 6e 69 63 00 00 00 00-00 00 00 00 00 00 00 00  onic............
81b1a360  88 ff ff ff c4 ff ff ff-02 00 00 00 00 00 00 01  ................
81b1a370  c4 ff ff ff 40 00 74 00-7a 00 72 00 65 00 73 00  ....@.t.z.r.e.s.
81b1a380  2e 00 64 00 6c 00 6c 00-2c 00 2d 00 33 00 32 00  ..d.l.l.,.-.3.2.
81b1a390  32 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  2...............
81b1a3a0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
81b1a3b0  00 00 00 00 00 00 0a 00-05 00 03 00 00 00 00 00  ................

It seems, that ExpUuidCachedValues is some structure, which holds some values, which are updated by system and are copied into GUID buffer passed by user to ExUuidCreate function; lets continue:

819b6905 8b4508          mov     eax,dword ptr [ebp+8] ss:0010:87304d48=87304d50
819b6908 894808          mov     dword ptr [eax+8],ecx
819b690b 8b0d50a3b181    mov     ecx,dword ptr [nt!ExpUuidCachedValues+0x10 (81b1a350)]
819b6911 89480c          mov     dword ptr [eax+0Ch],ecx

Voila! This piece of code writes into buffer which was passed by user into ExUuidCreate. The write value is stored in ECX, which is pointing to [nt!ExpUuidCachedValues+0xc]. In other words, at the begining the function ExUuidCreate takes some field from ExpUuidCachedValues and writes it down into user buffer without taking care about return value of function. It means, that even if later the function might fail, the content of user buffer is altered already.

Just to prove at this point that the write operation is done into user buffer I output the content of buffer which was passed into ExUuidCreate:

1: kd> db 0x87304d50
87304d50  00 00 00 00 00 00 00 00-85 da 80 6e 00 00 00 00

As you can see, at this moment the buffer is not fully zeroed as it was before. Lets go deeper inside the function. It operates with several global variables, and finally it also touches user buffer:

819b6a27 99              cdq
819b6a28 2bf0            sub     esi,eax
819b6a2a 8b4508          mov     eax,dword ptr [ebp+8]
819b6a2d 1bda            sbb     ebx,edx
819b6a2f 66895804        mov     word ptr [eax+4],bx
819b6a33 c1eb10          shr     ebx,10h
819b6a36 6681e3ff0f      and     bx,0FFFh
819b6a3b 6681cb0010      or      bx,1000h
819b6a40 84c9            test    cl,cl
819b6a42 8930            mov     dword ptr [eax],esi

Now the user buffer looks like:

0: kd> db 0x87304d50
87304d50  79 59 e4 06 8c 43 dd 11-85 da 80 6e 6f 6e 69 63On next iteration: 0: kd> db 0x87304d50
87304d50  7a 59 e4 06 8c 43 dd 11-85 da 80 6e 6f 6e 69 63

Again, on next iteration:

0: kd> db 0x87304d50
87304d50  7d 59 e4 06 8c 43 dd 11-85 da 80 6e 6f 6e 69 63

As if you have mentioned, the first byte is changing all the time. Wonderful, on each call the function gives unique values, although it is failing! Well, I suggest MSFT to documented this behavior, or at least explain this case in documentation. If you would like to repeat this case, please download full sources of the driver here: sources

2 Comments

  1. Pingback: Mysterious ExUuidCreate function - ab origine ...

  2. on Win2k8, in certain cases when IRQL is not PASSIVE_LEVEL, this function returns STATUS_SUCCESS but changes only the first byte. Totally undocumented thing it is, I suspect that floating point operations (which are generally may be not available at certain IRQLs) affect it.

Leave a Reply

Your email address will not be published. Required fields are marked *


1 + two =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>