Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation\TimeZoneKeyName corrupt?

I'm trying to determine the current time zone for a Windows system. The following code snippet is (loosely) based on the answer by @MattJohnson on this thread: Getting local timezone identifier when OS display language is non-english

    using (RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(
                                   @"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"))
    {
       if (registryKey != null)
       {
          string windowsTimeZoneId = registryKey.GetValue("TimeZoneKeyName") as string;
          if (string.IsNullOrEmpty(windowsTimeZoneId))
             windowsTimeZoneId = registryKey.GetValue("StandardName") as string;
          if (!string.IsNullOrEmpty(windowsTimeZoneId))
          {
             int i = windowsTimeZoneId.IndexOf('\0');
             if (i != -1)
                windowsTimeZoneId = windowsTimeZoneId.Remove(i);
             return ConvertFromWindowsId(windowsTimeZoneId);
          }
       }
    }

If I place a breakpoint on the first line "if (string.IsNullOrEmpty(windowsTimeZoneId))", then this is what I see in Visual Studio debugger:

enter image description here

What is going on here? RegistryKey.GetValue() is returning a boxed string, but why does it not detect the two hex 00 bytes and terminate the string there?

So far I've tested this on two of my PCs. This is from one that runs Windows 7 64-bit. The other one, running Windows 7 32-bit, is the same except that it says that the length of the returned string is 128 characters instead of 127.

When looking at the registry entry with regedit.exe it looks fine, showing only "Romance Standard Time".

A bit of Googling turned up this question https://social.msdn.microsoft.com/Forums/sqlserver/en-US/eca7ad76-c910-46be-8fb9-876c7cde5c69/registry-read-time-zone-info-differ-when-code-build-on-40-framework-on-host-system-win-7-64-bit?forum=csharpgeneral Otherwise I can't find anything.

The program is being built with Visual Studio 2012, and targeting .Net 2.0.

As you can see, I've added code to take this "corrupt" result into account, but still I'd appreciate it if someone could explain to me what is going on here, and maybe even how to avoid the whole problem.

EDIT:

The program is being built with Visual Studio 2012, and targeting .Net 2.0.

Hmm, the plot thickens. That statement was not totally correct. The stump of code shown above is in a library assembly that is built to target .Net 2.0, but it was being called from a program that targeted .Net 4.0. Now I've tried calling it from a program that targets .Net 2.0, and there is no problem, RegistryKey.GetValue() simply returns "Romance Standard Time". So it appears that it does have something to do with .Net Framework 4.0, as implied by the posting on MSDN.

EDIT 2 - beginning to think that this is "normal"

This is a bit off-topic for SO, but I'd appreciate it if someone would take a look at my related posting over at Superuser.com, since I'm not getting instant gratification there, and I'd like to get this resolved so I know whether I should still be panicking or not. Thanks.

https://superuser.com/questions/859031/possible-malware-modification-of-windows-registry-entry

like image 930
RenniePet Avatar asked Nov 01 '22 12:11

RenniePet


1 Answers

When a string or multi-string value is set in the registry, Windows does not check the semantics; it simply stores whatever binary content is provided, with the length specified by the programmer. This means that a string can be prematurely null-terminated, or conversely, not null-terminated at all. (This does have security implications, by the way: while I don't think premature null termination is likely to pose a risk, native code that fails to handle the case where the string is not null-terminated might.)

According to Hans (in his deleted answer) versions of .NET prior to 4.x would ignore the extra data if the string is prematurely null-terminated, whereas 4.x includes it. So that's why you only noticed the problem once you started using 4.x.

As for why this particular value is prematurely null-terminated, that appears to be carelessness on Microsoft's part. If you remove the extra data, and then change the timezone, the extra data reappears. So it appears to be Windows itself that is doing this. The data looks random to me, so I don't believe it is intentional. In fact, this may technically constitute a data exposure vulnerability, though there is probably no practical impact.

I suggest you search for a null and truncate the string if necessary. There might be situations in which there isn't one, e.g., if the entry has been modified by third-party code, or if MS eventually issues an update and fixes the problem, or, of course, if you're running in .NET 2.x. So you'll need to handle both cases.

(If I have time, when I go back to work next week I'll install a clean copy of Windows on a virtual machine and confirm that the issue exists with absolutely no third-party software present. If so, I'll consider reporting it - I doubt MS will issue a patch, but it might get fixed in a future version of Windows.)

like image 89
Harry Johnston Avatar answered Nov 09 '22 09:11

Harry Johnston