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