Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(214)

Side by Side Diff: chrome_elf/nt_registry/nt_registry.cc

Issue 2345913003: [chrome_elf] NTRegistry - added wow64 redirection support. (Closed)
Patch Set: Code review fixes, part 4. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
10 #include <regex>
11
7 namespace { 12 namespace {
8 13
9 // Function pointers used for registry access. 14 // Function pointers used for registry access.
10 RtlInitUnicodeStringFunction g_rtl_init_unicode_string = nullptr; 15 RtlInitUnicodeStringFunction g_rtl_init_unicode_string = nullptr;
11 NtCreateKeyFunction g_nt_create_key = nullptr; 16 NtCreateKeyFunction g_nt_create_key = nullptr;
12 NtDeleteKeyFunction g_nt_delete_key = nullptr; 17 NtDeleteKeyFunction g_nt_delete_key = nullptr;
13 NtOpenKeyExFunction g_nt_open_key_ex = nullptr; 18 NtOpenKeyExFunction g_nt_open_key_ex = nullptr;
14 NtCloseFunction g_nt_close = nullptr; 19 NtCloseFunction g_nt_close = nullptr;
15 NtQueryValueKeyFunction g_nt_query_value_key = nullptr; 20 NtQueryValueKeyFunction g_nt_query_value_key = nullptr;
16 NtSetValueKeyFunction g_nt_set_value_key = nullptr; 21 NtSetValueKeyFunction g_nt_set_value_key = nullptr;
17 22
18 // Lazy init. No concern about concurrency in chrome_elf. 23 // Lazy init. No concern about concurrency in chrome_elf.
19 bool g_initialized = false; 24 bool g_initialized = false;
20 bool g_system_install = false; 25 bool g_system_install = false;
21 bool g_reg_redirection = false; 26 bool g_wow64_proc = false;
22 const size_t g_kMaxPathLen = 255;
23 wchar_t g_kRegPathHKLM[] = L"\\Registry\\Machine\\"; 27 wchar_t g_kRegPathHKLM[] = L"\\Registry\\Machine\\";
24 wchar_t g_kRegPathHKCU[g_kMaxPathLen] = L""; 28 wchar_t g_kRegPathHKCU[nt::g_kRegMaxPathLen + 1] = L"";
25 wchar_t g_current_user_sid_string[g_kMaxPathLen] = L""; 29 wchar_t g_current_user_sid_string[nt::g_kRegMaxPathLen + 1] = L"";
26 wchar_t g_override_path[g_kMaxPathLen] = 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
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(&current_user_reg_path))) 115 if (!NT_SUCCESS(rtl_current_user_string(&current_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(&current_user_reg_path); 126 rtl_free_unicode_str(&current_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
108 const wchar_t* ConvertRootKey(nt::ROOT_KEY root) { 138 //------------------------------------------------------------------------------
109 nt::ROOT_KEY key = root; 139 // Reg WOW64 Redirection - LOCAL
110 140 //
111 if (!root) { 141 // How registry redirection works directly calling NTDLL APIs:
112 // AUTO 142 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
113 key = g_system_install ? nt::HKLM : nt::HKCU; 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 assert(root != nt::AUTO);
325
326 // |subkey_path| could legitimately be empty.
327 if (subkey_path->empty() ||
328 (access & KEY_WOW64_32KEY && access & KEY_WOW64_64KEY))
329 return;
330
331 // No redirection during testing when there's already an override.
332 // Otherwise, the testing redirect directory Software\Chromium\TempTestKeys
333 // would get WOW64 redirected if root_key == HKLM in this function.
334 if ((root == nt::HKCU && *g_HKCU_override) ||
grt (UTC plus 2) 2016/10/02 20:10:54 wdyt: if (root == nt::HKCU ? *g_HKCU_override :
penny 2016/10/03 19:18:48 Nice one.
335 (root == nt::HKLM && *g_HKLM_override))
336 return;
337
338 // WOW64 redirection only supported on x64 architecture. Return if x86.
339 SYSTEM_INFO system_info = {};
340 ::GetNativeSystemInfo(&system_info);
341 if (system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
342 return;
343
344 bool use_wow64 = g_wow64_proc;
345 // Consider KEY_WOW64_32KEY and KEY_WOW64_64KEY override access flags.
346 if (access & KEY_WOW64_32KEY)
347 use_wow64 = true;
348 if (access & KEY_WOW64_64KEY)
349 use_wow64 = false;
350
351 // If !use_wow64, there's nothing more to do.
352 if (!use_wow64)
353 return;
354
355 // The root of the decision trees are an array of 1.
356 size_t node_array_len = 1;
357 // Pick which decision tree to use.
358 const Node* current_node = (root == nt::HKCU) ? &kRedirectionDecisionTreeHkcu
359 : &kRedirectionDecisionTreeHklm;
360
361 // The following loop works on the |subkey_path| from left to right.
362 // |position| tracks progress along |subkey_path|.
363 const wchar_t* position = subkey_path->c_str();
364 // Hold a count of chars left after position, for efficient calculations.
365 size_t chars_left = subkey_path->length();
366 // |redirect_state| holds the latest state of redirection requirement.
367 RedirectionType redirect_state = SHARED;
368 // |insertion_point| tracks latest spot for redirection subkey to be inserted.
369 const wchar_t* insertion_point = nullptr;
370 // |insert_string| tracks which redirection string would be inserted.
371 const wchar_t* insert_string = nullptr;
372
373 size_t node_index = 0;
374 while (node_index < node_array_len) {
375 size_t current_to_match_len = current_node->to_match_len;
376 // Make sure the remainder of the path is at least as long as the current
377 // subkey to match.
378 if (chars_left >= current_to_match_len) {
379 // Do case insensitive comparisons.
380 if (!::wcsnicmp(position, current_node->to_match, current_to_match_len)) {
381 // Make sure not to match on a substring.
382 if (*(position + current_to_match_len) == L'\\' ||
383 *(position + current_to_match_len) == L'\0') {
384 // MATCH!
385 // -------------------------------------------------------------------
386 // 1) Update state of redirection.
387 redirect_state = current_node->redirection_type;
388 // 1.5) If new state is to redirect, the new insertion point will be
389 // either right before or right after this match.
390 if (redirect_state == REDIRECTED_BEFORE) {
391 insertion_point = position;
392 insert_string = kRedirectBefore;
393 } else if (redirect_state == REDIRECTED_AFTER) {
394 insertion_point = position + current_to_match_len;
395 insert_string = kRedirectAfter;
396 }
397 // 2) Adjust |position| along the subkey path.
398 position += current_to_match_len;
399 chars_left -= current_to_match_len;
400 // 2.5) Increment the position, to move past path seperator(s).
401 while (*position == L'\\') {
402 ++position;
403 --chars_left;
404 }
405 // 3) Move our loop parameters to the |next| array of Nodes.
406 node_array_len = current_node->next_len;
407 current_node = current_node->next;
408 node_index = 0;
409 // 4) Finish this loop and start on new array.
410 continue;
411 }
412 }
413 }
414
415 // Move to the next node in the array if we didn't match this loop.
416 ++current_node;
417 ++node_index;
114 } 418 }
115 419
116 if ((key == nt::HKCU) && (::wcslen(nt::HKCU_override) != 0)) { 420 if (redirect_state == SHARED)
117 std::wstring temp(g_kRegPathHKCU); 421 return;
118 temp.append(nt::HKCU_override); 422
423 // Insert the redirection into |subkey_path|, at |insertion_point|.
424 subkey_path->insert((insertion_point - subkey_path->c_str()), insert_string);
425 }
426
427 //------------------------------------------------------------------------------
428 // Reg Path Utilities - LOCAL
429 //------------------------------------------------------------------------------
430
431 std::wstring ConvertRootKey(nt::ROOT_KEY root) {
432 assert(root != nt::AUTO);
433 std::wstring temp;
434
435 if (root == nt::HKCU && *g_HKCU_override) {
436 temp = g_kRegPathHKCU;
437 temp.append(g_HKCU_override);
119 temp.append(L"\\"); 438 temp.append(L"\\");
120 ::wcsncpy(g_override_path, temp.c_str(), g_kMaxPathLen - 1); 439 return temp;
121 g_reg_redirection = true; 440 } else if (root == nt::HKLM && *g_HKLM_override) {
122 return g_override_path; 441 // Yes, HKLM override goes into HKCU. This is not a typo.
123 } else if ((key == nt::HKLM) && (::wcslen(nt::HKLM_override) != 0)) { 442 temp = g_kRegPathHKCU;
124 std::wstring temp(g_kRegPathHKCU); 443 temp.append(g_HKLM_override);
125 temp.append(nt::HKLM_override);
126 temp.append(L"\\"); 444 temp.append(L"\\");
127 ::wcsncpy(g_override_path, temp.c_str(), g_kMaxPathLen - 1); 445 return temp;
128 g_reg_redirection = true;
129 return g_override_path;
130 } 446 }
131 447
132 g_reg_redirection = false; 448 if (root == nt::HKCU)
grt (UTC plus 2) 2016/10/02 20:10:54 return root == nt::HKCU ? g_kRegPathHKCU : g_kRegP
penny 2016/10/03 19:18:48 Except that the globals are wchar_t arrays, and I
grt (UTC plus 2) 2016/10/03 20:17:44 That's fine. I thought wstring's ctor that takes a
penny 2016/10/03 20:46:03 MIND BLOWN AGAIN. Implicit constructors. I don't
133 if (key == nt::HKCU) 449 temp = g_kRegPathHKCU;
134 return g_kRegPathHKCU;
135 else 450 else
136 return g_kRegPathHKLM; 451 temp = g_kRegPathHKLM;
452 return temp;
453 }
454
455 // This utility should be called on an externally provided subkey path.
456 // - Ensures there are no starting or trailing backslashes, and no more than
457 // - one backslash in a row.
458 // - Note from MSDN: "Key names cannot include the backslash character (\),
459 // but any other printable character can be used. Value names and data can
460 // include the backslash character."
461 void SanitizeSubkeyPath(std::wstring* input) {
462 assert(input != nullptr);
463
464 // Remove trailing backslashes.
465 size_t last_valid_pos = input->find_last_not_of(L'\\');
466 if (last_valid_pos == std::wstring::npos) {
467 // The string is all backslashes, or it's empty. Clear and abort.
468 input->clear();
469 return;
470 }
471 // Chop off the trailing backslashes.
472 input->resize(last_valid_pos + 1);
473
474 // Remove leading backslashes.
475 input->erase(0, input->find_first_not_of(L'\\'));
476
477 // Replace any occurances of more than 2 backslashes in a row with just 1.
grt (UTC plus 2) 2016/10/02 20:10:54 more than two in a row or more than one in a row?
penny 2016/10/03 19:18:48 Thank you.
478 // Since regex_replace will create a string copy, only do that if there is
479 // an occurance (most of the time I don't think this will be required).
480 std::wregex regex(L"\\\\{2,}");
grt (UTC plus 2) 2016/10/02 20:10:54 std::regex is banned: http://chromium-cpp.appspot.
penny 2016/10/03 19:18:48 <SIGH> I've removed the regex use, as it's not wor
481 if (std::regex_search(*input, regex))
482 *input = std::regex_replace(*input, regex, L"\\");
137 } 483 }
138 484
139 // Turns a root and subkey path into the registry base hive and the rest of the 485 // Turns a root and subkey path into the registry base hive and the rest of the
140 // subkey tokens. 486 // subkey tokens.
141 // - |converted_root| should come directly out of ConvertRootKey function. 487 // - |converted_root| should come directly out of ConvertRootKey function.
488 // - |subkey_path| should be passed to SanitizeSubkeyPath() first.
142 // - E.g. base hive: "\Registry\Machine\", "\Registry\User\<SID>\". 489 // - E.g. base hive: "\Registry\Machine\", "\Registry\User\<SID>\".
143 bool ParseFullRegPath(const wchar_t* converted_root, 490 bool ParseFullRegPath(const std::wstring& converted_root,
144 const wchar_t* subkey_path, 491 const std::wstring& subkey_path,
145 std::wstring* out_base, 492 std::wstring* out_base,
146 std::vector<std::wstring>* subkeys) { 493 std::vector<std::wstring>* subkeys) {
147 out_base->clear(); 494 out_base->clear();
148 subkeys->clear(); 495 subkeys->clear();
149 std::wstring temp = L""; 496 std::wstring temp_path;
150 497
151 if (g_reg_redirection) { 498 // Special case if there is testing redirection set up.
499 if (*g_HKCU_override || *g_HKLM_override) {
152 // Why process |converted_root|? To handle reg redirection used by tests. 500 // Why process |converted_root|? To handle reg redirection used by tests.
153 // E.g.: 501 // E.g.:
154 // |converted_root| = "\REGISTRY\USER\S-1-5-21-39260824-743453154-142223018- 502 // |converted_root| = "\REGISTRY\USER\S-1-5-21-39260824-743453154-142223018-
155 // 716772\Software\Chromium\TempTestKeys\13110669370890870$94c6ed9d-bc34- 503 // 716772\Software\Chromium\TempTestKeys\13110669370890870$94c6ed9d-bc34-
156 // 44f3-a0b3-9eee2d3f2f82\". 504 // 44f3-a0b3-9eee2d3f2f82\".
157 // |subkey_path| = "SOFTWARE\Google\Chrome\BrowserSec". 505 // |subkey_path| = "SOFTWARE\Google\Chrome\BrowserSec".
158 temp.append(converted_root); 506 temp_path.append(converted_root, 1);
grt (UTC plus 2) 2016/10/02 20:10:54 why ", 1"? is this to omit the leading '\' in the
penny 2016/10/03 19:18:48 TIL
159 } 507 }
160 if (subkey_path != nullptr) 508 temp_path.append(subkey_path);
161 temp.append(subkey_path);
162 509
163 // Tokenize the full path. 510 // Tokenize the full path.
164 size_t find_start = 0; 511 size_t find_start = 0;
165 size_t delimiter = temp.find_first_of(L'\\'); 512 size_t delimiter = temp_path.find_first_of(L'\\');
166 while (delimiter != std::wstring::npos) { 513 while (delimiter != std::wstring::npos) {
167 std::wstring token = temp.substr(find_start, delimiter - find_start); 514 subkeys->emplace_back(temp_path, find_start, delimiter - find_start);
168 if (!token.empty()) 515 // Move past the backslash.
169 subkeys->push_back(token);
170 find_start = delimiter + 1; 516 find_start = delimiter + 1;
171 delimiter = temp.find_first_of(L'\\', find_start); 517 delimiter = temp_path.find_first_of(L'\\', find_start);
172 } 518 }
173 if (!temp.empty() && find_start < temp.length()) 519 if (!temp_path.empty())
grt (UTC plus 2) 2016/10/02 20:10:54 nit: need braces here since the comment makes the
penny 2016/10/03 19:18:49 Done. Is this comment case a Chromium standard? (
grt (UTC plus 2) 2016/10/03 20:17:44 Yup. It's been discussed here and there on chromiu
penny 2016/10/03 20:46:03 Acknowledged.
174 // Get the last token. 520 // Get the last token.
175 subkeys->push_back(temp.substr(find_start)); 521 subkeys->emplace_back(temp_path, find_start);
176 522
177 if (g_reg_redirection) { 523 // Special case if there is testing redirection set up.
524 if (*g_HKCU_override || *g_HKLM_override) {
178 // The base hive for HKCU needs to include the user SID. 525 // The base hive for HKCU needs to include the user SID.
179 uint32_t num_base_tokens = 2; 526 uint32_t num_base_tokens = 2;
180 const wchar_t* hkcu = L"\\REGISTRY\\USER\\"; 527 if (0 == temp_path.compare(0, 14, L"REGISTRY\\USER\\"))
181 if (0 == ::wcsnicmp(converted_root, hkcu, ::wcslen(hkcu)))
182 num_base_tokens = 3; 528 num_base_tokens = 3;
183 529
184 if (subkeys->size() < num_base_tokens) 530 if (subkeys->size() < num_base_tokens)
185 return false; 531 return false;
186 532
187 // Pull out the base hive tokens. 533 // Pull out the base hive tokens.
188 out_base->push_back(L'\\'); 534 out_base->push_back(L'\\');
189 for (size_t i = 0; i < num_base_tokens; i++) { 535 for (size_t i = 0; i < num_base_tokens; ++i) {
190 out_base->append((*subkeys)[i].c_str()); 536 out_base->append((*subkeys)[i]);
191 out_base->push_back(L'\\'); 537 out_base->push_back(L'\\');
192 } 538 }
193 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens); 539 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens);
194 } else { 540 } else {
195 out_base->assign(converted_root); 541 out_base->assign(converted_root);
196 } 542 }
197 543
198 return true; 544 return true;
199 } 545 }
200 546
547 //------------------------------------------------------------------------------
548 // Misc wrapper functions - LOCAL
549 //------------------------------------------------------------------------------
550
201 NTSTATUS CreateKeyWrapper(const std::wstring& key_path, 551 NTSTATUS CreateKeyWrapper(const std::wstring& key_path,
202 ACCESS_MASK access, 552 ACCESS_MASK access,
203 HANDLE* out_handle, 553 HANDLE* out_handle,
204 ULONG* create_or_open OPTIONAL) { 554 ULONG* create_or_open OPTIONAL) {
205 UNICODE_STRING key_path_uni = {}; 555 UNICODE_STRING key_path_uni = {};
206 g_rtl_init_unicode_string(&key_path_uni, key_path.c_str()); 556 g_rtl_init_unicode_string(&key_path_uni, key_path.c_str());
207 557
208 OBJECT_ATTRIBUTES obj = {}; 558 OBJECT_ATTRIBUTES obj = {};
209 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL, 559 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL,
210 nullptr); 560 nullptr);
211 561
212 return g_nt_create_key(out_handle, access, &obj, 0, nullptr, 562 return g_nt_create_key(out_handle, access, &obj, 0, nullptr,
213 REG_OPTION_NON_VOLATILE, create_or_open); 563 REG_OPTION_NON_VOLATILE, create_or_open);
214 } 564 }
215 565
216 } // namespace 566 } // namespace
217 567
218 namespace nt { 568 namespace nt {
219 569
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 //------------------------------------------------------------------------------ 570 //------------------------------------------------------------------------------
225 // Create, open, delete, close functions 571 // Create, open, delete, close functions
226 //------------------------------------------------------------------------------ 572 //------------------------------------------------------------------------------
227 573
228 bool CreateRegKey(ROOT_KEY root, 574 bool CreateRegKey(ROOT_KEY root,
229 const wchar_t* key_path, 575 const wchar_t* key_path,
230 ACCESS_MASK access, 576 ACCESS_MASK access,
231 HANDLE* out_handle OPTIONAL) { 577 HANDLE* out_handle OPTIONAL) {
578 // |key_path| can be null or empty, but it can't be longer than
579 // |g_kRegMaxPathLen| at this point.
580 if (key_path != nullptr &&
581 ::wcsnlen(key_path, g_kRegMaxPathLen + 1) == g_kRegMaxPathLen + 1)
582 return false;
583
232 if (!g_initialized) 584 if (!g_initialized)
233 InitNativeRegApi(); 585 InitNativeRegApi();
234 586
587 if (root == nt::AUTO)
588 root = g_system_install ? nt::HKLM : nt::HKCU;
589
590 std::wstring redirected_key_path;
591 if (key_path) {
592 redirected_key_path = key_path;
593 SanitizeSubkeyPath(&redirected_key_path);
594 ProcessRedirection(root, access, &redirected_key_path);
595 }
596
235 std::wstring current_path; 597 std::wstring current_path;
236 std::vector<std::wstring> subkeys; 598 std::vector<std::wstring> subkeys;
237 if (!ParseFullRegPath(ConvertRootKey(root), key_path, &current_path, 599 if (!ParseFullRegPath(ConvertRootKey(root), redirected_key_path,
238 &subkeys)) 600 &current_path, &subkeys))
239 return false; 601 return false;
240 602
241 // Open the base hive first. It should always exist already. 603 // Open the base hive first. It should always exist already.
242 HANDLE last_handle = INVALID_HANDLE_VALUE; 604 HANDLE last_handle = INVALID_HANDLE_VALUE;
243 NTSTATUS status = 605 NTSTATUS status =
244 CreateKeyWrapper(current_path, access, &last_handle, nullptr); 606 CreateKeyWrapper(current_path, access, &last_handle, nullptr);
245 if (!NT_SUCCESS(status)) 607 if (!NT_SUCCESS(status))
246 return false; 608 return false;
247 609
248 size_t subkeys_size = subkeys.size(); 610 size_t subkeys_size = subkeys.size();
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 g_nt_close(last_handle); 659 g_nt_close(last_handle);
298 660
299 return true; 661 return true;
300 } 662 }
301 663
302 bool OpenRegKey(ROOT_KEY root, 664 bool OpenRegKey(ROOT_KEY root,
303 const wchar_t* key_path, 665 const wchar_t* key_path,
304 ACCESS_MASK access, 666 ACCESS_MASK access,
305 HANDLE* out_handle, 667 HANDLE* out_handle,
306 NTSTATUS* error_code OPTIONAL) { 668 NTSTATUS* error_code OPTIONAL) {
669 // |key_path| can be null or empty, but it can't be longer than
670 // |g_kRegMaxPathLen| at this point.
671 if (key_path != nullptr &&
672 ::wcsnlen(key_path, g_kRegMaxPathLen + 1) == g_kRegMaxPathLen + 1)
673 return false;
674
307 if (!g_initialized) 675 if (!g_initialized)
308 InitNativeRegApi(); 676 InitNativeRegApi();
309 677
310 NTSTATUS status = STATUS_UNSUCCESSFUL; 678 NTSTATUS status = STATUS_UNSUCCESSFUL;
311 UNICODE_STRING key_path_uni = {}; 679 UNICODE_STRING key_path_uni = {};
312 OBJECT_ATTRIBUTES obj = {}; 680 OBJECT_ATTRIBUTES obj = {};
313 *out_handle = INVALID_HANDLE_VALUE; 681 *out_handle = INVALID_HANDLE_VALUE;
314 682
315 std::wstring full_path(ConvertRootKey(root)); 683 if (root == nt::AUTO)
316 full_path.append(key_path); 684 root = g_system_install ? nt::HKLM : nt::HKCU;
685
686 std::wstring full_path;
687 if (key_path) {
688 full_path = key_path;
689 SanitizeSubkeyPath(&full_path);
690 ProcessRedirection(root, access, &full_path);
691 }
692 full_path.insert(0, ConvertRootKey(root));
317 693
318 g_rtl_init_unicode_string(&key_path_uni, full_path.c_str()); 694 g_rtl_init_unicode_string(&key_path_uni, full_path.c_str());
319 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL, 695 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL,
320 NULL); 696 NULL);
321 697
322 status = g_nt_open_key_ex(out_handle, access, &obj, 0); 698 status = g_nt_open_key_ex(out_handle, access, &obj, 0);
323 // See if caller wants the NTSTATUS. 699 // See if caller wants the NTSTATUS.
324 if (error_code) 700 if (error_code)
325 *error_code = status; 701 *error_code = status;
326 702
(...skipping 11 matching lines...) Expand all
338 714
339 status = g_nt_delete_key(key); 715 status = g_nt_delete_key(key);
340 716
341 if (NT_SUCCESS(status)) 717 if (NT_SUCCESS(status))
342 return true; 718 return true;
343 719
344 return false; 720 return false;
345 } 721 }
346 722
347 // wrapper function 723 // wrapper function
348 bool DeleteRegKey(ROOT_KEY root, const wchar_t* key_path) { 724 bool DeleteRegKey(ROOT_KEY root,
725 WOW64_OVERRIDE wow64_override,
726 const wchar_t* key_path) {
349 HANDLE key = INVALID_HANDLE_VALUE; 727 HANDLE key = INVALID_HANDLE_VALUE;
350 728
351 if (!OpenRegKey(root, key_path, DELETE, &key, nullptr)) 729 if (!OpenRegKey(root, key_path, DELETE | wow64_override, &key, nullptr))
352 return false; 730 return false;
353 731
354 if (!DeleteRegKey(key)) { 732 if (!DeleteRegKey(key)) {
355 CloseRegKey(key); 733 CloseRegKey(key);
356 return false; 734 return false;
357 } 735 }
358 736
359 CloseRegKey(key); 737 CloseRegKey(key);
360 return true; 738 return true;
361 } 739 }
362 740
363 void CloseRegKey(HANDLE key) { 741 void CloseRegKey(HANDLE key) {
364 if (!g_initialized) 742 if (!g_initialized)
365 InitNativeRegApi(); 743 InitNativeRegApi();
366 g_nt_close(key); 744 g_nt_close(key);
367 } 745 }
368 746
369 //------------------------------------------------------------------------------ 747 //------------------------------------------------------------------------------
370 // Getter functions 748 // Getter functions
371 //------------------------------------------------------------------------------ 749 //------------------------------------------------------------------------------
372 750
373 bool QueryRegKeyValue(HANDLE key, 751 bool QueryRegKeyValue(HANDLE key,
374 const wchar_t* value_name, 752 const wchar_t* value_name,
375 ULONG* out_type, 753 ULONG* out_type,
376 BYTE** out_buffer, 754 BYTE** out_buffer,
377 DWORD* out_size) { 755 DWORD* out_size) {
378 if (!g_initialized) 756 if (!g_initialized)
379 InitNativeRegApi(); 757 InitNativeRegApi();
380 758
759 if (value_name == nullptr || *value_name == L'\0')
grt (UTC plus 2) 2016/10/02 20:10:54 in advapi, nullptr and the empty string name a key
penny 2016/10/03 19:18:48 It's the same in ntoskrnl and ntdll. Thanks for n
760 return false;
761
381 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL; 762 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL;
382 UNICODE_STRING value_uni = {}; 763 UNICODE_STRING value_uni = {};
383 g_rtl_init_unicode_string(&value_uni, value_name); 764 g_rtl_init_unicode_string(&value_uni, value_name);
384 DWORD size_needed = 0; 765 DWORD size_needed = 0;
385 bool success = false; 766 bool success = false;
386 767
387 // First call to find out how much room we need for the value! 768 // First call to find out how much room we need for the value!
388 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, 769 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation,
389 nullptr, 0, &size_needed); 770 nullptr, 0, &size_needed);
390 if (ntstatus != STATUS_BUFFER_TOO_SMALL) 771 if (ntstatus != STATUS_BUFFER_TOO_SMALL)
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
423 return false; 804 return false;
424 805
425 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes)); 806 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes));
426 807
427 delete[] value_bytes; 808 delete[] value_bytes;
428 return true; 809 return true;
429 } 810 }
430 811
431 // wrapper function 812 // wrapper function
432 bool QueryRegValueDWORD(ROOT_KEY root, 813 bool QueryRegValueDWORD(ROOT_KEY root,
814 WOW64_OVERRIDE wow64_override,
433 const wchar_t* key_path, 815 const wchar_t* key_path,
434 const wchar_t* value_name, 816 const wchar_t* value_name,
435 DWORD* out_dword) { 817 DWORD* out_dword) {
436 HANDLE key = INVALID_HANDLE_VALUE; 818 HANDLE key = INVALID_HANDLE_VALUE;
437 819
438 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key, 820 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL))
439 NULL))
440 return false; 821 return false;
441 822
442 if (!QueryRegValueDWORD(key, value_name, out_dword)) { 823 if (!QueryRegValueDWORD(key, value_name, out_dword)) {
443 CloseRegKey(key); 824 CloseRegKey(key);
444 return false; 825 return false;
445 } 826 }
446 827
447 CloseRegKey(key); 828 CloseRegKey(key);
448 return true; 829 return true;
449 } 830 }
(...skipping 11 matching lines...) Expand all
461 return false; 842 return false;
462 843
463 *out_sz = reinterpret_cast<wchar_t*>(value_bytes); 844 *out_sz = reinterpret_cast<wchar_t*>(value_bytes);
464 845
465 delete[] value_bytes; 846 delete[] value_bytes;
466 return true; 847 return true;
467 } 848 }
468 849
469 // wrapper function 850 // wrapper function
470 bool QueryRegValueSZ(ROOT_KEY root, 851 bool QueryRegValueSZ(ROOT_KEY root,
852 WOW64_OVERRIDE wow64_override,
471 const wchar_t* key_path, 853 const wchar_t* key_path,
472 const wchar_t* value_name, 854 const wchar_t* value_name,
473 std::wstring* out_sz) { 855 std::wstring* out_sz) {
474 HANDLE key = INVALID_HANDLE_VALUE; 856 HANDLE key = INVALID_HANDLE_VALUE;
475 857
476 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key, 858 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL))
477 NULL))
478 return false; 859 return false;
479 860
480 if (!QueryRegValueSZ(key, value_name, out_sz)) { 861 if (!QueryRegValueSZ(key, value_name, out_sz)) {
481 CloseRegKey(key); 862 CloseRegKey(key);
482 return false; 863 return false;
483 } 864 }
484 865
485 CloseRegKey(key); 866 CloseRegKey(key);
486 return true; 867 return true;
487 } 868 }
(...skipping 27 matching lines...) Expand all
515 // Handle the case of "empty multi_sz". 896 // Handle the case of "empty multi_sz".
516 if (out_multi_sz->size() == 0) 897 if (out_multi_sz->size() == 0)
517 out_multi_sz->push_back(L""); 898 out_multi_sz->push_back(L"");
518 899
519 delete[] value_bytes; 900 delete[] value_bytes;
520 return true; 901 return true;
521 } 902 }
522 903
523 // wrapper function 904 // wrapper function
524 bool QueryRegValueMULTISZ(ROOT_KEY root, 905 bool QueryRegValueMULTISZ(ROOT_KEY root,
906 WOW64_OVERRIDE wow64_override,
525 const wchar_t* key_path, 907 const wchar_t* key_path,
526 const wchar_t* value_name, 908 const wchar_t* value_name,
527 std::vector<std::wstring>* out_multi_sz) { 909 std::vector<std::wstring>* out_multi_sz) {
528 HANDLE key = INVALID_HANDLE_VALUE; 910 HANDLE key = INVALID_HANDLE_VALUE;
529 911
530 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key, 912 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL))
531 NULL))
532 return false; 913 return false;
533 914
534 if (!QueryRegValueMULTISZ(key, value_name, out_multi_sz)) { 915 if (!QueryRegValueMULTISZ(key, value_name, out_multi_sz)) {
535 CloseRegKey(key); 916 CloseRegKey(key);
536 return false; 917 return false;
537 } 918 }
538 919
539 CloseRegKey(key); 920 CloseRegKey(key);
540 return true; 921 return true;
541 } 922 }
542 923
543 //------------------------------------------------------------------------------ 924 //------------------------------------------------------------------------------
544 // Setter functions 925 // Setter functions
545 //------------------------------------------------------------------------------ 926 //------------------------------------------------------------------------------
546 927
547 bool SetRegKeyValue(HANDLE key, 928 bool SetRegKeyValue(HANDLE key,
548 const wchar_t* value_name, 929 const wchar_t* value_name,
549 ULONG type, 930 ULONG type,
550 const BYTE* data, 931 const BYTE* data,
551 DWORD data_size) { 932 DWORD data_size) {
552 if (!g_initialized) 933 if (!g_initialized)
553 InitNativeRegApi(); 934 InitNativeRegApi();
554 935
936 if (value_name == nullptr || *value_name == L'\0')
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
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(ROOT_KEY root, const std::wstring& new_path) {
1080 if (!g_initialized)
1081 InitNativeRegApi();
1082
1083 std::wstring sani_new_path = new_path;
1084 SanitizeSubkeyPath(&sani_new_path);
1085 if (sani_new_path.length() > g_kRegMaxPathLen)
1086 return false;
1087
1088 if (root == HKCU || (root == AUTO && !g_system_install))
1089 ::wcsncpy(g_HKCU_override, sani_new_path.c_str(), nt::g_kRegMaxPathLen);
1090 else
1091 ::wcsncpy(g_HKLM_override, sani_new_path.c_str(), nt::g_kRegMaxPathLen);
1092
1093 return true;
1094 }
1095
1096 std::wstring GetTestingOverride(ROOT_KEY root) {
1097 if (!g_initialized)
1098 InitNativeRegApi();
1099
1100 std::wstring temp;
grt (UTC plus 2) 2016/10/02 20:10:54 nit: get rid of temp and return the value directly
penny 2016/10/03 19:18:48 Again, these globals are wchar_t arrays and I want
grt (UTC plus 2) 2016/10/03 20:17:44 I think the implicit ctor will kick in if you "ret
penny 2016/10/03 20:46:03 CRAY-Z.
1101 if (root == HKCU || (root == AUTO && !g_system_install))
1102 temp = g_HKCU_override;
1103 else
1104 temp = g_HKLM_override;
1105
1106 return temp;
1107 }
1108
685 }; // namespace nt 1109 }; // namespace nt
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698