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 | |
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 Loading... | |
82 ::GetProcAddress(ntdll, "RtlFreeUnicodeString")); | 109 ::GetProcAddress(ntdll, "RtlFreeUnicodeString")); |
83 | 110 |
84 if (!rtl_current_user_string || !rtl_free_unicode_str) | 111 if (!rtl_current_user_string || !rtl_free_unicode_str) |
85 return false; | 112 return false; |
86 | 113 |
87 UNICODE_STRING current_user_reg_path; | 114 UNICODE_STRING current_user_reg_path; |
88 if (!NT_SUCCESS(rtl_current_user_string(¤t_user_reg_path))) | 115 if (!NT_SUCCESS(rtl_current_user_string(¤t_user_reg_path))) |
89 return false; | 116 return false; |
90 | 117 |
91 // Finish setting up global HKCU path. | 118 // Finish setting up global HKCU path. |
92 ::wcsncat(g_kRegPathHKCU, current_user_reg_path.Buffer, (g_kMaxPathLen - 1)); | 119 ::wcsncat(g_kRegPathHKCU, current_user_reg_path.Buffer, nt::g_kRegMaxPathLen); |
93 ::wcsncat(g_kRegPathHKCU, L"\\", | 120 ::wcsncat(g_kRegPathHKCU, L"\\", |
94 (g_kMaxPathLen - ::wcslen(g_kRegPathHKCU) - 1)); | 121 (nt::g_kRegMaxPathLen - ::wcslen(g_kRegPathHKCU))); |
95 // Keep the sid string as well. | 122 // Keep the sid string as well. |
96 wchar_t* ptr = ::wcsrchr(current_user_reg_path.Buffer, L'\\'); | 123 wchar_t* ptr = ::wcsrchr(current_user_reg_path.Buffer, L'\\'); |
97 ptr++; | 124 ptr++; |
98 ::wcsncpy(g_current_user_sid_string, ptr, (g_kMaxPathLen - 1)); | 125 ::wcsncpy(g_current_user_sid_string, ptr, nt::g_kRegMaxPathLen); |
99 rtl_free_unicode_str(¤t_user_reg_path); | 126 rtl_free_unicode_str(¤t_user_reg_path); |
100 | 127 |
101 // Figure out if we're a system or user install. | 128 // Figure out if this is a system or user install. |
102 g_system_install = IsThisProcSystem(); | 129 g_system_install = IsThisProcSystem(); |
103 | 130 |
131 // Figure out if this is a WOW64 process. | |
132 g_wow64_proc = IsThisProcWow64(); | |
133 | |
104 g_initialized = true; | 134 g_initialized = true; |
105 return true; | 135 return true; |
106 } | 136 } |
107 | 137 |
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, ¤t_path, | 599 if (!ParseFullRegPath(ConvertRootKey(root), redirected_key_path, |
238 &subkeys)) | 600 ¤t_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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
648 if (std::numeric_limits<DWORD>::max() < builder.size()) | 1034 if (std::numeric_limits<DWORD>::max() < builder.size()) |
649 return false; | 1035 return false; |
650 | 1036 |
651 return SetRegKeyValue( | 1037 return SetRegKeyValue( |
652 key, value_name, REG_MULTI_SZ, reinterpret_cast<BYTE*>(builder.data()), | 1038 key, value_name, REG_MULTI_SZ, reinterpret_cast<BYTE*>(builder.data()), |
653 (static_cast<DWORD>(builder.size()) + 1) * sizeof(wchar_t)); | 1039 (static_cast<DWORD>(builder.size()) + 1) * sizeof(wchar_t)); |
654 } | 1040 } |
655 | 1041 |
656 // wrapper function | 1042 // wrapper function |
657 bool SetRegValueMULTISZ(ROOT_KEY root, | 1043 bool SetRegValueMULTISZ(ROOT_KEY root, |
1044 WOW64_OVERRIDE wow64_override, | |
658 const wchar_t* key_path, | 1045 const wchar_t* key_path, |
659 const wchar_t* value_name, | 1046 const wchar_t* value_name, |
660 const std::vector<std::wstring>& values) { | 1047 const std::vector<std::wstring>& values) { |
661 HANDLE key = INVALID_HANDLE_VALUE; | 1048 HANDLE key = INVALID_HANDLE_VALUE; |
662 | 1049 |
663 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL)) | 1050 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | wow64_override, &key, NULL)) |
664 return false; | 1051 return false; |
665 | 1052 |
666 if (!SetRegValueMULTISZ(key, value_name, values)) { | 1053 if (!SetRegValueMULTISZ(key, value_name, values)) { |
667 CloseRegKey(key); | 1054 CloseRegKey(key); |
668 return false; | 1055 return false; |
669 } | 1056 } |
670 | 1057 |
671 return true; | 1058 return true; |
672 } | 1059 } |
673 | 1060 |
674 //------------------------------------------------------------------------------ | 1061 //------------------------------------------------------------------------------ |
675 // Utils | 1062 // Utils |
676 //------------------------------------------------------------------------------ | 1063 //------------------------------------------------------------------------------ |
677 | 1064 |
678 const wchar_t* GetCurrentUserSidString() { | 1065 const wchar_t* GetCurrentUserSidString() { |
679 if (!g_initialized) | 1066 if (!g_initialized) |
680 InitNativeRegApi(); | 1067 InitNativeRegApi(); |
681 | 1068 |
682 return g_current_user_sid_string; | 1069 return g_current_user_sid_string; |
683 } | 1070 } |
684 | 1071 |
1072 bool IsCurrentProcWow64() { | |
1073 if (!g_initialized) | |
1074 InitNativeRegApi(); | |
1075 | |
1076 return g_wow64_proc; | |
1077 } | |
1078 | |
1079 bool SetTestingOverride(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 |
OLD | NEW |