OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome_elf/nt_registry/nt_registry.h" | 5 #include "chrome_elf/nt_registry/nt_registry.h" |
6 | 6 |
7 #include <assert.h> | |
8 #include <stdlib.h> | |
9 | |
7 namespace { | 10 namespace { |
8 | 11 |
9 // Function pointers used for registry access. | 12 // Function pointers used for registry access. |
10 RtlInitUnicodeStringFunction g_rtl_init_unicode_string = nullptr; | 13 RtlInitUnicodeStringFunction g_rtl_init_unicode_string = nullptr; |
11 NtCreateKeyFunction g_nt_create_key = nullptr; | 14 NtCreateKeyFunction g_nt_create_key = nullptr; |
12 NtDeleteKeyFunction g_nt_delete_key = nullptr; | 15 NtDeleteKeyFunction g_nt_delete_key = nullptr; |
13 NtOpenKeyExFunction g_nt_open_key_ex = nullptr; | 16 NtOpenKeyExFunction g_nt_open_key_ex = nullptr; |
14 NtCloseFunction g_nt_close = nullptr; | 17 NtCloseFunction g_nt_close = nullptr; |
15 NtQueryValueKeyFunction g_nt_query_value_key = nullptr; | 18 NtQueryValueKeyFunction g_nt_query_value_key = nullptr; |
16 NtSetValueKeyFunction g_nt_set_value_key = nullptr; | 19 NtSetValueKeyFunction g_nt_set_value_key = nullptr; |
17 | 20 |
18 // Lazy init. No concern about concurrency in chrome_elf. | 21 // Lazy init. No concern about concurrency in chrome_elf. |
19 bool g_initialized = false; | 22 bool g_initialized = false; |
20 bool g_system_install = false; | 23 bool g_system_install = false; |
24 bool g_wow64_proc = false; | |
21 bool g_reg_redirection = false; | 25 bool g_reg_redirection = false; |
22 const size_t g_kMaxPathLen = 255; | 26 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[g_kMaxPathLen] = L""; |
25 wchar_t g_current_user_sid_string[g_kMaxPathLen] = L""; | 29 wchar_t g_current_user_sid_string[g_kMaxPathLen] = L""; |
26 wchar_t g_override_path[g_kMaxPathLen] = L""; | 30 wchar_t g_override_path[g_kMaxPathLen] = L""; |
27 | 31 |
28 // Not using install_util, to prevent circular dependency. | 32 //------------------------------------------------------------------------------ |
33 // Initialization - LOCAL | |
34 //------------------------------------------------------------------------------ | |
35 | |
36 // Not using install_static, to prevent circular dependency. | |
29 bool IsThisProcSystem() { | 37 bool IsThisProcSystem() { |
30 wchar_t program_dir[MAX_PATH] = {}; | 38 wchar_t program_dir[MAX_PATH] = {}; |
31 wchar_t* cmd_line = GetCommandLineW(); | 39 wchar_t* cmd_line = GetCommandLineW(); |
32 // If our command line starts with the "Program Files" or | 40 // If our command line starts with the "Program Files" or |
33 // "Program Files (x86)" path, we're system. | 41 // "Program Files (x86)" path, we're system. |
34 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, MAX_PATH); | 42 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, MAX_PATH); |
35 if (ret && ret < MAX_PATH && !::wcsncmp(cmd_line, program_dir, ret)) | 43 if (ret && ret < MAX_PATH && !::wcsncmp(cmd_line, program_dir, ret)) |
36 return true; | 44 return true; |
37 | 45 |
38 ret = ::GetEnvironmentVariable(L"PROGRAMFILES(X86)", program_dir, MAX_PATH); | 46 ret = ::GetEnvironmentVariable(L"PROGRAMFILES(X86)", program_dir, MAX_PATH); |
39 if (ret && ret < MAX_PATH && !::wcsncmp(cmd_line, program_dir, ret)) | 47 if (ret && ret < MAX_PATH && !::wcsncmp(cmd_line, program_dir, ret)) |
40 return true; | 48 return true; |
41 | 49 |
42 return false; | 50 return false; |
43 } | 51 } |
44 | 52 |
53 bool IsThisProcWow64() { | |
54 // Using BOOL type for compat with IsWow64Process() system API. | |
55 BOOL is_wow64 = FALSE; | |
56 | |
57 // API might not exist, so dynamic lookup. | |
58 using IsWow64ProcessFunction = decltype(&IsWow64Process); | |
59 IsWow64ProcessFunction is_wow64_process = | |
60 reinterpret_cast<IsWow64ProcessFunction>(::GetProcAddress( | |
61 ::GetModuleHandle(L"kernel32.dll"), "IsWow64Process")); | |
62 if (!is_wow64_process) | |
63 return false; | |
64 if (!is_wow64_process(::GetCurrentProcess(), &is_wow64)) | |
65 return false; | |
66 return is_wow64 ? true : false; | |
67 } | |
68 | |
45 bool InitNativeRegApi() { | 69 bool InitNativeRegApi() { |
46 HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); | 70 HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); |
47 | 71 |
48 // Setup the global function pointers for registry access. | 72 // Setup the global function pointers for registry access. |
49 g_rtl_init_unicode_string = reinterpret_cast<RtlInitUnicodeStringFunction>( | 73 g_rtl_init_unicode_string = reinterpret_cast<RtlInitUnicodeStringFunction>( |
50 ::GetProcAddress(ntdll, "RtlInitUnicodeString")); | 74 ::GetProcAddress(ntdll, "RtlInitUnicodeString")); |
51 | 75 |
52 g_nt_create_key = reinterpret_cast<NtCreateKeyFunction>( | 76 g_nt_create_key = reinterpret_cast<NtCreateKeyFunction>( |
53 ::GetProcAddress(ntdll, "NtCreateKey")); | 77 ::GetProcAddress(ntdll, "NtCreateKey")); |
54 | 78 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
91 // Finish setting up global HKCU path. | 115 // Finish setting up global HKCU path. |
92 ::wcsncat(g_kRegPathHKCU, current_user_reg_path.Buffer, (g_kMaxPathLen - 1)); | 116 ::wcsncat(g_kRegPathHKCU, current_user_reg_path.Buffer, (g_kMaxPathLen - 1)); |
93 ::wcsncat(g_kRegPathHKCU, L"\\", | 117 ::wcsncat(g_kRegPathHKCU, L"\\", |
94 (g_kMaxPathLen - ::wcslen(g_kRegPathHKCU) - 1)); | 118 (g_kMaxPathLen - ::wcslen(g_kRegPathHKCU) - 1)); |
95 // Keep the sid string as well. | 119 // Keep the sid string as well. |
96 wchar_t* ptr = ::wcsrchr(current_user_reg_path.Buffer, L'\\'); | 120 wchar_t* ptr = ::wcsrchr(current_user_reg_path.Buffer, L'\\'); |
97 ptr++; | 121 ptr++; |
98 ::wcsncpy(g_current_user_sid_string, ptr, (g_kMaxPathLen - 1)); | 122 ::wcsncpy(g_current_user_sid_string, ptr, (g_kMaxPathLen - 1)); |
99 rtl_free_unicode_str(¤t_user_reg_path); | 123 rtl_free_unicode_str(¤t_user_reg_path); |
100 | 124 |
101 // Figure out if we're a system or user install. | 125 // Figure out if this is a system or user install. |
102 g_system_install = IsThisProcSystem(); | 126 g_system_install = IsThisProcSystem(); |
103 | 127 |
128 // Figure out if this is a WOW64 process. | |
129 g_wow64_proc = IsThisProcWow64(); | |
130 | |
104 g_initialized = true; | 131 g_initialized = true; |
105 return true; | 132 return true; |
106 } | 133 } |
107 | 134 |
135 //------------------------------------------------------------------------------ | |
136 // Reg WOW64 Redirection - LOCAL | |
137 // | |
138 // How registry redirection works directly calling NTDLL APIs: | |
139 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
140 // - NOTE: On >= Win7, reflection support was removed. | |
141 // - | |
142 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa384253(v=vs.85).as px | |
143 // | |
144 // - 1) 32-bit / WOW64 process: | |
145 // a) Default access WILL be redirected to WOW64. | |
146 // b) KEY_WOW64_32KEY access WILL be redirected to WOW64. | |
147 // c) KEY_WOW64_64KEY access will NOT be redirected to WOW64. | |
148 // | |
149 // - 2) 64-bit process: | |
150 // a) Default access will NOT be redirected to WOW64. | |
151 // b) KEY_WOW64_32KEY access will NOT be redirected to WOW64. | |
152 // c) KEY_WOW64_64KEY access will NOT be redirected to WOW64. | |
153 // | |
154 // - Key point from above is that NTDLL redirects and respects access | |
155 // overrides for WOW64 calling processes. But does NOT do any of that if the | |
156 // calling process is 64-bit. 2b is surprising and troublesome. | |
157 // | |
158 // How registry redirection works using these nt_registry APIs: | |
159 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
160 // - These APIs will behave the same as NTDLL above, EXCEPT for 2b. | |
161 // nt_registry APIs will respect the override access flags for all processes. | |
162 // | |
163 // - How the WOW64 redirection decision trees / Nodes work below: | |
164 // | |
165 // The HKLM and HKCU descision trees represent the information at the MSDN | |
166 // link above... but in a way that generates a decision about whether a | |
167 // registry path should be subject to WOW64 redirection. The tree is | |
168 // traversed as you scan along the registry path in question. | |
169 // | |
170 // - Each Node contains a chunk of registry subkey(s) to match. | |
171 // - If it is NOT matched, traversal is done. | |
172 // - If it is matched: | |
173 // - Current state of |redirection_type| for the whole registry path is | |
174 // updated. | |
175 // - If |next| is empty, traversal is done. | |
176 // - Otherwise, |next| is an array of child Nodes to try to match against. | |
177 // Loop. | |
178 //------------------------------------------------------------------------------ | |
179 | |
180 // This enum defines states for how to handle redirection. | |
181 // NOTE: When WOW64 redirection should happen, the redirect subkey can be either | |
182 // before or after the latest Node match. Unfortunately not consistent. | |
183 enum RedirectionType { SHARED = 0, REDIRECTED_BEFORE, REDIRECTED_AFTER }; | |
184 | |
185 struct Node { | |
186 template <size_t len> | |
187 constexpr Node(const wchar_t (&wcs)[len], | |
188 RedirectionType rt, | |
189 const Node* n, | |
190 size_t n_len) | |
191 : to_match(wcs), | |
192 to_match_len(len - 1), | |
193 redirection_type(rt), | |
194 next(n), | |
195 next_len(n_len) {} | |
196 | |
197 const wchar_t* to_match; | |
198 size_t to_match_len; | |
199 // If a match, this is the new state of how to redirect. | |
200 RedirectionType redirection_type; | |
201 // |next| is nullptr or an array of Nodes of length |array_len|. | |
202 const Node* next; | |
203 // NOTE: Could not auto compute this array length like above, as arrays of | |
grt (UTC plus 2)
2016/09/26 11:49:18
could you have a 2nd ctor for the leaf nodes that
penny
2016/09/28 22:36:51
Thanks - I've added a second constructor, which is
grt (UTC plus 2)
2016/09/29 10:30:21
Achievement unlocked!
| |
204 // size 0 are illegal. | |
205 size_t next_len; | |
206 }; | |
207 | |
208 // HKLM or HKCU SOFTWARE\Classes is shared by default. Specific subkeys under | |
209 // Classes are redirected to SOFTWARE\WOW6432Node\Classes\<subkey> though. | |
210 constexpr Node classes_subtree[] = { | |
211 {L"CLSID", REDIRECTED_BEFORE, nullptr, 0}, | |
212 {L"DirectShow", REDIRECTED_BEFORE, nullptr, 0}, | |
213 {L"Interface", REDIRECTED_BEFORE, nullptr, 0}, | |
214 {L"Media Type", REDIRECTED_BEFORE, nullptr, 0}, | |
215 {L"MediaFoundation", REDIRECTED_BEFORE, nullptr, 0}}; | |
216 | |
217 // These specific HKLM\SOFTWARE subkeys are shared. Specific | |
218 // subkeys under Classes are redirected though... see classes_subtree. | |
219 constexpr Node hklm_software_subtree[] = { | |
220 {L"Classes", SHARED, classes_subtree, _countof(classes_subtree)}, | |
221 | |
222 {L"Clients", SHARED, nullptr, 0}, | |
223 {L"Microsoft\\COM3", SHARED, nullptr, 0}, | |
224 {L"Microsoft\\Cryptography\\Calais\\Current", SHARED, nullptr, 0}, | |
225 {L"Microsoft\\Cryptography\\Calais\\Readers", SHARED, nullptr, 0}, | |
226 {L"Microsoft\\Cryptography\\Services", SHARED, nullptr, 0}, | |
227 | |
228 {L"Microsoft\\CTF\\SystemShared", SHARED, nullptr, 0}, | |
229 {L"Microsoft\\CTF\\TIP", SHARED, nullptr, 0}, | |
230 {L"Microsoft\\DFS", SHARED, nullptr, 0}, | |
231 {L"Microsoft\\Driver Signing", SHARED, nullptr, 0}, | |
232 {L"Microsoft\\EnterpriseCertificates", SHARED, nullptr, 0}, | |
233 | |
234 {L"Microsoft\\EventSystem", SHARED, nullptr, 0}, | |
235 {L"Microsoft\\MSMQ", SHARED, nullptr, 0}, | |
236 {L"Microsoft\\Non-Driver Signing", SHARED, nullptr, 0}, | |
237 {L"Microsoft\\Notepad\\DefaultFonts", SHARED, nullptr, 0}, | |
238 {L"Microsoft\\OLE", SHARED, nullptr, 0}, | |
239 | |
240 {L"Microsoft\\RAS", SHARED, nullptr, 0}, | |
241 {L"Microsoft\\RPC", SHARED, nullptr, 0}, | |
242 {L"Microsoft\\SOFTWARE\\Microsoft\\Shared Tools\\MSInfo", SHARED, nullptr, | |
243 0}, | |
244 {L"Microsoft\\SystemCertificates", SHARED, nullptr, 0}, | |
245 {L"Microsoft\\TermServLicensing", SHARED, nullptr, 0}, | |
246 | |
247 {L"Microsoft\\Transaction Server", SHARED, nullptr, 0}, | |
248 {L"Microsoft\\Windows\\CurrentVersion\\App Paths", SHARED, nullptr, 0}, | |
249 {L"Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cursors\\Schemes", | |
250 SHARED, nullptr, 0}, | |
251 {L"Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers", SHARED, | |
252 nullptr, 0}, | |
253 {L"Microsoft\\Windows\\CurrentVersion\\Explorer\\DriveIcons", SHARED, | |
254 nullptr, 0}, | |
255 | |
256 {L"Microsoft\\Windows\\CurrentVersion\\Explorer\\KindMap", SHARED, nullptr, | |
257 0}, | |
258 {L"Microsoft\\Windows\\CurrentVersion\\Group Policy", SHARED, nullptr, 0}, | |
259 {L"Microsoft\\Windows\\CurrentVersion\\Policies", SHARED, nullptr, 0}, | |
260 {L"Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", SHARED, nullptr, | |
261 0}, | |
262 {L"Microsoft\\Windows\\CurrentVersion\\Setup", SHARED, nullptr, 0}, | |
263 | |
264 {L"Microsoft\\Windows\\CurrentVersion\\Telephony\\Locations", SHARED, | |
265 nullptr, 0}, | |
266 {L"Microsoft\\Windows NT\\CurrentVersion\\Console", SHARED, nullptr, 0}, | |
267 {L"Microsoft\\Windows NT\\CurrentVersion\\FontDpi", SHARED, nullptr, 0}, | |
268 {L"Microsoft\\Windows NT\\CurrentVersion\\FontLink", SHARED, nullptr, 0}, | |
269 {L"Microsoft\\Windows NT\\CurrentVersion\\FontMapper", SHARED, nullptr, 0}, | |
270 | |
271 {L"Microsoft\\Windows NT\\CurrentVersion\\Fonts", SHARED, nullptr, 0}, | |
272 {L"Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", SHARED, nullptr, | |
273 0}, | |
274 {L"Microsoft\\Windows NT\\CurrentVersion\\Gre_Initialize", SHARED, nullptr, | |
275 0}, | |
276 {L"Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options", | |
277 SHARED, nullptr, 0}, | |
278 {L"Microsoft\\Windows NT\\CurrentVersion\\LanguagePack", SHARED, nullptr, | |
279 0}, | |
280 | |
281 {L"Microsoft\\Windows NT\\CurrentVersion\\NetworkCards", SHARED, nullptr, | |
282 0}, | |
283 {L"Microsoft\\Windows NT\\CurrentVersion\\Perflib", SHARED, nullptr, 0}, | |
284 {L"Microsoft\\Windows NT\\CurrentVersion\\Ports", SHARED, nullptr, 0}, | |
285 {L"Microsoft\\Windows NT\\CurrentVersion\\Print", SHARED, nullptr, 0}, | |
286 {L"Microsoft\\Windows NT\\CurrentVersion\\ProfileList", SHARED, nullptr, 0}, | |
287 | |
288 {L"Microsoft\\Windows NT\\CurrentVersion\\Time Zones", SHARED, nullptr, 0}, | |
289 {L"Policies", SHARED, nullptr, 0}, | |
290 {L"RegisteredApplications", SHARED, nullptr, 0}}; | |
291 | |
292 // HKCU is entirely shared, except for a few specific Classes subkeys which | |
293 // are redirected. See |classes_subtree|. | |
294 constexpr Node g_redirectionDecisionTreeHKCU = { | |
295 L"SOFTWARE\\Classes", SHARED, classes_subtree, _countof(classes_subtree)}; | |
296 | |
297 // HKLM\SOFTWARE is redirected by default to SOFTWARE\WOW6432Node. Specific | |
298 // subkeys under SOFTWARE are shared though... see |hklm_software_subtree|. | |
299 constexpr Node g_redirectionDecisionTreeHKLM = { | |
300 L"SOFTWARE", REDIRECTED_AFTER, hklm_software_subtree, | |
301 _countof(hklm_software_subtree)}; | |
302 | |
303 // Main redirection handler function. | |
304 // If redirection is required, change is made to |subkey_path| in place. | |
305 // | |
306 // This function should be called BEFORE concatenating |subkey_path| with the | |
307 // root hive or calling ParseFullRegPath(). Also, |subkey_path| should neither | |
308 // start nor end with a path seperator. | |
309 void ProcessRedirection(nt::ROOT_KEY root, | |
310 ACCESS_MASK access, | |
311 std::wstring* subkey_path) { | |
312 static constexpr wchar_t kRedirectBefore[] = L"WOW6432Node\\"; | |
313 static constexpr wchar_t kRedirectAfter[] = L"\\WOW6432Node"; | |
314 | |
315 if (subkey_path == nullptr || subkey_path->empty() || | |
316 (access & KEY_WOW64_32KEY && access & KEY_WOW64_64KEY)) | |
317 return; | |
318 | |
319 // Assert on states that should not happen. | |
320 if (subkey_path->front() == L'\\' || subkey_path->back() == L'\\') { | |
321 #ifdef _DEBUG | |
grt (UTC plus 2)
2016/09/26 11:49:18
nit: #ifndef NDEBUG (or, less common, #if !defined
penny
2016/09/28 22:36:51
We don't want any sort of break to happen in relea
| |
322 assert(false); | |
323 #endif // _DEBUG | |
324 return; | |
325 } | |
326 | |
327 // Convert nt::AUTO to the appropriate root key. | |
328 nt::ROOT_KEY temp_root = root; | |
329 if (root == nt::AUTO) | |
330 temp_root = g_system_install ? nt::HKLM : nt::HKCU; | |
331 | |
332 // No redirection during testing when there's already an override. | |
333 // Otherwise, the testing redirect directory Software\Chromium\TempTestKeys | |
334 // would get WOW64 redirected if root_key == HKLM in this function. | |
335 if ((temp_root == nt::HKCU && *nt::HKCU_override) || | |
336 (temp_root == nt::HKLM && *nt::HKLM_override)) | |
337 return; | |
338 | |
339 // WOW64 redirection only supported on x64 architecture. Return if x86. | |
340 SYSTEM_INFO system_info = {}; | |
341 ::GetNativeSystemInfo(&system_info); | |
342 if (system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) | |
343 return; | |
344 | |
345 bool use_wow64 = g_wow64_proc; | |
346 // Consider KEY_WOW64_32KEY and KEY_WOW64_64KEY override access flags. | |
347 if (access & KEY_WOW64_32KEY) | |
348 use_wow64 = true; | |
349 if (access & KEY_WOW64_64KEY) | |
350 use_wow64 = false; | |
351 | |
352 // If !use_wow64, there's nothing more to do. | |
353 if (!use_wow64) | |
354 return; | |
355 | |
356 // Pick which decision tree to use. | |
357 const Node* current = (temp_root == nt::HKCU) | |
358 ? &g_redirectionDecisionTreeHKCU | |
359 : &g_redirectionDecisionTreeHKLM; | |
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 pointer to the end of |subkey_path|, for calculations. | |
grt (UTC plus 2)
2016/09/26 11:49:17
nit: update comment
penny
2016/09/28 22:36:51
Done.
| |
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 // The root of the tree is an array of 1. | |
374 size_t array_len = 1; | |
375 size_t index = 0; | |
376 while (index < array_len) { | |
377 size_t len = current->to_match_len; | |
378 // Make sure the remainder of the path is at least as long as the current | |
379 // subkey to match. | |
380 if (chars_left >= len) { | |
381 // Do case insensitive comparisons. | |
382 if (::wcsnicmp(position, current->to_match, len) == 0) { | |
383 // Make sure not to match on a substring. | |
384 if (*(position + len) == L'\\' || *(position + len) == L'\0') { | |
385 // MATCH! | |
386 // ------------------------------------------------------------------- | |
387 // 1) Update state of redirection. | |
388 redirect_state = current->redirection_type; | |
389 if (redirect_state != SHARED) { | |
grt (UTC plus 2)
2016/09/26 11:49:17
nit: remove this outer conditional and change the
penny
2016/09/28 22:36:51
Done.
| |
390 // 1.5) The new insertion point will be either right before or right | |
391 // after this match. | |
392 if (redirect_state == REDIRECTED_BEFORE) { | |
393 insertion_point = position; | |
394 insert_string = kRedirectBefore; | |
395 } else { | |
396 insertion_point = position + len; | |
397 insert_string = kRedirectAfter; | |
398 } | |
399 } | |
400 // 2) Adjust |position| along the subkey path. | |
401 position += len; | |
402 chars_left -= len; | |
403 // 2.5) Increment the position, to move past path seperator(s). | |
404 while (*position == L'\\') { | |
405 ++position; | |
406 --chars_left; | |
407 } | |
408 // 3) Move our loop parameters to the |next| array of Nodes. | |
409 array_len = current->next_len; | |
410 current = current->next; | |
411 index = 0; | |
412 // 4) Finish this loop and start on new array. | |
413 continue; | |
414 } | |
415 } | |
416 } | |
417 | |
418 // Move to the next node in the array if we didn't match this loop. | |
419 ++current; | |
420 ++index; | |
421 } | |
422 | |
423 if (redirect_state == SHARED) | |
424 return; | |
425 | |
426 // Insert the redirection into |subkey_path|, at |insertion_point|. | |
427 subkey_path->insert((insertion_point - subkey_path->data()), insert_string); | |
428 } | |
429 | |
430 //------------------------------------------------------------------------------ | |
431 // Reg Path Utilities - LOCAL | |
432 //------------------------------------------------------------------------------ | |
433 | |
108 const wchar_t* ConvertRootKey(nt::ROOT_KEY root) { | 434 const wchar_t* ConvertRootKey(nt::ROOT_KEY root) { |
109 nt::ROOT_KEY key = root; | 435 nt::ROOT_KEY key = root; |
110 | 436 |
111 if (!root) { | 437 if (!root) { |
112 // AUTO | 438 // AUTO |
113 key = g_system_install ? nt::HKLM : nt::HKCU; | 439 key = g_system_install ? nt::HKLM : nt::HKCU; |
114 } | 440 } |
115 | 441 |
116 if ((key == nt::HKCU) && (::wcslen(nt::HKCU_override) != 0)) { | 442 if ((key == nt::HKCU) && (::wcslen(nt::HKCU_override) != 0)) { |
grt (UTC plus 2)
2016/09/26 11:49:17
nit: use * rather than wcslen here and below, too
penny
2016/09/28 22:36:51
Done. Thanks!
| |
117 std::wstring temp(g_kRegPathHKCU); | 443 std::wstring temp(g_kRegPathHKCU); |
118 temp.append(nt::HKCU_override); | 444 temp.append(nt::HKCU_override); |
119 temp.append(L"\\"); | 445 temp.append(L"\\"); |
120 ::wcsncpy(g_override_path, temp.c_str(), g_kMaxPathLen - 1); | 446 ::wcsncpy(g_override_path, temp.c_str(), g_kMaxPathLen - 1); |
121 g_reg_redirection = true; | 447 g_reg_redirection = true; |
122 return g_override_path; | 448 return g_override_path; |
123 } else if ((key == nt::HKLM) && (::wcslen(nt::HKLM_override) != 0)) { | 449 } else if ((key == nt::HKLM) && (::wcslen(nt::HKLM_override) != 0)) { |
124 std::wstring temp(g_kRegPathHKCU); | 450 std::wstring temp(g_kRegPathHKCU); |
125 temp.append(nt::HKLM_override); | 451 temp.append(nt::HKLM_override); |
126 temp.append(L"\\"); | 452 temp.append(L"\\"); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
191 out_base->push_back(L'\\'); | 517 out_base->push_back(L'\\'); |
192 } | 518 } |
193 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens); | 519 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens); |
194 } else { | 520 } else { |
195 out_base->assign(converted_root); | 521 out_base->assign(converted_root); |
196 } | 522 } |
197 | 523 |
198 return true; | 524 return true; |
199 } | 525 } |
200 | 526 |
527 //------------------------------------------------------------------------------ | |
528 // Misc wrapper functions - LOCAL | |
529 //------------------------------------------------------------------------------ | |
530 | |
201 NTSTATUS CreateKeyWrapper(const std::wstring& key_path, | 531 NTSTATUS CreateKeyWrapper(const std::wstring& key_path, |
202 ACCESS_MASK access, | 532 ACCESS_MASK access, |
203 HANDLE* out_handle, | 533 HANDLE* out_handle, |
204 ULONG* create_or_open OPTIONAL) { | 534 ULONG* create_or_open OPTIONAL) { |
205 UNICODE_STRING key_path_uni = {}; | 535 UNICODE_STRING key_path_uni = {}; |
206 g_rtl_init_unicode_string(&key_path_uni, key_path.c_str()); | 536 g_rtl_init_unicode_string(&key_path_uni, key_path.c_str()); |
207 | 537 |
208 OBJECT_ATTRIBUTES obj = {}; | 538 OBJECT_ATTRIBUTES obj = {}; |
209 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL, | 539 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL, |
210 nullptr); | 540 nullptr); |
(...skipping 14 matching lines...) Expand all Loading... | |
225 // Create, open, delete, close functions | 555 // Create, open, delete, close functions |
226 //------------------------------------------------------------------------------ | 556 //------------------------------------------------------------------------------ |
227 | 557 |
228 bool CreateRegKey(ROOT_KEY root, | 558 bool CreateRegKey(ROOT_KEY root, |
229 const wchar_t* key_path, | 559 const wchar_t* key_path, |
230 ACCESS_MASK access, | 560 ACCESS_MASK access, |
231 HANDLE* out_handle OPTIONAL) { | 561 HANDLE* out_handle OPTIONAL) { |
232 if (!g_initialized) | 562 if (!g_initialized) |
233 InitNativeRegApi(); | 563 InitNativeRegApi(); |
234 | 564 |
565 std::wstring redirected_key_path; | |
566 if (key_path) { | |
567 redirected_key_path = key_path; | |
568 ProcessRedirection(root, access, &redirected_key_path); | |
569 } | |
570 | |
235 std::wstring current_path; | 571 std::wstring current_path; |
236 std::vector<std::wstring> subkeys; | 572 std::vector<std::wstring> subkeys; |
237 if (!ParseFullRegPath(ConvertRootKey(root), key_path, ¤t_path, | 573 if (!ParseFullRegPath(ConvertRootKey(root), redirected_key_path.data(), |
238 &subkeys)) | 574 ¤t_path, &subkeys)) |
239 return false; | 575 return false; |
240 | 576 |
241 // Open the base hive first. It should always exist already. | 577 // Open the base hive first. It should always exist already. |
242 HANDLE last_handle = INVALID_HANDLE_VALUE; | 578 HANDLE last_handle = INVALID_HANDLE_VALUE; |
243 NTSTATUS status = | 579 NTSTATUS status = |
244 CreateKeyWrapper(current_path, access, &last_handle, nullptr); | 580 CreateKeyWrapper(current_path, access, &last_handle, nullptr); |
245 if (!NT_SUCCESS(status)) | 581 if (!NT_SUCCESS(status)) |
246 return false; | 582 return false; |
247 | 583 |
248 size_t subkeys_size = subkeys.size(); | 584 size_t subkeys_size = subkeys.size(); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
305 HANDLE* out_handle, | 641 HANDLE* out_handle, |
306 NTSTATUS* error_code OPTIONAL) { | 642 NTSTATUS* error_code OPTIONAL) { |
307 if (!g_initialized) | 643 if (!g_initialized) |
308 InitNativeRegApi(); | 644 InitNativeRegApi(); |
309 | 645 |
310 NTSTATUS status = STATUS_UNSUCCESSFUL; | 646 NTSTATUS status = STATUS_UNSUCCESSFUL; |
311 UNICODE_STRING key_path_uni = {}; | 647 UNICODE_STRING key_path_uni = {}; |
312 OBJECT_ATTRIBUTES obj = {}; | 648 OBJECT_ATTRIBUTES obj = {}; |
313 *out_handle = INVALID_HANDLE_VALUE; | 649 *out_handle = INVALID_HANDLE_VALUE; |
314 | 650 |
315 std::wstring full_path(ConvertRootKey(root)); | 651 std::wstring full_path; |
316 full_path.append(key_path); | 652 if (key_path) { |
653 full_path = key_path; | |
654 ProcessRedirection(root, access, &full_path); | |
655 } | |
656 full_path.insert(0, ConvertRootKey(root)); | |
317 | 657 |
318 g_rtl_init_unicode_string(&key_path_uni, full_path.c_str()); | 658 g_rtl_init_unicode_string(&key_path_uni, full_path.c_str()); |
319 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL, | 659 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL, |
320 NULL); | 660 NULL); |
321 | 661 |
322 status = g_nt_open_key_ex(out_handle, access, &obj, 0); | 662 status = g_nt_open_key_ex(out_handle, access, &obj, 0); |
323 // See if caller wants the NTSTATUS. | 663 // See if caller wants the NTSTATUS. |
324 if (error_code) | 664 if (error_code) |
325 *error_code = status; | 665 *error_code = status; |
326 | 666 |
(...skipping 11 matching lines...) Expand all Loading... | |
338 | 678 |
339 status = g_nt_delete_key(key); | 679 status = g_nt_delete_key(key); |
340 | 680 |
341 if (NT_SUCCESS(status)) | 681 if (NT_SUCCESS(status)) |
342 return true; | 682 return true; |
343 | 683 |
344 return false; | 684 return false; |
345 } | 685 } |
346 | 686 |
347 // wrapper function | 687 // wrapper function |
348 bool DeleteRegKey(ROOT_KEY root, const wchar_t* key_path) { | 688 bool DeleteRegKey(ROOT_KEY root, |
689 WOW64_OVERRIDE wow64_override, | |
690 const wchar_t* key_path) { | |
349 HANDLE key = INVALID_HANDLE_VALUE; | 691 HANDLE key = INVALID_HANDLE_VALUE; |
350 | 692 |
351 if (!OpenRegKey(root, key_path, DELETE, &key, nullptr)) | 693 if (!OpenRegKey(root, key_path, DELETE | wow64_override, &key, nullptr)) |
352 return false; | 694 return false; |
353 | 695 |
354 if (!DeleteRegKey(key)) { | 696 if (!DeleteRegKey(key)) { |
355 CloseRegKey(key); | 697 CloseRegKey(key); |
356 return false; | 698 return false; |
357 } | 699 } |
358 | 700 |
359 CloseRegKey(key); | 701 CloseRegKey(key); |
360 return true; | 702 return true; |
361 } | 703 } |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
423 return false; | 765 return false; |
424 | 766 |
425 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes)); | 767 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes)); |
426 | 768 |
427 delete[] value_bytes; | 769 delete[] value_bytes; |
428 return true; | 770 return true; |
429 } | 771 } |
430 | 772 |
431 // wrapper function | 773 // wrapper function |
432 bool QueryRegValueDWORD(ROOT_KEY root, | 774 bool QueryRegValueDWORD(ROOT_KEY root, |
775 WOW64_OVERRIDE wow64_override, | |
433 const wchar_t* key_path, | 776 const wchar_t* key_path, |
434 const wchar_t* value_name, | 777 const wchar_t* value_name, |
435 DWORD* out_dword) { | 778 DWORD* out_dword) { |
436 HANDLE key = INVALID_HANDLE_VALUE; | 779 HANDLE key = INVALID_HANDLE_VALUE; |
437 | 780 |
438 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key, | 781 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) |
439 NULL)) | |
440 return false; | 782 return false; |
441 | 783 |
442 if (!QueryRegValueDWORD(key, value_name, out_dword)) { | 784 if (!QueryRegValueDWORD(key, value_name, out_dword)) { |
443 CloseRegKey(key); | 785 CloseRegKey(key); |
444 return false; | 786 return false; |
445 } | 787 } |
446 | 788 |
447 CloseRegKey(key); | 789 CloseRegKey(key); |
448 return true; | 790 return true; |
449 } | 791 } |
(...skipping 11 matching lines...) Expand all Loading... | |
461 return false; | 803 return false; |
462 | 804 |
463 *out_sz = reinterpret_cast<wchar_t*>(value_bytes); | 805 *out_sz = reinterpret_cast<wchar_t*>(value_bytes); |
464 | 806 |
465 delete[] value_bytes; | 807 delete[] value_bytes; |
466 return true; | 808 return true; |
467 } | 809 } |
468 | 810 |
469 // wrapper function | 811 // wrapper function |
470 bool QueryRegValueSZ(ROOT_KEY root, | 812 bool QueryRegValueSZ(ROOT_KEY root, |
813 WOW64_OVERRIDE wow64_override, | |
471 const wchar_t* key_path, | 814 const wchar_t* key_path, |
472 const wchar_t* value_name, | 815 const wchar_t* value_name, |
473 std::wstring* out_sz) { | 816 std::wstring* out_sz) { |
474 HANDLE key = INVALID_HANDLE_VALUE; | 817 HANDLE key = INVALID_HANDLE_VALUE; |
475 | 818 |
476 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key, | 819 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) |
477 NULL)) | |
478 return false; | 820 return false; |
479 | 821 |
480 if (!QueryRegValueSZ(key, value_name, out_sz)) { | 822 if (!QueryRegValueSZ(key, value_name, out_sz)) { |
481 CloseRegKey(key); | 823 CloseRegKey(key); |
482 return false; | 824 return false; |
483 } | 825 } |
484 | 826 |
485 CloseRegKey(key); | 827 CloseRegKey(key); |
486 return true; | 828 return true; |
487 } | 829 } |
(...skipping 27 matching lines...) Expand all Loading... | |
515 // Handle the case of "empty multi_sz". | 857 // Handle the case of "empty multi_sz". |
516 if (out_multi_sz->size() == 0) | 858 if (out_multi_sz->size() == 0) |
517 out_multi_sz->push_back(L""); | 859 out_multi_sz->push_back(L""); |
518 | 860 |
519 delete[] value_bytes; | 861 delete[] value_bytes; |
520 return true; | 862 return true; |
521 } | 863 } |
522 | 864 |
523 // wrapper function | 865 // wrapper function |
524 bool QueryRegValueMULTISZ(ROOT_KEY root, | 866 bool QueryRegValueMULTISZ(ROOT_KEY root, |
867 WOW64_OVERRIDE wow64_override, | |
525 const wchar_t* key_path, | 868 const wchar_t* key_path, |
526 const wchar_t* value_name, | 869 const wchar_t* value_name, |
527 std::vector<std::wstring>* out_multi_sz) { | 870 std::vector<std::wstring>* out_multi_sz) { |
528 HANDLE key = INVALID_HANDLE_VALUE; | 871 HANDLE key = INVALID_HANDLE_VALUE; |
529 | 872 |
530 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key, | 873 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) |
531 NULL)) | |
532 return false; | 874 return false; |
533 | 875 |
534 if (!QueryRegValueMULTISZ(key, value_name, out_multi_sz)) { | 876 if (!QueryRegValueMULTISZ(key, value_name, out_multi_sz)) { |
535 CloseRegKey(key); | 877 CloseRegKey(key); |
536 return false; | 878 return false; |
537 } | 879 } |
538 | 880 |
539 CloseRegKey(key); | 881 CloseRegKey(key); |
540 return true; | 882 return true; |
541 } | 883 } |
(...skipping 25 matching lines...) Expand all Loading... | |
567 } | 909 } |
568 | 910 |
569 // wrapper function | 911 // wrapper function |
570 bool SetRegValueDWORD(HANDLE key, const wchar_t* value_name, DWORD value) { | 912 bool SetRegValueDWORD(HANDLE key, const wchar_t* value_name, DWORD value) { |
571 return SetRegKeyValue(key, value_name, REG_DWORD, | 913 return SetRegKeyValue(key, value_name, REG_DWORD, |
572 reinterpret_cast<BYTE*>(&value), sizeof(value)); | 914 reinterpret_cast<BYTE*>(&value), sizeof(value)); |
573 } | 915 } |
574 | 916 |
575 // wrapper function | 917 // wrapper function |
576 bool SetRegValueDWORD(ROOT_KEY root, | 918 bool SetRegValueDWORD(ROOT_KEY root, |
919 WOW64_OVERRIDE wow64_override, | |
577 const wchar_t* key_path, | 920 const wchar_t* key_path, |
578 const wchar_t* value_name, | 921 const wchar_t* value_name, |
579 DWORD value) { | 922 DWORD value) { |
580 HANDLE key = INVALID_HANDLE_VALUE; | 923 HANDLE key = INVALID_HANDLE_VALUE; |
581 | 924 |
582 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL)) | 925 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | wow64_override, &key, NULL)) |
583 return false; | 926 return false; |
584 | 927 |
585 if (!SetRegValueDWORD(key, value_name, value)) { | 928 if (!SetRegValueDWORD(key, value_name, value)) { |
586 CloseRegKey(key); | 929 CloseRegKey(key); |
587 return false; | 930 return false; |
588 } | 931 } |
589 | 932 |
590 return true; | 933 return true; |
591 } | 934 } |
592 | 935 |
593 // wrapper function | 936 // wrapper function |
594 bool SetRegValueSZ(HANDLE key, | 937 bool SetRegValueSZ(HANDLE key, |
595 const wchar_t* value_name, | 938 const wchar_t* value_name, |
596 const std::wstring& value) { | 939 const std::wstring& value) { |
597 // Make sure the number of bytes in |value|, including EoS, fits in a DWORD. | 940 // Make sure the number of bytes in |value|, including EoS, fits in a DWORD. |
598 if (std::numeric_limits<DWORD>::max() < | 941 if (std::numeric_limits<DWORD>::max() < |
599 ((value.length() + 1) * sizeof(wchar_t))) | 942 ((value.length() + 1) * sizeof(wchar_t))) |
600 return false; | 943 return false; |
601 | 944 |
602 DWORD size = (static_cast<DWORD>((value.length() + 1) * sizeof(wchar_t))); | 945 DWORD size = (static_cast<DWORD>((value.length() + 1) * sizeof(wchar_t))); |
603 return SetRegKeyValue(key, value_name, REG_SZ, | 946 return SetRegKeyValue(key, value_name, REG_SZ, |
604 reinterpret_cast<const BYTE*>(value.c_str()), size); | 947 reinterpret_cast<const BYTE*>(value.c_str()), size); |
605 } | 948 } |
606 | 949 |
607 // wrapper function | 950 // wrapper function |
608 bool SetRegValueSZ(ROOT_KEY root, | 951 bool SetRegValueSZ(ROOT_KEY root, |
952 WOW64_OVERRIDE wow64_override, | |
609 const wchar_t* key_path, | 953 const wchar_t* key_path, |
610 const wchar_t* value_name, | 954 const wchar_t* value_name, |
611 const std::wstring& value) { | 955 const std::wstring& value) { |
612 HANDLE key = INVALID_HANDLE_VALUE; | 956 HANDLE key = INVALID_HANDLE_VALUE; |
613 | 957 |
614 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL)) | 958 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | wow64_override, &key, NULL)) |
615 return false; | 959 return false; |
616 | 960 |
617 if (!SetRegValueSZ(key, value_name, value)) { | 961 if (!SetRegValueSZ(key, value_name, value)) { |
618 CloseRegKey(key); | 962 CloseRegKey(key); |
619 return false; | 963 return false; |
620 } | 964 } |
621 | 965 |
622 return true; | 966 return true; |
623 } | 967 } |
624 | 968 |
(...skipping 23 matching lines...) Expand all Loading... | |
648 if (std::numeric_limits<DWORD>::max() < builder.size()) | 992 if (std::numeric_limits<DWORD>::max() < builder.size()) |
649 return false; | 993 return false; |
650 | 994 |
651 return SetRegKeyValue( | 995 return SetRegKeyValue( |
652 key, value_name, REG_MULTI_SZ, reinterpret_cast<BYTE*>(builder.data()), | 996 key, value_name, REG_MULTI_SZ, reinterpret_cast<BYTE*>(builder.data()), |
653 (static_cast<DWORD>(builder.size()) + 1) * sizeof(wchar_t)); | 997 (static_cast<DWORD>(builder.size()) + 1) * sizeof(wchar_t)); |
654 } | 998 } |
655 | 999 |
656 // wrapper function | 1000 // wrapper function |
657 bool SetRegValueMULTISZ(ROOT_KEY root, | 1001 bool SetRegValueMULTISZ(ROOT_KEY root, |
1002 WOW64_OVERRIDE wow64_override, | |
658 const wchar_t* key_path, | 1003 const wchar_t* key_path, |
659 const wchar_t* value_name, | 1004 const wchar_t* value_name, |
660 const std::vector<std::wstring>& values) { | 1005 const std::vector<std::wstring>& values) { |
661 HANDLE key = INVALID_HANDLE_VALUE; | 1006 HANDLE key = INVALID_HANDLE_VALUE; |
662 | 1007 |
663 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL)) | 1008 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | wow64_override, &key, NULL)) |
664 return false; | 1009 return false; |
665 | 1010 |
666 if (!SetRegValueMULTISZ(key, value_name, values)) { | 1011 if (!SetRegValueMULTISZ(key, value_name, values)) { |
667 CloseRegKey(key); | 1012 CloseRegKey(key); |
668 return false; | 1013 return false; |
669 } | 1014 } |
670 | 1015 |
671 return true; | 1016 return true; |
672 } | 1017 } |
673 | 1018 |
674 //------------------------------------------------------------------------------ | 1019 //------------------------------------------------------------------------------ |
675 // Utils | 1020 // Utils |
676 //------------------------------------------------------------------------------ | 1021 //------------------------------------------------------------------------------ |
677 | 1022 |
678 const wchar_t* GetCurrentUserSidString() { | 1023 const wchar_t* GetCurrentUserSidString() { |
679 if (!g_initialized) | 1024 if (!g_initialized) |
680 InitNativeRegApi(); | 1025 InitNativeRegApi(); |
681 | 1026 |
682 return g_current_user_sid_string; | 1027 return g_current_user_sid_string; |
683 } | 1028 } |
684 | 1029 |
685 }; // namespace nt | 1030 }; // namespace nt |
OLD | NEW |