Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome_elf/nt_registry/nt_registry.h" | 5 #include "chrome_elf/nt_registry/nt_registry.h" |
| 6 | 6 |
| 7 #include <assert.h> | |
| 8 #include <stdlib.h> | |
| 9 | |
| 7 namespace { | 10 namespace { |
| 8 | 11 |
| 9 // Function pointers used for registry access. | 12 // Function pointers used for registry access. |
| 10 RtlInitUnicodeStringFunction g_rtl_init_unicode_string = nullptr; | 13 RtlInitUnicodeStringFunction g_rtl_init_unicode_string = nullptr; |
| 11 NtCreateKeyFunction g_nt_create_key = nullptr; | 14 NtCreateKeyFunction g_nt_create_key = nullptr; |
| 12 NtDeleteKeyFunction g_nt_delete_key = nullptr; | 15 NtDeleteKeyFunction g_nt_delete_key = nullptr; |
| 13 NtOpenKeyExFunction g_nt_open_key_ex = nullptr; | 16 NtOpenKeyExFunction g_nt_open_key_ex = nullptr; |
| 14 NtCloseFunction g_nt_close = nullptr; | 17 NtCloseFunction g_nt_close = nullptr; |
| 15 NtQueryValueKeyFunction g_nt_query_value_key = nullptr; | 18 NtQueryValueKeyFunction g_nt_query_value_key = nullptr; |
| 16 NtSetValueKeyFunction g_nt_set_value_key = nullptr; | 19 NtSetValueKeyFunction g_nt_set_value_key = nullptr; |
| 17 | 20 |
| 18 // Lazy init. No concern about concurrency in chrome_elf. | 21 // Lazy init. No concern about concurrency in chrome_elf. |
| 19 bool g_initialized = false; | 22 bool g_initialized = false; |
| 20 bool g_system_install = false; | 23 bool g_system_install = false; |
| 24 bool g_wow64_proc = false; | |
| 21 bool g_reg_redirection = false; | 25 bool g_reg_redirection = false; |
| 22 const size_t g_kMaxPathLen = 255; | |
| 23 wchar_t g_kRegPathHKLM[] = L"\\Registry\\Machine\\"; | 26 wchar_t g_kRegPathHKLM[] = L"\\Registry\\Machine\\"; |
| 24 wchar_t g_kRegPathHKCU[g_kMaxPathLen] = L""; | 27 wchar_t g_kRegPathHKCU[nt::g_kRegMaxPathLen + 1] = L""; |
| 25 wchar_t g_current_user_sid_string[g_kMaxPathLen] = L""; | 28 wchar_t g_current_user_sid_string[nt::g_kRegMaxPathLen + 1] = L""; |
| 26 wchar_t g_override_path[g_kMaxPathLen] = L""; | 29 wchar_t g_override_path[nt::g_kRegMaxPathLen + 1] = L""; |
| 27 | 30 |
| 28 // Not using install_util, to prevent circular dependency. | 31 // For testing only. |
| 32 wchar_t g_HKLM_override[nt::g_kRegMaxPathLen + 1] = L""; | |
| 33 wchar_t g_HKCU_override[nt::g_kRegMaxPathLen + 1] = L""; | |
| 34 | |
| 35 //------------------------------------------------------------------------------ | |
| 36 // Initialization - LOCAL | |
| 37 //------------------------------------------------------------------------------ | |
| 38 | |
| 39 // Not using install_static, to prevent circular dependency. | |
| 29 bool IsThisProcSystem() { | 40 bool IsThisProcSystem() { |
| 30 wchar_t program_dir[MAX_PATH] = {}; | 41 wchar_t program_dir[MAX_PATH] = {}; |
| 31 wchar_t* cmd_line = GetCommandLineW(); | 42 wchar_t* cmd_line = GetCommandLineW(); |
| 32 // If our command line starts with the "Program Files" or | 43 // If our command line starts with the "Program Files" or |
| 33 // "Program Files (x86)" path, we're system. | 44 // "Program Files (x86)" path, we're system. |
| 34 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, MAX_PATH); | 45 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, MAX_PATH); |
| 35 if (ret && ret < MAX_PATH && !::wcsncmp(cmd_line, program_dir, ret)) | 46 if (ret && ret < MAX_PATH && !::wcsncmp(cmd_line, program_dir, ret)) |
| 36 return true; | 47 return true; |
| 37 | 48 |
| 38 ret = ::GetEnvironmentVariable(L"PROGRAMFILES(X86)", program_dir, MAX_PATH); | 49 ret = ::GetEnvironmentVariable(L"PROGRAMFILES(X86)", program_dir, MAX_PATH); |
| 39 if (ret && ret < MAX_PATH && !::wcsncmp(cmd_line, program_dir, ret)) | 50 if (ret && ret < MAX_PATH && !::wcsncmp(cmd_line, program_dir, ret)) |
| 40 return true; | 51 return true; |
| 41 | 52 |
| 42 return false; | 53 return false; |
| 43 } | 54 } |
| 44 | 55 |
| 56 bool IsThisProcWow64() { | |
| 57 // Using BOOL type for compat with IsWow64Process() system API. | |
| 58 BOOL is_wow64 = FALSE; | |
| 59 | |
| 60 // API might not exist, so dynamic lookup. | |
| 61 using IsWow64ProcessFunction = decltype(&IsWow64Process); | |
| 62 IsWow64ProcessFunction is_wow64_process = | |
| 63 reinterpret_cast<IsWow64ProcessFunction>(::GetProcAddress( | |
| 64 ::GetModuleHandle(L"kernel32.dll"), "IsWow64Process")); | |
| 65 if (!is_wow64_process) | |
| 66 return false; | |
| 67 if (!is_wow64_process(::GetCurrentProcess(), &is_wow64)) | |
| 68 return false; | |
| 69 return is_wow64 ? true : false; | |
| 70 } | |
| 71 | |
| 45 bool InitNativeRegApi() { | 72 bool InitNativeRegApi() { |
| 46 HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); | 73 HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); |
| 47 | 74 |
| 48 // Setup the global function pointers for registry access. | 75 // Setup the global function pointers for registry access. |
| 49 g_rtl_init_unicode_string = reinterpret_cast<RtlInitUnicodeStringFunction>( | 76 g_rtl_init_unicode_string = reinterpret_cast<RtlInitUnicodeStringFunction>( |
| 50 ::GetProcAddress(ntdll, "RtlInitUnicodeString")); | 77 ::GetProcAddress(ntdll, "RtlInitUnicodeString")); |
| 51 | 78 |
| 52 g_nt_create_key = reinterpret_cast<NtCreateKeyFunction>( | 79 g_nt_create_key = reinterpret_cast<NtCreateKeyFunction>( |
| 53 ::GetProcAddress(ntdll, "NtCreateKey")); | 80 ::GetProcAddress(ntdll, "NtCreateKey")); |
| 54 | 81 |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 82 ::GetProcAddress(ntdll, "RtlFreeUnicodeString")); | 109 ::GetProcAddress(ntdll, "RtlFreeUnicodeString")); |
| 83 | 110 |
| 84 if (!rtl_current_user_string || !rtl_free_unicode_str) | 111 if (!rtl_current_user_string || !rtl_free_unicode_str) |
| 85 return false; | 112 return false; |
| 86 | 113 |
| 87 UNICODE_STRING current_user_reg_path; | 114 UNICODE_STRING current_user_reg_path; |
| 88 if (!NT_SUCCESS(rtl_current_user_string(¤t_user_reg_path))) | 115 if (!NT_SUCCESS(rtl_current_user_string(¤t_user_reg_path))) |
| 89 return false; | 116 return false; |
| 90 | 117 |
| 91 // Finish setting up global HKCU path. | 118 // Finish setting up global HKCU path. |
| 92 ::wcsncat(g_kRegPathHKCU, current_user_reg_path.Buffer, (g_kMaxPathLen - 1)); | 119 ::wcsncat(g_kRegPathHKCU, current_user_reg_path.Buffer, nt::g_kRegMaxPathLen); |
| 93 ::wcsncat(g_kRegPathHKCU, L"\\", | 120 ::wcsncat(g_kRegPathHKCU, L"\\", |
| 94 (g_kMaxPathLen - ::wcslen(g_kRegPathHKCU) - 1)); | 121 (nt::g_kRegMaxPathLen - ::wcslen(g_kRegPathHKCU))); |
| 95 // Keep the sid string as well. | 122 // Keep the sid string as well. |
| 96 wchar_t* ptr = ::wcsrchr(current_user_reg_path.Buffer, L'\\'); | 123 wchar_t* ptr = ::wcsrchr(current_user_reg_path.Buffer, L'\\'); |
| 97 ptr++; | 124 ptr++; |
| 98 ::wcsncpy(g_current_user_sid_string, ptr, (g_kMaxPathLen - 1)); | 125 ::wcsncpy(g_current_user_sid_string, ptr, nt::g_kRegMaxPathLen); |
| 99 rtl_free_unicode_str(¤t_user_reg_path); | 126 rtl_free_unicode_str(¤t_user_reg_path); |
| 100 | 127 |
| 101 // Figure out if we're a system or user install. | 128 // Figure out if this is a system or user install. |
| 102 g_system_install = IsThisProcSystem(); | 129 g_system_install = IsThisProcSystem(); |
| 103 | 130 |
| 131 // Figure out if this is a WOW64 process. | |
| 132 g_wow64_proc = IsThisProcWow64(); | |
| 133 | |
| 104 g_initialized = true; | 134 g_initialized = true; |
| 105 return true; | 135 return true; |
| 106 } | 136 } |
| 107 | 137 |
| 138 //------------------------------------------------------------------------------ | |
| 139 // Reg WOW64 Redirection - LOCAL | |
| 140 // | |
| 141 // How registry redirection works directly calling NTDLL APIs: | |
| 142 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| 143 // - NOTE: On >= Win7, reflection support was removed. | |
| 144 // - | |
| 145 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa384253(v=vs.85).as px | |
| 146 // | |
| 147 // - 1) 32-bit / WOW64 process: | |
| 148 // a) Default access WILL be redirected to WOW64. | |
| 149 // b) KEY_WOW64_32KEY access WILL be redirected to WOW64. | |
| 150 // c) KEY_WOW64_64KEY access will NOT be redirected to WOW64. | |
| 151 // | |
| 152 // - 2) 64-bit process: | |
| 153 // a) Default access will NOT be redirected to WOW64. | |
| 154 // b) KEY_WOW64_32KEY access will NOT be redirected to WOW64. | |
| 155 // c) KEY_WOW64_64KEY access will NOT be redirected to WOW64. | |
| 156 // | |
| 157 // - Key point from above is that NTDLL redirects and respects access | |
| 158 // overrides for WOW64 calling processes. But does NOT do any of that if the | |
| 159 // calling process is 64-bit. 2b is surprising and troublesome. | |
| 160 // | |
| 161 // How registry redirection works using these nt_registry APIs: | |
| 162 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| 163 // - These APIs will behave the same as NTDLL above, EXCEPT for 2b. | |
| 164 // nt_registry APIs will respect the override access flags for all processes. | |
| 165 // | |
| 166 // - How the WOW64 redirection decision trees / Nodes work below: | |
| 167 // | |
| 168 // The HKLM and HKCU decision trees represent the information at the MSDN | |
| 169 // link above... but in a way that generates a decision about whether a | |
| 170 // registry path should be subject to WOW64 redirection. The tree is | |
| 171 // traversed as you scan along the registry path in question. | |
| 172 // | |
| 173 // - Each Node contains a chunk of registry subkey(s) to match. | |
| 174 // - If it is NOT matched, traversal is done. | |
| 175 // - If it is matched: | |
| 176 // - Current state of |redirection_type| for the whole registry path is | |
| 177 // updated. | |
| 178 // - If |next| is empty, traversal is done. | |
| 179 // - Otherwise, |next| is an array of child Nodes to try to match against. | |
| 180 // Loop. | |
| 181 //------------------------------------------------------------------------------ | |
| 182 | |
| 183 // This enum defines states for how to handle redirection. | |
| 184 // NOTE: When WOW64 redirection should happen, the redirect subkey can be either | |
| 185 // before or after the latest Node match. Unfortunately not consistent. | |
| 186 enum RedirectionType { SHARED = 0, REDIRECTED_BEFORE, REDIRECTED_AFTER }; | |
| 187 | |
| 188 struct Node { | |
| 189 template <size_t len, size_t n_len> | |
| 190 constexpr Node(const wchar_t (&wcs)[len], | |
| 191 RedirectionType rt, | |
| 192 const Node (&n)[n_len]) | |
| 193 : to_match(wcs), | |
| 194 to_match_len(len - 1), | |
| 195 redirection_type(rt), | |
| 196 next(n), | |
| 197 next_len(n_len) {} | |
| 198 | |
| 199 template <size_t len> | |
| 200 constexpr Node(const wchar_t (&wcs)[len], RedirectionType rt) | |
| 201 : to_match(wcs), | |
| 202 to_match_len(len - 1), | |
| 203 redirection_type(rt), | |
| 204 next(nullptr), | |
| 205 next_len(0) {} | |
| 206 | |
| 207 const wchar_t* to_match; | |
| 208 size_t to_match_len; | |
| 209 // If a match, this is the new state of how to redirect. | |
| 210 RedirectionType redirection_type; | |
| 211 // |next| is nullptr or an array of Nodes of length |array_len|. | |
| 212 const Node* next; | |
| 213 size_t next_len; | |
| 214 }; | |
| 215 | |
| 216 // HKLM or HKCU SOFTWARE\Classes is shared by default. Specific subkeys under | |
| 217 // Classes are redirected to SOFTWARE\WOW6432Node\Classes\<subkey> though. | |
| 218 constexpr Node kClassesSubtree[] = {{L"CLSID", REDIRECTED_BEFORE}, | |
| 219 {L"DirectShow", REDIRECTED_BEFORE}, | |
| 220 {L"Interface", REDIRECTED_BEFORE}, | |
| 221 {L"Media Type", REDIRECTED_BEFORE}, | |
| 222 {L"MediaFoundation", REDIRECTED_BEFORE}}; | |
| 223 | |
| 224 // These specific HKLM\SOFTWARE subkeys are shared. Specific | |
| 225 // subkeys under Classes are redirected though... see classes_subtree. | |
| 226 constexpr Node kHklmSoftwareSubtree[] = { | |
| 227 // TODO(pennymac): when MS fixes compiler bug, or bots are all using clang, | |
| 228 // remove the "Classes" subkeys below and replace with: | |
| 229 // {L"Classes", SHARED, kClassesSubtree}, | |
| 230 // https://connect.microsoft.com/VisualStudio/feedback/details/3104499 | |
| 231 {L"Classes\\CLSID", REDIRECTED_BEFORE}, | |
| 232 {L"Classes\\DirectShow", REDIRECTED_BEFORE}, | |
| 233 {L"Classes\\Interface", REDIRECTED_BEFORE}, | |
| 234 {L"Classes\\Media Type", REDIRECTED_BEFORE}, | |
| 235 {L"Classes\\MediaFoundation", REDIRECTED_BEFORE}, | |
| 236 {L"Classes", SHARED}, | |
| 237 | |
| 238 {L"Clients", SHARED}, | |
| 239 {L"Microsoft\\COM3", SHARED}, | |
| 240 {L"Microsoft\\Cryptography\\Calais\\Current", SHARED}, | |
| 241 {L"Microsoft\\Cryptography\\Calais\\Readers", SHARED}, | |
| 242 {L"Microsoft\\Cryptography\\Services", SHARED}, | |
| 243 | |
| 244 {L"Microsoft\\CTF\\SystemShared", SHARED}, | |
| 245 {L"Microsoft\\CTF\\TIP", SHARED}, | |
| 246 {L"Microsoft\\DFS", SHARED}, | |
| 247 {L"Microsoft\\Driver Signing", SHARED}, | |
| 248 {L"Microsoft\\EnterpriseCertificates", SHARED}, | |
| 249 | |
| 250 {L"Microsoft\\EventSystem", SHARED}, | |
| 251 {L"Microsoft\\MSMQ", SHARED}, | |
| 252 {L"Microsoft\\Non-Driver Signing", SHARED}, | |
| 253 {L"Microsoft\\Notepad\\DefaultFonts", SHARED}, | |
| 254 {L"Microsoft\\OLE", SHARED}, | |
| 255 | |
| 256 {L"Microsoft\\RAS", SHARED}, | |
| 257 {L"Microsoft\\RPC", SHARED}, | |
| 258 {L"Microsoft\\SOFTWARE\\Microsoft\\Shared Tools\\MSInfo", SHARED}, | |
| 259 {L"Microsoft\\SystemCertificates", SHARED}, | |
| 260 {L"Microsoft\\TermServLicensing", SHARED}, | |
| 261 | |
| 262 {L"Microsoft\\Transaction Server", SHARED}, | |
| 263 {L"Microsoft\\Windows\\CurrentVersion\\App Paths", SHARED}, | |
| 264 {L"Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cursors\\Schemes", | |
| 265 SHARED}, | |
| 266 {L"Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers", SHARED}, | |
| 267 {L"Microsoft\\Windows\\CurrentVersion\\Explorer\\DriveIcons", SHARED}, | |
| 268 | |
| 269 {L"Microsoft\\Windows\\CurrentVersion\\Explorer\\KindMap", SHARED}, | |
| 270 {L"Microsoft\\Windows\\CurrentVersion\\Group Policy", SHARED}, | |
| 271 {L"Microsoft\\Windows\\CurrentVersion\\Policies", SHARED}, | |
| 272 {L"Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", SHARED}, | |
| 273 {L"Microsoft\\Windows\\CurrentVersion\\Setup", SHARED}, | |
| 274 | |
| 275 {L"Microsoft\\Windows\\CurrentVersion\\Telephony\\Locations", SHARED}, | |
| 276 {L"Microsoft\\Windows NT\\CurrentVersion\\Console", SHARED}, | |
| 277 {L"Microsoft\\Windows NT\\CurrentVersion\\FontDpi", SHARED}, | |
| 278 {L"Microsoft\\Windows NT\\CurrentVersion\\FontLink", SHARED}, | |
| 279 {L"Microsoft\\Windows NT\\CurrentVersion\\FontMapper", SHARED}, | |
| 280 | |
| 281 {L"Microsoft\\Windows NT\\CurrentVersion\\Fonts", SHARED}, | |
| 282 {L"Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", SHARED}, | |
| 283 {L"Microsoft\\Windows NT\\CurrentVersion\\Gre_Initialize", SHARED}, | |
| 284 {L"Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options", | |
| 285 SHARED}, | |
| 286 {L"Microsoft\\Windows NT\\CurrentVersion\\LanguagePack", SHARED}, | |
| 287 | |
| 288 {L"Microsoft\\Windows NT\\CurrentVersion\\NetworkCards", SHARED}, | |
| 289 {L"Microsoft\\Windows NT\\CurrentVersion\\Perflib", SHARED}, | |
| 290 {L"Microsoft\\Windows NT\\CurrentVersion\\Ports", SHARED}, | |
| 291 {L"Microsoft\\Windows NT\\CurrentVersion\\Print", SHARED}, | |
| 292 {L"Microsoft\\Windows NT\\CurrentVersion\\ProfileList", SHARED}, | |
| 293 | |
| 294 {L"Microsoft\\Windows NT\\CurrentVersion\\Time Zones", SHARED}, | |
| 295 {L"Policies", SHARED}, | |
| 296 {L"RegisteredApplications", SHARED}}; | |
| 297 | |
| 298 // HKCU is entirely shared, except for a few specific Classes subkeys which | |
| 299 // are redirected. See |classes_subtree|. | |
| 300 constexpr Node kRedirectionDecisionTreeHkcu = {L"SOFTWARE\\Classes", SHARED, | |
| 301 kClassesSubtree}; | |
| 302 | |
| 303 // HKLM\SOFTWARE is redirected by default to SOFTWARE\WOW6432Node. Specific | |
| 304 // subkeys under SOFTWARE are shared though... see |hklm_software_subtree|. | |
| 305 constexpr Node kRedirectionDecisionTreeHklm = {L"SOFTWARE", REDIRECTED_AFTER, | |
| 306 kHklmSoftwareSubtree}; | |
| 307 | |
| 308 // Main redirection handler function. | |
| 309 // If redirection is required, change is made to |subkey_path| in place. | |
| 310 // | |
| 311 // - This function should be called BEFORE concatenating |subkey_path| with the | |
| 312 // root hive or calling ParseFullRegPath(). | |
| 313 // - Also, |subkey_path| should be passed to SanitizeSubkeyPath() before calling | |
| 314 // this function. | |
| 315 void ProcessRedirection(nt::ROOT_KEY root, | |
| 316 ACCESS_MASK access, | |
| 317 std::wstring* subkey_path) { | |
| 318 static constexpr wchar_t kRedirectBefore[] = L"WOW6432Node\\"; | |
| 319 static constexpr wchar_t kRedirectAfter[] = L"\\WOW6432Node"; | |
| 320 | |
| 321 assert(subkey_path != nullptr); | |
| 322 assert(subkey_path->empty() || subkey_path->front() != L'\\'); | |
| 323 assert(subkey_path->empty() || subkey_path->back() != L'\\'); | |
| 324 | |
| 325 // |subkey_path| could legitimately be empty. | |
| 326 if (subkey_path->empty() || | |
| 327 (access & KEY_WOW64_32KEY && access & KEY_WOW64_64KEY)) | |
| 328 return; | |
| 329 | |
| 330 // Convert nt::AUTO to the appropriate root key. | |
| 331 nt::ROOT_KEY temp_root = root; | |
| 332 if (root == nt::AUTO) | |
| 333 temp_root = g_system_install ? nt::HKLM : nt::HKCU; | |
| 334 | |
| 335 // No redirection during testing when there's already an override. | |
| 336 // Otherwise, the testing redirect directory Software\Chromium\TempTestKeys | |
| 337 // would get WOW64 redirected if root_key == HKLM in this function. | |
| 338 if ((temp_root == nt::HKCU && *g_HKCU_override) || | |
| 339 (temp_root == nt::HKLM && *g_HKLM_override)) | |
| 340 return; | |
| 341 | |
| 342 // WOW64 redirection only supported on x64 architecture. Return if x86. | |
| 343 SYSTEM_INFO system_info = {}; | |
| 344 ::GetNativeSystemInfo(&system_info); | |
| 345 if (system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) | |
| 346 return; | |
| 347 | |
| 348 bool use_wow64 = g_wow64_proc; | |
| 349 // Consider KEY_WOW64_32KEY and KEY_WOW64_64KEY override access flags. | |
| 350 if (access & KEY_WOW64_32KEY) | |
| 351 use_wow64 = true; | |
| 352 if (access & KEY_WOW64_64KEY) | |
| 353 use_wow64 = false; | |
| 354 | |
| 355 // If !use_wow64, there's nothing more to do. | |
| 356 if (!use_wow64) | |
| 357 return; | |
| 358 | |
| 359 // The root of the decision trees are an array of 1. | |
| 360 size_t node_array_len = 1; | |
| 361 // Pick which decision tree to use. | |
| 362 const Node* current_node = (temp_root == nt::HKCU) | |
| 363 ? &kRedirectionDecisionTreeHkcu | |
| 364 : &kRedirectionDecisionTreeHklm; | |
| 365 | |
| 366 // The following loop works on the |subkey_path| from left to right. | |
| 367 // |position| tracks progress along |subkey_path|. | |
| 368 const wchar_t* position = subkey_path->c_str(); | |
| 369 // Hold a count of chars left after position, for efficient calculations. | |
| 370 size_t chars_left = subkey_path->length(); | |
| 371 // |redirect_state| holds the latest state of redirection requirement. | |
| 372 RedirectionType redirect_state = SHARED; | |
| 373 // |insertion_point| tracks latest spot for redirection subkey to be inserted. | |
| 374 const wchar_t* insertion_point = nullptr; | |
| 375 // |insert_string| tracks which redirection string would be inserted. | |
| 376 const wchar_t* insert_string = nullptr; | |
| 377 | |
| 378 size_t node_index = 0; | |
| 379 while (node_index < node_array_len) { | |
| 380 size_t current_to_match_len = current_node->to_match_len; | |
| 381 // Make sure the remainder of the path is at least as long as the current | |
| 382 // subkey to match. | |
| 383 if (chars_left >= current_to_match_len) { | |
| 384 // Do case insensitive comparisons. | |
| 385 if (::wcsnicmp(position, current_node->to_match, current_to_match_len) == | |
|
grt (UTC plus 2)
2016/09/30 09:32:16
nit: !::wcsnicmp to make this fit on one line
penny
2016/10/01 01:44:25
Done.
| |
| 386 0) { | |
| 387 // Make sure not to match on a substring. | |
| 388 if (*(position + current_to_match_len) == L'\\' || | |
| 389 *(position + current_to_match_len) == L'\0') { | |
| 390 // MATCH! | |
| 391 // ------------------------------------------------------------------- | |
| 392 // 1) Update state of redirection. | |
| 393 redirect_state = current_node->redirection_type; | |
| 394 // 1.5) If new state is to redirect, the new insertion point will be | |
| 395 // either right before or right after this match. | |
| 396 if (redirect_state == REDIRECTED_BEFORE) { | |
| 397 insertion_point = position; | |
| 398 insert_string = kRedirectBefore; | |
| 399 } else if (redirect_state == REDIRECTED_AFTER) { | |
| 400 insertion_point = position + current_to_match_len; | |
| 401 insert_string = kRedirectAfter; | |
| 402 } | |
| 403 // 2) Adjust |position| along the subkey path. | |
| 404 position += current_to_match_len; | |
| 405 chars_left -= current_to_match_len; | |
| 406 // 2.5) Increment the position, to move past path seperator(s). | |
| 407 while (*position == L'\\') { | |
| 408 ++position; | |
| 409 --chars_left; | |
| 410 } | |
| 411 // 3) Move our loop parameters to the |next| array of Nodes. | |
| 412 node_array_len = current_node->next_len; | |
| 413 current_node = current_node->next; | |
| 414 node_index = 0; | |
| 415 // 4) Finish this loop and start on new array. | |
| 416 continue; | |
| 417 } | |
| 418 } | |
| 419 } | |
| 420 | |
| 421 // Move to the next node in the array if we didn't match this loop. | |
| 422 ++current_node; | |
| 423 ++node_index; | |
| 424 } | |
| 425 | |
| 426 if (redirect_state == SHARED) | |
| 427 return; | |
| 428 | |
| 429 // Insert the redirection into |subkey_path|, at |insertion_point|. | |
| 430 subkey_path->insert((insertion_point - subkey_path->c_str()), insert_string); | |
| 431 } | |
| 432 | |
| 433 //------------------------------------------------------------------------------ | |
| 434 // Reg Path Utilities - LOCAL | |
| 435 //------------------------------------------------------------------------------ | |
| 436 | |
| 108 const wchar_t* ConvertRootKey(nt::ROOT_KEY root) { | 437 const wchar_t* ConvertRootKey(nt::ROOT_KEY root) { |
| 109 nt::ROOT_KEY key = root; | 438 nt::ROOT_KEY key = root; |
| 110 | 439 |
| 111 if (!root) { | 440 if (root == nt::AUTO) { |
|
grt (UTC plus 2)
2016/09/30 09:32:16
nit: omit braces now that the comment is out of th
penny
2016/10/01 01:44:25
Done.
| |
| 112 // AUTO | |
| 113 key = g_system_install ? nt::HKLM : nt::HKCU; | 441 key = g_system_install ? nt::HKLM : nt::HKCU; |
| 114 } | 442 } |
| 115 | 443 |
| 116 if ((key == nt::HKCU) && (::wcslen(nt::HKCU_override) != 0)) { | 444 if (key == nt::HKCU && *g_HKCU_override) { |
| 117 std::wstring temp(g_kRegPathHKCU); | 445 std::wstring temp(g_kRegPathHKCU); |
| 118 temp.append(nt::HKCU_override); | 446 temp.append(g_HKCU_override); |
| 119 temp.append(L"\\"); | 447 temp.append(L"\\"); |
| 120 ::wcsncpy(g_override_path, temp.c_str(), g_kMaxPathLen - 1); | 448 ::wcsncpy(g_override_path, temp.c_str(), nt::g_kRegMaxPathLen); |
| 121 g_reg_redirection = true; | 449 g_reg_redirection = true; |
| 122 return g_override_path; | 450 return g_override_path; |
| 123 } else if ((key == nt::HKLM) && (::wcslen(nt::HKLM_override) != 0)) { | 451 } else if (key == nt::HKLM && *g_HKLM_override) { |
| 452 // Yes, HKLM override goes into HKCU. This is not a typo. | |
| 124 std::wstring temp(g_kRegPathHKCU); | 453 std::wstring temp(g_kRegPathHKCU); |
| 125 temp.append(nt::HKLM_override); | 454 temp.append(g_HKLM_override); |
| 126 temp.append(L"\\"); | 455 temp.append(L"\\"); |
| 127 ::wcsncpy(g_override_path, temp.c_str(), g_kMaxPathLen - 1); | 456 ::wcsncpy(g_override_path, temp.c_str(), nt::g_kRegMaxPathLen); |
| 128 g_reg_redirection = true; | 457 g_reg_redirection = true; |
| 129 return g_override_path; | 458 return g_override_path; |
| 130 } | 459 } |
| 131 | 460 |
| 132 g_reg_redirection = false; | 461 g_reg_redirection = false; |
| 133 if (key == nt::HKCU) | 462 if (key == nt::HKCU) |
| 134 return g_kRegPathHKCU; | 463 return g_kRegPathHKCU; |
| 135 else | 464 else |
| 136 return g_kRegPathHKLM; | 465 return g_kRegPathHKLM; |
| 137 } | 466 } |
| 138 | 467 |
| 468 // This utility should be called on an externally provided subkey path. | |
| 469 // - Ensures there are no starting or trailing backslashes. | |
| 470 // - Note from MSDN: "Key names cannot include the backslash character (\), | |
| 471 // but any other printable character can be used." | |
| 472 void SanitizeSubkeyPath(std::wstring* input) { | |
| 473 assert(input != nullptr); | |
| 474 | |
| 475 // Remove any trailing backslashes. | |
| 476 while (!input->empty() && input->back() == L'\\') | |
| 477 input->pop_back(); | |
| 478 | |
| 479 // Remove any starting backslashes. | |
| 480 size_t index = 0; | |
| 481 while ((*input)[index] == L'\\') | |
| 482 ++index; | |
| 483 if (!index) | |
| 484 *input = input->substr(index); | |
| 485 } | |
| 486 | |
| 139 // Turns a root and subkey path into the registry base hive and the rest of the | 487 // Turns a root and subkey path into the registry base hive and the rest of the |
| 140 // subkey tokens. | 488 // subkey tokens. |
| 141 // - |converted_root| should come directly out of ConvertRootKey function. | 489 // - |converted_root| should come directly out of ConvertRootKey function. |
| 490 // - |subkey_path| should be passed to SanitizeSubkeyPath() first. | |
| 142 // - E.g. base hive: "\Registry\Machine\", "\Registry\User\<SID>\". | 491 // - E.g. base hive: "\Registry\Machine\", "\Registry\User\<SID>\". |
| 143 bool ParseFullRegPath(const wchar_t* converted_root, | 492 bool ParseFullRegPath(const wchar_t* converted_root, |
| 144 const wchar_t* subkey_path, | 493 const std::wstring& subkey_path, |
| 145 std::wstring* out_base, | 494 std::wstring* out_base, |
| 146 std::vector<std::wstring>* subkeys) { | 495 std::vector<std::wstring>* subkeys) { |
| 496 assert(converted_root != nullptr); | |
| 497 | |
| 147 out_base->clear(); | 498 out_base->clear(); |
| 148 subkeys->clear(); | 499 subkeys->clear(); |
| 149 std::wstring temp = L""; | 500 std::wstring temp = L""; |
| 150 | 501 |
| 151 if (g_reg_redirection) { | 502 if (g_reg_redirection) { |
| 152 // Why process |converted_root|? To handle reg redirection used by tests. | 503 // Why process |converted_root|? To handle reg redirection used by tests. |
| 153 // E.g.: | 504 // E.g.: |
| 154 // |converted_root| = "\REGISTRY\USER\S-1-5-21-39260824-743453154-142223018- | 505 // |converted_root| = "\REGISTRY\USER\S-1-5-21-39260824-743453154-142223018- |
| 155 // 716772\Software\Chromium\TempTestKeys\13110669370890870$94c6ed9d-bc34- | 506 // 716772\Software\Chromium\TempTestKeys\13110669370890870$94c6ed9d-bc34- |
| 156 // 44f3-a0b3-9eee2d3f2f82\". | 507 // 44f3-a0b3-9eee2d3f2f82\". |
| 157 // |subkey_path| = "SOFTWARE\Google\Chrome\BrowserSec". | 508 // |subkey_path| = "SOFTWARE\Google\Chrome\BrowserSec". |
| 158 temp.append(converted_root); | 509 temp.append(converted_root); |
| 159 } | 510 } |
| 160 if (subkey_path != nullptr) | 511 temp.append(subkey_path); |
| 161 temp.append(subkey_path); | |
| 162 | 512 |
| 163 // Tokenize the full path. | 513 // Tokenize the full path. |
| 164 size_t find_start = 0; | 514 size_t find_start = 0; |
| 165 size_t delimiter = temp.find_first_of(L'\\'); | 515 size_t delimiter = temp.find_first_of(L'\\'); |
| 166 while (delimiter != std::wstring::npos) { | 516 while (delimiter != std::wstring::npos) { |
| 167 std::wstring token = temp.substr(find_start, delimiter - find_start); | 517 std::wstring token = temp.substr(find_start, delimiter - find_start); |
| 168 if (!token.empty()) | 518 if (!token.empty()) |
| 169 subkeys->push_back(token); | 519 subkeys->push_back(token); |
| 170 find_start = delimiter + 1; | 520 find_start = delimiter + 1; |
| 171 delimiter = temp.find_first_of(L'\\', find_start); | 521 delimiter = temp.find_first_of(L'\\', find_start); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 191 out_base->push_back(L'\\'); | 541 out_base->push_back(L'\\'); |
| 192 } | 542 } |
| 193 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens); | 543 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens); |
| 194 } else { | 544 } else { |
| 195 out_base->assign(converted_root); | 545 out_base->assign(converted_root); |
| 196 } | 546 } |
| 197 | 547 |
| 198 return true; | 548 return true; |
| 199 } | 549 } |
| 200 | 550 |
| 551 //------------------------------------------------------------------------------ | |
| 552 // Misc wrapper functions - LOCAL | |
| 553 //------------------------------------------------------------------------------ | |
| 554 | |
| 201 NTSTATUS CreateKeyWrapper(const std::wstring& key_path, | 555 NTSTATUS CreateKeyWrapper(const std::wstring& key_path, |
| 202 ACCESS_MASK access, | 556 ACCESS_MASK access, |
| 203 HANDLE* out_handle, | 557 HANDLE* out_handle, |
| 204 ULONG* create_or_open OPTIONAL) { | 558 ULONG* create_or_open OPTIONAL) { |
| 205 UNICODE_STRING key_path_uni = {}; | 559 UNICODE_STRING key_path_uni = {}; |
| 206 g_rtl_init_unicode_string(&key_path_uni, key_path.c_str()); | 560 g_rtl_init_unicode_string(&key_path_uni, key_path.c_str()); |
| 207 | 561 |
| 208 OBJECT_ATTRIBUTES obj = {}; | 562 OBJECT_ATTRIBUTES obj = {}; |
| 209 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL, | 563 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL, |
| 210 nullptr); | 564 nullptr); |
| 211 | 565 |
| 212 return g_nt_create_key(out_handle, access, &obj, 0, nullptr, | 566 return g_nt_create_key(out_handle, access, &obj, 0, nullptr, |
| 213 REG_OPTION_NON_VOLATILE, create_or_open); | 567 REG_OPTION_NON_VOLATILE, create_or_open); |
| 214 } | 568 } |
| 215 | 569 |
| 216 } // namespace | 570 } // namespace |
| 217 | 571 |
| 218 namespace nt { | 572 namespace nt { |
| 219 | 573 |
| 220 const size_t g_kRegMaxPathLen = 255; | |
| 221 wchar_t HKLM_override[g_kRegMaxPathLen] = L""; | |
| 222 wchar_t HKCU_override[g_kRegMaxPathLen] = L""; | |
| 223 | |
| 224 //------------------------------------------------------------------------------ | 574 //------------------------------------------------------------------------------ |
| 225 // Create, open, delete, close functions | 575 // Create, open, delete, close functions |
| 226 //------------------------------------------------------------------------------ | 576 //------------------------------------------------------------------------------ |
| 227 | 577 |
| 228 bool CreateRegKey(ROOT_KEY root, | 578 bool CreateRegKey(ROOT_KEY root, |
| 229 const wchar_t* key_path, | 579 const wchar_t* key_path, |
| 230 ACCESS_MASK access, | 580 ACCESS_MASK access, |
| 231 HANDLE* out_handle OPTIONAL) { | 581 HANDLE* out_handle OPTIONAL) { |
| 232 if (!g_initialized) | 582 if (!g_initialized) |
| 233 InitNativeRegApi(); | 583 InitNativeRegApi(); |
| 234 | 584 |
| 585 // |key_path| can be null or empty, but it can't be longer than | |
| 586 // |g_kRegMaxPathLen| at this point. | |
| 587 if (key_path != nullptr && | |
| 588 ::wcsnlen(key_path, g_kRegMaxPathLen + 1) == g_kRegMaxPathLen + 1) | |
| 589 return false; | |
| 590 | |
| 591 std::wstring redirected_key_path; | |
| 592 if (key_path) { | |
| 593 redirected_key_path = key_path; | |
| 594 SanitizeSubkeyPath(&redirected_key_path); | |
| 595 ProcessRedirection(root, access, &redirected_key_path); | |
| 596 } | |
| 597 | |
| 235 std::wstring current_path; | 598 std::wstring current_path; |
| 236 std::vector<std::wstring> subkeys; | 599 std::vector<std::wstring> subkeys; |
| 237 if (!ParseFullRegPath(ConvertRootKey(root), key_path, ¤t_path, | 600 if (!ParseFullRegPath(ConvertRootKey(root), redirected_key_path, |
| 238 &subkeys)) | 601 ¤t_path, &subkeys)) |
| 239 return false; | 602 return false; |
| 240 | 603 |
| 241 // Open the base hive first. It should always exist already. | 604 // Open the base hive first. It should always exist already. |
| 242 HANDLE last_handle = INVALID_HANDLE_VALUE; | 605 HANDLE last_handle = INVALID_HANDLE_VALUE; |
| 243 NTSTATUS status = | 606 NTSTATUS status = |
| 244 CreateKeyWrapper(current_path, access, &last_handle, nullptr); | 607 CreateKeyWrapper(current_path, access, &last_handle, nullptr); |
| 245 if (!NT_SUCCESS(status)) | 608 if (!NT_SUCCESS(status)) |
| 246 return false; | 609 return false; |
| 247 | 610 |
| 248 size_t subkeys_size = subkeys.size(); | 611 size_t subkeys_size = subkeys.size(); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 300 } | 663 } |
| 301 | 664 |
| 302 bool OpenRegKey(ROOT_KEY root, | 665 bool OpenRegKey(ROOT_KEY root, |
| 303 const wchar_t* key_path, | 666 const wchar_t* key_path, |
| 304 ACCESS_MASK access, | 667 ACCESS_MASK access, |
| 305 HANDLE* out_handle, | 668 HANDLE* out_handle, |
| 306 NTSTATUS* error_code OPTIONAL) { | 669 NTSTATUS* error_code OPTIONAL) { |
| 307 if (!g_initialized) | 670 if (!g_initialized) |
| 308 InitNativeRegApi(); | 671 InitNativeRegApi(); |
| 309 | 672 |
| 673 // |key_path| can be null or empty, but it can't be longer than | |
| 674 // |g_kRegMaxPathLen| at this point. | |
| 675 if (key_path != nullptr && | |
| 676 ::wcsnlen(key_path, g_kRegMaxPathLen + 1) == g_kRegMaxPathLen + 1) | |
| 677 return false; | |
| 678 | |
| 310 NTSTATUS status = STATUS_UNSUCCESSFUL; | 679 NTSTATUS status = STATUS_UNSUCCESSFUL; |
| 311 UNICODE_STRING key_path_uni = {}; | 680 UNICODE_STRING key_path_uni = {}; |
| 312 OBJECT_ATTRIBUTES obj = {}; | 681 OBJECT_ATTRIBUTES obj = {}; |
| 313 *out_handle = INVALID_HANDLE_VALUE; | 682 *out_handle = INVALID_HANDLE_VALUE; |
| 314 | 683 |
| 315 std::wstring full_path(ConvertRootKey(root)); | 684 std::wstring full_path; |
| 316 full_path.append(key_path); | 685 if (key_path) { |
| 686 full_path = key_path; | |
| 687 SanitizeSubkeyPath(&full_path); | |
| 688 ProcessRedirection(root, access, &full_path); | |
| 689 } | |
| 690 full_path.insert(0, ConvertRootKey(root)); | |
| 317 | 691 |
| 318 g_rtl_init_unicode_string(&key_path_uni, full_path.c_str()); | 692 g_rtl_init_unicode_string(&key_path_uni, full_path.c_str()); |
| 319 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL, | 693 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL, |
| 320 NULL); | 694 NULL); |
| 321 | 695 |
| 322 status = g_nt_open_key_ex(out_handle, access, &obj, 0); | 696 status = g_nt_open_key_ex(out_handle, access, &obj, 0); |
| 323 // See if caller wants the NTSTATUS. | 697 // See if caller wants the NTSTATUS. |
| 324 if (error_code) | 698 if (error_code) |
| 325 *error_code = status; | 699 *error_code = status; |
| 326 | 700 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 338 | 712 |
| 339 status = g_nt_delete_key(key); | 713 status = g_nt_delete_key(key); |
| 340 | 714 |
| 341 if (NT_SUCCESS(status)) | 715 if (NT_SUCCESS(status)) |
| 342 return true; | 716 return true; |
| 343 | 717 |
| 344 return false; | 718 return false; |
| 345 } | 719 } |
| 346 | 720 |
| 347 // wrapper function | 721 // wrapper function |
| 348 bool DeleteRegKey(ROOT_KEY root, const wchar_t* key_path) { | 722 bool DeleteRegKey(ROOT_KEY root, |
| 723 WOW64_OVERRIDE wow64_override, | |
| 724 const wchar_t* key_path) { | |
| 349 HANDLE key = INVALID_HANDLE_VALUE; | 725 HANDLE key = INVALID_HANDLE_VALUE; |
| 350 | 726 |
| 351 if (!OpenRegKey(root, key_path, DELETE, &key, nullptr)) | 727 if (!OpenRegKey(root, key_path, DELETE | wow64_override, &key, nullptr)) |
| 352 return false; | 728 return false; |
| 353 | 729 |
| 354 if (!DeleteRegKey(key)) { | 730 if (!DeleteRegKey(key)) { |
| 355 CloseRegKey(key); | 731 CloseRegKey(key); |
| 356 return false; | 732 return false; |
| 357 } | 733 } |
| 358 | 734 |
| 359 CloseRegKey(key); | 735 CloseRegKey(key); |
| 360 return true; | 736 return true; |
| 361 } | 737 } |
| 362 | 738 |
| 363 void CloseRegKey(HANDLE key) { | 739 void CloseRegKey(HANDLE key) { |
| 364 if (!g_initialized) | 740 if (!g_initialized) |
| 365 InitNativeRegApi(); | 741 InitNativeRegApi(); |
| 366 g_nt_close(key); | 742 g_nt_close(key); |
| 367 } | 743 } |
| 368 | 744 |
| 369 //------------------------------------------------------------------------------ | 745 //------------------------------------------------------------------------------ |
| 370 // Getter functions | 746 // Getter functions |
| 371 //------------------------------------------------------------------------------ | 747 //------------------------------------------------------------------------------ |
| 372 | 748 |
| 373 bool QueryRegKeyValue(HANDLE key, | 749 bool QueryRegKeyValue(HANDLE key, |
| 374 const wchar_t* value_name, | 750 const wchar_t* value_name, |
| 375 ULONG* out_type, | 751 ULONG* out_type, |
| 376 BYTE** out_buffer, | 752 BYTE** out_buffer, |
| 377 DWORD* out_size) { | 753 DWORD* out_size) { |
| 378 if (!g_initialized) | 754 if (!g_initialized) |
| 379 InitNativeRegApi(); | 755 InitNativeRegApi(); |
| 380 | 756 |
| 757 if (value_name == nullptr || *value_name == L'\0' || | |
|
grt (UTC plus 2)
2016/09/30 09:32:16
will g_nt_query_value_key already do this validati
penny
2016/10/01 01:44:25
Right, so yes, the ntdll functions should fail out
grt (UTC plus 2)
2016/10/02 20:10:54
Seems okay to me. Thanks.
| |
| 758 ::wcsnlen(value_name, g_kRegMaxValueName) == g_kRegMaxValueName) | |
| 759 return false; | |
| 760 | |
| 381 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL; | 761 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL; |
| 382 UNICODE_STRING value_uni = {}; | 762 UNICODE_STRING value_uni = {}; |
| 383 g_rtl_init_unicode_string(&value_uni, value_name); | 763 g_rtl_init_unicode_string(&value_uni, value_name); |
| 384 DWORD size_needed = 0; | 764 DWORD size_needed = 0; |
| 385 bool success = false; | 765 bool success = false; |
| 386 | 766 |
| 387 // First call to find out how much room we need for the value! | 767 // First call to find out how much room we need for the value! |
| 388 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, | 768 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, |
| 389 nullptr, 0, &size_needed); | 769 nullptr, 0, &size_needed); |
| 390 if (ntstatus != STATUS_BUFFER_TOO_SMALL) | 770 if (ntstatus != STATUS_BUFFER_TOO_SMALL) |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 423 return false; | 803 return false; |
| 424 | 804 |
| 425 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes)); | 805 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes)); |
| 426 | 806 |
| 427 delete[] value_bytes; | 807 delete[] value_bytes; |
| 428 return true; | 808 return true; |
| 429 } | 809 } |
| 430 | 810 |
| 431 // wrapper function | 811 // wrapper function |
| 432 bool QueryRegValueDWORD(ROOT_KEY root, | 812 bool QueryRegValueDWORD(ROOT_KEY root, |
| 813 WOW64_OVERRIDE wow64_override, | |
| 433 const wchar_t* key_path, | 814 const wchar_t* key_path, |
| 434 const wchar_t* value_name, | 815 const wchar_t* value_name, |
| 435 DWORD* out_dword) { | 816 DWORD* out_dword) { |
| 436 HANDLE key = INVALID_HANDLE_VALUE; | 817 HANDLE key = INVALID_HANDLE_VALUE; |
| 437 | 818 |
| 438 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key, | 819 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) |
| 439 NULL)) | |
| 440 return false; | 820 return false; |
| 441 | 821 |
| 442 if (!QueryRegValueDWORD(key, value_name, out_dword)) { | 822 if (!QueryRegValueDWORD(key, value_name, out_dword)) { |
| 443 CloseRegKey(key); | 823 CloseRegKey(key); |
| 444 return false; | 824 return false; |
| 445 } | 825 } |
| 446 | 826 |
| 447 CloseRegKey(key); | 827 CloseRegKey(key); |
| 448 return true; | 828 return true; |
| 449 } | 829 } |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 461 return false; | 841 return false; |
| 462 | 842 |
| 463 *out_sz = reinterpret_cast<wchar_t*>(value_bytes); | 843 *out_sz = reinterpret_cast<wchar_t*>(value_bytes); |
| 464 | 844 |
| 465 delete[] value_bytes; | 845 delete[] value_bytes; |
| 466 return true; | 846 return true; |
| 467 } | 847 } |
| 468 | 848 |
| 469 // wrapper function | 849 // wrapper function |
| 470 bool QueryRegValueSZ(ROOT_KEY root, | 850 bool QueryRegValueSZ(ROOT_KEY root, |
| 851 WOW64_OVERRIDE wow64_override, | |
| 471 const wchar_t* key_path, | 852 const wchar_t* key_path, |
| 472 const wchar_t* value_name, | 853 const wchar_t* value_name, |
| 473 std::wstring* out_sz) { | 854 std::wstring* out_sz) { |
| 474 HANDLE key = INVALID_HANDLE_VALUE; | 855 HANDLE key = INVALID_HANDLE_VALUE; |
| 475 | 856 |
| 476 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key, | 857 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) |
| 477 NULL)) | |
| 478 return false; | 858 return false; |
| 479 | 859 |
| 480 if (!QueryRegValueSZ(key, value_name, out_sz)) { | 860 if (!QueryRegValueSZ(key, value_name, out_sz)) { |
| 481 CloseRegKey(key); | 861 CloseRegKey(key); |
| 482 return false; | 862 return false; |
| 483 } | 863 } |
| 484 | 864 |
| 485 CloseRegKey(key); | 865 CloseRegKey(key); |
| 486 return true; | 866 return true; |
| 487 } | 867 } |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 515 // Handle the case of "empty multi_sz". | 895 // Handle the case of "empty multi_sz". |
| 516 if (out_multi_sz->size() == 0) | 896 if (out_multi_sz->size() == 0) |
| 517 out_multi_sz->push_back(L""); | 897 out_multi_sz->push_back(L""); |
| 518 | 898 |
| 519 delete[] value_bytes; | 899 delete[] value_bytes; |
| 520 return true; | 900 return true; |
| 521 } | 901 } |
| 522 | 902 |
| 523 // wrapper function | 903 // wrapper function |
| 524 bool QueryRegValueMULTISZ(ROOT_KEY root, | 904 bool QueryRegValueMULTISZ(ROOT_KEY root, |
| 905 WOW64_OVERRIDE wow64_override, | |
| 525 const wchar_t* key_path, | 906 const wchar_t* key_path, |
| 526 const wchar_t* value_name, | 907 const wchar_t* value_name, |
| 527 std::vector<std::wstring>* out_multi_sz) { | 908 std::vector<std::wstring>* out_multi_sz) { |
| 528 HANDLE key = INVALID_HANDLE_VALUE; | 909 HANDLE key = INVALID_HANDLE_VALUE; |
| 529 | 910 |
| 530 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key, | 911 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) |
| 531 NULL)) | |
| 532 return false; | 912 return false; |
| 533 | 913 |
| 534 if (!QueryRegValueMULTISZ(key, value_name, out_multi_sz)) { | 914 if (!QueryRegValueMULTISZ(key, value_name, out_multi_sz)) { |
| 535 CloseRegKey(key); | 915 CloseRegKey(key); |
| 536 return false; | 916 return false; |
| 537 } | 917 } |
| 538 | 918 |
| 539 CloseRegKey(key); | 919 CloseRegKey(key); |
| 540 return true; | 920 return true; |
| 541 } | 921 } |
| 542 | 922 |
| 543 //------------------------------------------------------------------------------ | 923 //------------------------------------------------------------------------------ |
| 544 // Setter functions | 924 // Setter functions |
| 545 //------------------------------------------------------------------------------ | 925 //------------------------------------------------------------------------------ |
| 546 | 926 |
| 547 bool SetRegKeyValue(HANDLE key, | 927 bool SetRegKeyValue(HANDLE key, |
| 548 const wchar_t* value_name, | 928 const wchar_t* value_name, |
| 549 ULONG type, | 929 ULONG type, |
| 550 const BYTE* data, | 930 const BYTE* data, |
| 551 DWORD data_size) { | 931 DWORD data_size) { |
| 552 if (!g_initialized) | 932 if (!g_initialized) |
| 553 InitNativeRegApi(); | 933 InitNativeRegApi(); |
| 554 | 934 |
| 935 if (value_name == nullptr || *value_name == L'\0' || | |
| 936 ::wcsnlen(value_name, g_kRegMaxValueName) == g_kRegMaxValueName) | |
| 937 return false; | |
| 938 | |
| 555 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL; | 939 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL; |
| 556 UNICODE_STRING value_uni = {}; | 940 UNICODE_STRING value_uni = {}; |
| 557 g_rtl_init_unicode_string(&value_uni, value_name); | 941 g_rtl_init_unicode_string(&value_uni, value_name); |
| 558 | 942 |
| 559 BYTE* non_const_data = const_cast<BYTE*>(data); | 943 BYTE* non_const_data = const_cast<BYTE*>(data); |
| 560 ntstatus = | 944 ntstatus = |
| 561 g_nt_set_value_key(key, &value_uni, 0, type, non_const_data, data_size); | 945 g_nt_set_value_key(key, &value_uni, 0, type, non_const_data, data_size); |
| 562 | 946 |
| 563 if (NT_SUCCESS(ntstatus)) | 947 if (NT_SUCCESS(ntstatus)) |
| 564 return true; | 948 return true; |
| 565 | 949 |
| 566 return false; | 950 return false; |
| 567 } | 951 } |
| 568 | 952 |
| 569 // wrapper function | 953 // wrapper function |
| 570 bool SetRegValueDWORD(HANDLE key, const wchar_t* value_name, DWORD value) { | 954 bool SetRegValueDWORD(HANDLE key, const wchar_t* value_name, DWORD value) { |
| 571 return SetRegKeyValue(key, value_name, REG_DWORD, | 955 return SetRegKeyValue(key, value_name, REG_DWORD, |
| 572 reinterpret_cast<BYTE*>(&value), sizeof(value)); | 956 reinterpret_cast<BYTE*>(&value), sizeof(value)); |
| 573 } | 957 } |
| 574 | 958 |
| 575 // wrapper function | 959 // wrapper function |
| 576 bool SetRegValueDWORD(ROOT_KEY root, | 960 bool SetRegValueDWORD(ROOT_KEY root, |
| 961 WOW64_OVERRIDE wow64_override, | |
| 577 const wchar_t* key_path, | 962 const wchar_t* key_path, |
| 578 const wchar_t* value_name, | 963 const wchar_t* value_name, |
| 579 DWORD value) { | 964 DWORD value) { |
| 580 HANDLE key = INVALID_HANDLE_VALUE; | 965 HANDLE key = INVALID_HANDLE_VALUE; |
| 581 | 966 |
| 582 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL)) | 967 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | wow64_override, &key, NULL)) |
| 583 return false; | 968 return false; |
| 584 | 969 |
| 585 if (!SetRegValueDWORD(key, value_name, value)) { | 970 if (!SetRegValueDWORD(key, value_name, value)) { |
| 586 CloseRegKey(key); | 971 CloseRegKey(key); |
| 587 return false; | 972 return false; |
| 588 } | 973 } |
| 589 | 974 |
| 590 return true; | 975 return true; |
| 591 } | 976 } |
| 592 | 977 |
| 593 // wrapper function | 978 // wrapper function |
| 594 bool SetRegValueSZ(HANDLE key, | 979 bool SetRegValueSZ(HANDLE key, |
| 595 const wchar_t* value_name, | 980 const wchar_t* value_name, |
| 596 const std::wstring& value) { | 981 const std::wstring& value) { |
| 597 // Make sure the number of bytes in |value|, including EoS, fits in a DWORD. | 982 // Make sure the number of bytes in |value|, including EoS, fits in a DWORD. |
| 598 if (std::numeric_limits<DWORD>::max() < | 983 if (std::numeric_limits<DWORD>::max() < |
| 599 ((value.length() + 1) * sizeof(wchar_t))) | 984 ((value.length() + 1) * sizeof(wchar_t))) |
| 600 return false; | 985 return false; |
| 601 | 986 |
| 602 DWORD size = (static_cast<DWORD>((value.length() + 1) * sizeof(wchar_t))); | 987 DWORD size = (static_cast<DWORD>((value.length() + 1) * sizeof(wchar_t))); |
| 603 return SetRegKeyValue(key, value_name, REG_SZ, | 988 return SetRegKeyValue(key, value_name, REG_SZ, |
| 604 reinterpret_cast<const BYTE*>(value.c_str()), size); | 989 reinterpret_cast<const BYTE*>(value.c_str()), size); |
| 605 } | 990 } |
| 606 | 991 |
| 607 // wrapper function | 992 // wrapper function |
| 608 bool SetRegValueSZ(ROOT_KEY root, | 993 bool SetRegValueSZ(ROOT_KEY root, |
| 994 WOW64_OVERRIDE wow64_override, | |
| 609 const wchar_t* key_path, | 995 const wchar_t* key_path, |
| 610 const wchar_t* value_name, | 996 const wchar_t* value_name, |
| 611 const std::wstring& value) { | 997 const std::wstring& value) { |
| 612 HANDLE key = INVALID_HANDLE_VALUE; | 998 HANDLE key = INVALID_HANDLE_VALUE; |
| 613 | 999 |
| 614 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL)) | 1000 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | wow64_override, &key, NULL)) |
| 615 return false; | 1001 return false; |
| 616 | 1002 |
| 617 if (!SetRegValueSZ(key, value_name, value)) { | 1003 if (!SetRegValueSZ(key, value_name, value)) { |
| 618 CloseRegKey(key); | 1004 CloseRegKey(key); |
| 619 return false; | 1005 return false; |
| 620 } | 1006 } |
| 621 | 1007 |
| 622 return true; | 1008 return true; |
| 623 } | 1009 } |
| 624 | 1010 |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 648 if (std::numeric_limits<DWORD>::max() < builder.size()) | 1034 if (std::numeric_limits<DWORD>::max() < builder.size()) |
| 649 return false; | 1035 return false; |
| 650 | 1036 |
| 651 return SetRegKeyValue( | 1037 return SetRegKeyValue( |
| 652 key, value_name, REG_MULTI_SZ, reinterpret_cast<BYTE*>(builder.data()), | 1038 key, value_name, REG_MULTI_SZ, reinterpret_cast<BYTE*>(builder.data()), |
| 653 (static_cast<DWORD>(builder.size()) + 1) * sizeof(wchar_t)); | 1039 (static_cast<DWORD>(builder.size()) + 1) * sizeof(wchar_t)); |
| 654 } | 1040 } |
| 655 | 1041 |
| 656 // wrapper function | 1042 // wrapper function |
| 657 bool SetRegValueMULTISZ(ROOT_KEY root, | 1043 bool SetRegValueMULTISZ(ROOT_KEY root, |
| 1044 WOW64_OVERRIDE wow64_override, | |
| 658 const wchar_t* key_path, | 1045 const wchar_t* key_path, |
| 659 const wchar_t* value_name, | 1046 const wchar_t* value_name, |
| 660 const std::vector<std::wstring>& values) { | 1047 const std::vector<std::wstring>& values) { |
| 661 HANDLE key = INVALID_HANDLE_VALUE; | 1048 HANDLE key = INVALID_HANDLE_VALUE; |
| 662 | 1049 |
| 663 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL)) | 1050 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | wow64_override, &key, NULL)) |
| 664 return false; | 1051 return false; |
| 665 | 1052 |
| 666 if (!SetRegValueMULTISZ(key, value_name, values)) { | 1053 if (!SetRegValueMULTISZ(key, value_name, values)) { |
| 667 CloseRegKey(key); | 1054 CloseRegKey(key); |
| 668 return false; | 1055 return false; |
| 669 } | 1056 } |
| 670 | 1057 |
| 671 return true; | 1058 return true; |
| 672 } | 1059 } |
| 673 | 1060 |
| 674 //------------------------------------------------------------------------------ | 1061 //------------------------------------------------------------------------------ |
| 675 // Utils | 1062 // Utils |
| 676 //------------------------------------------------------------------------------ | 1063 //------------------------------------------------------------------------------ |
| 677 | 1064 |
| 678 const wchar_t* GetCurrentUserSidString() { | 1065 const wchar_t* GetCurrentUserSidString() { |
| 679 if (!g_initialized) | 1066 if (!g_initialized) |
| 680 InitNativeRegApi(); | 1067 InitNativeRegApi(); |
| 681 | 1068 |
| 682 return g_current_user_sid_string; | 1069 return g_current_user_sid_string; |
| 683 } | 1070 } |
| 684 | 1071 |
| 1072 bool IsCurrentProcWow64() { | |
| 1073 if (!g_initialized) | |
| 1074 InitNativeRegApi(); | |
| 1075 | |
| 1076 return g_wow64_proc; | |
| 1077 } | |
| 1078 | |
| 1079 bool SetTestingOverride(nt::ROOT_KEY root, const std::wstring& new_path) { | |
|
grt (UTC plus 2)
2016/09/30 09:32:16
nit: omit "nt::" here and below since this is with
penny
2016/10/01 01:44:25
Done.
| |
| 1080 if (!g_initialized) | |
| 1081 InitNativeRegApi(); | |
| 1082 | |
| 1083 std::wstring sani_new_path = new_path; | |
| 1084 SanitizeSubkeyPath(&sani_new_path); | |
| 1085 if (::wcsnlen(sani_new_path.c_str(), nt::g_kRegMaxPathLen + 1) == | |
|
grt (UTC plus 2)
2016/09/30 09:32:16
why not sani_new_path.length() > g_kRegMaxPathLen?
penny
2016/10/01 01:44:25
Thank you. And good question.
| |
| 1086 nt::g_kRegMaxPathLen + 1) | |
| 1087 return false; | |
| 1088 | |
| 1089 // Convert nt::AUTO to the appropriate root key. | |
| 1090 nt::ROOT_KEY temp_root = root; | |
| 1091 if (root == nt::AUTO) | |
| 1092 temp_root = g_system_install ? nt::HKLM : nt::HKCU; | |
| 1093 | |
| 1094 if (temp_root == nt::HKCU) | |
|
grt (UTC plus 2)
2016/09/30 09:32:16
how about doing away with temp_root and changing t
penny
2016/10/01 01:44:25
You know, for some reason I was thinking |root| ar
| |
| 1095 ::wcsncpy(g_HKCU_override, sani_new_path.c_str(), nt::g_kRegMaxPathLen); | |
| 1096 else | |
| 1097 ::wcsncpy(g_HKLM_override, sani_new_path.c_str(), nt::g_kRegMaxPathLen); | |
| 1098 | |
| 1099 return true; | |
| 1100 } | |
| 1101 | |
| 1102 void GetTestingOverride(nt::ROOT_KEY root, std::wstring* out_path) { | |
| 1103 if (!g_initialized) | |
| 1104 InitNativeRegApi(); | |
| 1105 | |
| 1106 // Convert nt::AUTO to the appropriate root key. | |
| 1107 nt::ROOT_KEY temp_root = root; | |
| 1108 if (root == nt::AUTO) | |
| 1109 temp_root = g_system_install ? nt::HKLM : nt::HKCU; | |
| 1110 | |
| 1111 if (temp_root == nt::HKCU) | |
| 1112 out_path->assign(g_HKCU_override); | |
| 1113 else | |
| 1114 out_path->assign(g_HKLM_override); | |
| 1115 } | |
| 1116 | |
| 685 }; // namespace nt | 1117 }; // namespace nt |
| OLD | NEW |