{"id":38063,"date":"2004-08-24T06:58:00","date_gmt":"2004-08-24T06:58:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2004\/08\/24\/beware-of-non-null-terminated-registry-strings\/"},"modified":"2004-08-24T06:58:00","modified_gmt":"2004-08-24T06:58:00","slug":"beware-of-non-null-terminated-registry-strings","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040824-00\/?p=38063","title":{"rendered":"Beware of non-null-terminated registry strings"},"content":{"rendered":"<p>\nEven though a value is stored in the registry as REG_SZ,\nthis doesn&#8217;t mean that the value actually ends with a proper\nnull terminator.  At the bottom, the registry is just a\nhierarchically-organized name\/value database.\n<\/p>\n<p>\nAnd you can lie and get away with it.\n<\/p>\n<p>\nLots of people lie about their registry data.\nYou&#8217;ll find lots of things that should be REG_DWORD\nstored as a four-byte REG_BINARY.\n(This is in part a holdover from Windows&nbsp;95&#8217;s\nregistry, which didn&#8217;t support REG_DWORD.)\n<\/p>\n<p>\nOne of the most insidious lies is to lie about the length of\na string you&#8217;re writing to the registry.\nConsider the following program:\n<\/p>\n<pre>\n#include &lt;windows.h&gt;\n#include &lt;stdio.h&gt;\nint __cdecl main(int argc, char **argv)\n{\n    RegSetValueExW(HKEY_CURRENT_USER, L\"Scratch\",\n                   0, REG_SZ, (BYTE*)L\"12\", 2);\n    DWORD cb = 0;\n    RegQueryValueExW(HKEY_CURRENT_USER, L\"Scratch\",\n                     NULL, NULL, NULL, &amp;cb);\n    printf(\"Size is %d bytes\\n\", cb);\n    WCHAR sz[2];\n    sz[0] = 0xFFFF;\n    sz[1] = 0xFFFF;\n    cb = sizeof(sz[0]);\n    DWORD dwRc = RegQueryValueExW(HKEY_CURRENT_USER, L\"Scratch\",\n                                  NULL, NULL, (BYTE*)sz, &amp;cb);\n    printf(\"RegQueryValueExW requesting %d bytes =&gt; %d\\n\",\n           sizeof(sz), dwRc);\n    printf(\"%d bytes required\\n\", cb);\n    if (dwRc == ERROR_SUCCESS) {\n        printf(\"sz[0] = %d\\n\", sz[0]);\n        printf(\"sz[1] = %d\\n\", sz[1]);\n    }\n    RegDeleteValueW(HKEY_CURRENT_USER, L\"Scratch\");\n    return 0;\n}\n<\/pre>\n<p>\nIf you run this program, you get this:\n<\/p>\n<pre>\nSize is 2 bytes\nRegQueryValueExW requesting 4 bytes =&gt; 0\n2 bytes required\nsz[0] = 49\nsz[1] = 65535\n<\/pre>\n<p>\nWhat happened?\n<\/p>\n<p>\nFirst, observe that the call to RegSetValueExW lies about the length\nof the string, claiming that it is two bytes long when in fact\nit is six!  (Two WCHARs plus a terminator.)\n<\/p>\n<p>\nThe registry dutifully records this lie and reports it back\nto subsequent callers.\n<\/p>\n<p>\nThe first call to RegQueryValueExW asks how big the string is,\nand the registry reports the value 2, since that&#8217;s the value it\nwas given when the value was originally stored.\n<\/p>\n<p>\nTo show that there really is no null terminator, we ask the\nregistry to read those two bytes of data into our buffer,\npre-filling the buffer with sentinel values so we can see\nwhat got updated and what didn&#8217;t.\n<\/p>\n<p>\nLo and behold, the values were read from the registry and\nonly two bytes were read.  sz[0] contains the character &#8216;1&#8217;,\nand sz[1] remains uninitialized.\n<\/p>\n<p>\n<strong>This has security implications<\/strong>.\n<\/p>\n<p>\nIf your program assumes that strings in the registry are always\nnull-terminated, then you can be tricked into a buffer overflow\nif you happen across a non-null-terminated string.\n(For example, if you use <code>strcpy<\/code> to copy it around.)\n<\/p>\n<p>\n(Note: I&#8217;m not going to get into whether it should have been\npossible to get into this state in the first place.\n<a HREF=\"\/oldnewthing\/archive\/2003\/08\/08\/54618.aspx\">\nI didn&#8217;t design the registry<\/a>.\nArguing about the past isn&#8217;t going to change the present,\nand the present is that this is how it works so you&#8217;d better\nbe ready for it.)\n<\/p>\n<p>\n<b>Exercise<\/b>: Change the last parameter of\nRegSetValueExW to 3 and run the program again.\nExplain the results and discuss its consequences.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Even though a value is stored in the registry as REG_SZ, this doesn&#8217;t mean that the value actually ends with a proper null terminator. At the bottom, the registry is just a hierarchically-organized name\/value database. And you can lie and get away with it. Lots of people lie about their registry data. You&#8217;ll find lots [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-38063","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Even though a value is stored in the registry as REG_SZ, this doesn&#8217;t mean that the value actually ends with a proper null terminator. At the bottom, the registry is just a hierarchically-organized name\/value database. And you can lie and get away with it. Lots of people lie about their registry data. You&#8217;ll find lots [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/38063","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=38063"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/38063\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=38063"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=38063"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=38063"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}