{"id":107291,"date":"2022-10-17T07:00:00","date_gmt":"2022-10-17T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107291"},"modified":"2022-10-17T06:55:51","modified_gmt":"2022-10-17T13:55:51","slug":"20221017-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20221017-00\/?p=107291","title":{"rendered":"How can I check the integrity level of my process?"},"content":{"rendered":"<p>Integrity levels capture the sense of &#8220;running as a regular Win32 process&#8221;, &#8220;running elevated&#8221;, &#8220;running in a sandbox process&#8221;, that sort of thing. They describe what degree of security enforcement is applied to the process and how protected the process is from other processes.<\/p>\n<p>You can inspect a process&#8217;s integrity level by calling <code>Get\u00adToken\u00adInformation<\/code> and asking for <code>Token\u00adIntegrity\u00adLevel<\/code>. For this trick, I&#8217;m going to use the magic <code>Get\u00adCurrent\u00adProcess\u00adToken()<\/code> function to save me the trouble of hunting down the process token (and then closing it when done). And I&#8217;ll use the <code>wil::<wbr \/>get_<wbr \/>token_<wbr \/>information<\/code> helper function from the <a href=\"https:\/\/github.com\/microsoft\/wil\/\"> Windows Implementation Library<\/a> to do the grunt work of calling <code>Get\u00adToken\u00adInformation<\/code> twice, once to get the buffer size, and again to fill it.<\/p>\n<pre>#include &lt;wil\/token_helpers.h&gt;\r\n\r\nDWORD GetCurrentProcessIntegrityLevel()\r\n{\r\n  auto info = wil::get_token_information&lt;TokenIntegrityLevel&gt;(\r\n    GetCurrentProcessToken());\r\n  auto sid = info-&gt;Label.Sid;\r\n  return *GetSidSubAuthority(sid, \r\n    *GetSidSubAuthorityCount(sid)-1);\r\n}\r\n<\/pre>\n<p>To get the integrity level, we obtain the <code>Token\u00adIntegrity\u00adLevel<\/code> information, which takes the form of a <code>TOKEN_<wbr \/>MANDATORY_<wbr \/>LABEL<\/code>. That structure consists of a <code>Label<\/code>, and in the <code>Label<\/code> is a <code>Sid<\/code>. That&#8217;s where the integrity level is.<\/p>\n<p>The integrity level is encoded in the SID as the relative identifier (the final subauthority). So we ask how many subauthorities there are and ask for the last one.<\/p>\n<p>All that&#8217;s left is mapping that integer to a semantic range.<\/p>\n<pre>auto integrityLevel = GetCurrentProcessIntegrityLevel();\r\nif (integrityLevel &gt;= SECURITY_MANDATORY_SYSTEM_RID) {\r\n  print(\"System integrity\");\r\n} else if (integrityLevel &gt;= SECURITY_MANDATORY_HIGH_RID) {\r\n  print(\"High integrity\");\r\n} else if (integrityLevel &gt;= SECURITY_MANDATORY_MEDIUM_RID) {\r\n  print(\"Medium integrity\");\r\n} else if (integrityLevel &gt;= SECURITY_MANDATORY_LOW_RID) {\r\n  print(\"Low integrity\");\r\n} else {\r\n  print(\"Below low integrity?\");\r\n}\r\n<\/pre>\n<p>Alternatively, we can check from low to high, but the tests look weird because we&#8217;re testing the upper boundary of the range, which is named after the <i>next<\/i> range.<\/p>\n<pre>auto integrityLevel = GetCurrentProcessIntegrityLevel();\r\nif (integrityLevel &lt; SECURITY_MANDATORY_LOW_RID) {\r\n  print(\"Below low integrity?\");\r\n} else if (integrityLevel &lt; SECURITY_MANDATORY_MEDIUM_RID) {\r\n  print(\"Low integrity\");\r\n} else if (integrityLevel &lt; SECURITY_MANDATORY_HIGH_RID) {\r\n  print(\"Medium integrity\");\r\n} else if (integrityLevel &lt; SECURITY_MANDATORY_SYSTEM_RID) {\r\n  print(\"High integrity\");\r\n} else {\r\n  print(\"System integrity\");\r\n}\r\n<\/pre>\n<p>Note the importance of using range checks rather than direct equality checks. That way, you will successfully handle new integrity levels that are created inside an existing range, such as <code>SECURITY_<wbr \/>MANDATORY_<wbr \/>MEDIUM_<wbr \/>PLUS_<wbr \/>RID<\/code>, which is an integrity level inserted into the &#8220;Medium&#8221; range, above the regular <code>SECURITY_<wbr \/>MANDATORY_<wbr \/>MEDIUM_<wbr \/>RID<\/code>. There&#8217;s also an unnamed integrity level that is <code>SECURITY_<wbr \/>MANDATORY_<wbr \/>MEDIUM_<wbr \/>RID<\/code> + <code>0x10<\/code> which is <a href=\"https:\/\/docs.microsoft.com\/en-us\/previous-versions\/dotnet\/articles\/bb625963(v=msdn.10)#uiaccess-for-ui-automation-applications\n  TITLE=\"> assigned to medium integrity applications with UIAccess rights<\/a>.<\/p>\n<p><a title=\"Appendix D: Getting the Integrity Level for an Access Token\" href=\"https:\/\/docs.microsoft.com\/en-us\/previous-versions\/dotnet\/articles\/bb625966(v=msdn.10)\"> The sample code in the archived content almost gets it right<\/a>, but it forgets to handle the case of an integrity level less than <code>SECURITY_<wbr \/>MANDATORY_<wbr \/>LOW_<wbr \/>RID<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A series of range checks.<\/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-107291","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>A series of range checks.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107291","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=107291"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107291\/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=107291"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107291"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107291"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}