Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome_elf/nt_registry/nt_registry.h" | 5 #include "chrome_elf/nt_registry/nt_registry.h" |
| 6 | 6 |
| 7 #include <mutex> | |
| 8 | |
| 7 namespace { | 9 namespace { |
| 8 | 10 |
| 9 // Function pointers used for registry access. | 11 // Function pointers used for registry access. |
| 10 RtlInitUnicodeStringFunction g_rtl_init_unicode_string = nullptr; | 12 RtlInitUnicodeStringFunction g_rtl_init_unicode_string = nullptr; |
| 11 NtCreateKeyFunction g_nt_create_key = nullptr; | 13 NtCreateKeyFunction g_nt_create_key = nullptr; |
| 12 NtDeleteKeyFunction g_nt_delete_key = nullptr; | 14 NtDeleteKeyFunction g_nt_delete_key = nullptr; |
| 13 NtOpenKeyExFunction g_nt_open_key_ex = nullptr; | 15 NtOpenKeyExFunction g_nt_open_key_ex = nullptr; |
| 14 NtCloseFunction g_nt_close = nullptr; | 16 NtCloseFunction g_nt_close = nullptr; |
| 15 NtQueryValueKeyFunction g_nt_query_value_key = nullptr; | 17 NtQueryValueKeyFunction g_nt_query_value_key = nullptr; |
| 16 NtSetValueKeyFunction g_nt_set_value_key = nullptr; | 18 NtSetValueKeyFunction g_nt_set_value_key = nullptr; |
| 17 | 19 |
| 18 // Lazy init. No concern about concurrency in chrome_elf. | 20 // Lazy init. No concern about concurrency in chrome_elf. |
| 19 bool g_initialized = false; | 21 bool g_initialized = false; |
| 20 bool g_system_install = false; | 22 bool g_system_install = false; |
| 21 bool g_reg_redirection = false; | 23 bool g_reg_redirection = false; |
| 22 const size_t g_kMaxPathLen = 255; | 24 const size_t g_kMaxPathLen = 255; |
| 23 wchar_t g_kRegPathHKLM[] = L"\\Registry\\Machine\\"; | 25 wchar_t g_kRegPathHKLM[] = L"\\Registry\\Machine\\"; |
| 24 wchar_t g_kRegPathHKCU[g_kMaxPathLen] = L""; | 26 wchar_t g_kRegPathHKCU[g_kMaxPathLen] = L""; |
| 25 wchar_t g_current_user_sid_string[g_kMaxPathLen] = L""; | 27 wchar_t g_current_user_sid_string[g_kMaxPathLen] = L""; |
| 26 wchar_t g_override_path[g_kMaxPathLen] = L""; | 28 wchar_t g_override_path[g_kMaxPathLen] = L""; |
| 27 | 29 |
| 28 // Not using install_util, to prevent circular dependency. | 30 //------------------------------------------------------------------------------ |
| 31 // Initialization - LOCAL | |
| 32 //------------------------------------------------------------------------------ | |
| 33 | |
| 34 // Not using install_static, to prevent circular dependency. | |
| 29 bool IsThisProcSystem() { | 35 bool IsThisProcSystem() { |
| 30 wchar_t program_dir[MAX_PATH] = {}; | 36 wchar_t program_dir[MAX_PATH] = {}; |
| 31 wchar_t* cmd_line = GetCommandLineW(); | 37 wchar_t* cmd_line = GetCommandLineW(); |
| 32 // If our command line starts with the "Program Files" or | 38 // If our command line starts with the "Program Files" or |
| 33 // "Program Files (x86)" path, we're system. | 39 // "Program Files (x86)" path, we're system. |
| 34 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, MAX_PATH); | 40 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, MAX_PATH); |
| 35 if (ret && ret < MAX_PATH && !::wcsncmp(cmd_line, program_dir, ret)) | 41 if (ret && ret < MAX_PATH && !::wcsncmp(cmd_line, program_dir, ret)) |
| 36 return true; | 42 return true; |
| 37 | 43 |
| 38 ret = ::GetEnvironmentVariable(L"PROGRAMFILES(X86)", program_dir, MAX_PATH); | 44 ret = ::GetEnvironmentVariable(L"PROGRAMFILES(X86)", program_dir, MAX_PATH); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 98 ::wcsncpy(g_current_user_sid_string, ptr, (g_kMaxPathLen - 1)); | 104 ::wcsncpy(g_current_user_sid_string, ptr, (g_kMaxPathLen - 1)); |
| 99 rtl_free_unicode_str(¤t_user_reg_path); | 105 rtl_free_unicode_str(¤t_user_reg_path); |
| 100 | 106 |
| 101 // Figure out if we're a system or user install. | 107 // Figure out if we're a system or user install. |
| 102 g_system_install = IsThisProcSystem(); | 108 g_system_install = IsThisProcSystem(); |
| 103 | 109 |
| 104 g_initialized = true; | 110 g_initialized = true; |
| 105 return true; | 111 return true; |
| 106 } | 112 } |
| 107 | 113 |
| 114 //------------------------------------------------------------------------------ | |
| 115 // Reg Redirection - LOCAL | |
| 116 // NOTE: On >= Win7, reflection support was removed. | |
| 117 // | |
| 118 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa384253(v=vs.85).as px | |
| 119 //------------------------------------------------------------------------------ | |
| 120 | |
| 121 // By default no WOW64 redirection will be done for any process, unless | |
| 122 // explicitly requested with the KEY_WOW64_32KEY access flag. | |
| 123 // This global setting can be changed via nt::ChangeDefaultWow64Redirection(). | |
| 124 bool g_defaultRedirection = false; | |
| 125 | |
| 126 typedef struct Node { | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
nit: remove typedef
penny
2016/09/23 23:50:58
Done.
| |
| 127 const wchar_t* to_match; | |
| 128 // If a match, the state of whether to redirect or not becomes: | |
| 129 bool if_match_set_to; | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
consider replacing these two bools with something
penny
2016/09/23 23:50:58
Done. Good idea, thanks.
| |
| 130 // If redirect state was set to true, the WOW64 subkey should be inserted | |
| 131 // right before (or after) this match. Unfortunately not consistent. | |
| 132 bool redirect_before; | |
| 133 // |next| is nullptr or an array of Nodes. | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
nit "...Nodes of length |array_len|."
penny
2016/09/23 23:50:58
Done.
| |
| 134 size_t array_len; | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
nit: swap these two so that they are in the same o
penny
2016/09/23 23:50:58
Done.
| |
| 135 const Node* next; | |
| 136 } Node; | |
| 137 | |
| 138 const Node classes_subtree[5] = {{L"CLSID", true, true, 0, nullptr}, | |
|
grt (UTC plus 2)
2016/09/20 10:39:53
constexpr Node...
same for the other constants bel
grt (UTC plus 2)
2016/09/20 10:39:54
nit: remove "5" since the initializer makes the si
penny
2016/09/23 23:50:58
Done.
penny
2016/09/23 23:50:58
Done. TIL, thanks!
| |
| 139 {L"DirectShow", true, true, 0, nullptr}, | |
| 140 {L"Interface", true, true, 0, nullptr}, | |
| 141 {L"Media Type", true, true, 0, nullptr}, | |
| 142 {L"MediaFoundation", true, true, 0, nullptr}}; | |
| 143 | |
| 144 const Node hklm_software_subtree[49] = { | |
| 145 {L"Classes", false, false, sizeof(classes_subtree) / sizeof(Node), | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
nit: #include <stdlib.h> and use _countof(classes_
penny
2016/09/23 23:50:57
Done. Excellent, thank you.
| |
| 146 classes_subtree}, | |
| 147 | |
| 148 {L"Clients", false, false, 0, nullptr}, | |
| 149 {L"Microsoft\\COM3", false, false, 0, nullptr}, | |
| 150 {L"Microsoft\\Cryptography\\Calais\\Current", false, false, 0, nullptr}, | |
| 151 {L"Microsoft\\Cryptography\\Calais\\Readers", false, false, 0, nullptr}, | |
| 152 {L"Microsoft\\Cryptography\\Services", false, false, 0, nullptr}, | |
| 153 | |
| 154 {L"Microsoft\\CTF\\SystemShared", false, false, 0, nullptr}, | |
| 155 {L"Microsoft\\CTF\\TIP", false, false, 0, nullptr}, | |
| 156 {L"Microsoft\\DFS", false, false, 0, nullptr}, | |
| 157 {L"Microsoft\\Driver Signing", false, false, 0, nullptr}, | |
| 158 {L"Microsoft\\EnterpriseCertificates", false, false, 0, nullptr}, | |
| 159 | |
| 160 {L"Microsoft\\EventSystem", false, false, 0, nullptr}, | |
| 161 {L"Microsoft\\MSMQ", false, false, 0, nullptr}, | |
| 162 {L"Microsoft\\Non-Driver Signing", false, false, 0, nullptr}, | |
| 163 {L"Microsoft\\Notepad\\DefaultFonts", false, false, 0, nullptr}, | |
| 164 {L"Microsoft\\OLE", false, false, 0, nullptr}, | |
| 165 | |
| 166 {L"Microsoft\\RAS", false, false, 0, nullptr}, | |
| 167 {L"Microsoft\\RPC", false, false, 0, nullptr}, | |
| 168 {L"Microsoft\\SOFTWARE\\Microsoft\\Shared Tools\\MSInfo", false, false, 0, | |
| 169 nullptr}, | |
| 170 {L"Microsoft\\SystemCertificates", false, false, 0, nullptr}, | |
| 171 {L"Microsoft\\TermServLicensing", false, false, 0, nullptr}, | |
| 172 | |
| 173 {L"Microsoft\\Transaction Server", false, false, 0, nullptr}, | |
| 174 {L"Microsoft\\Windows\\CurrentVersion\\App Paths", false, false, 0, | |
| 175 nullptr}, | |
| 176 {L"Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cursors\\Schemes", | |
| 177 false, false, 0, nullptr}, | |
| 178 {L"Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers", false, | |
| 179 false, 0, nullptr}, | |
| 180 {L"Microsoft\\Windows\\CurrentVersion\\Explorer\\DriveIcons", false, false, | |
| 181 0, nullptr}, | |
| 182 | |
| 183 {L"Microsoft\\Windows\\CurrentVersion\\Explorer\\KindMap", false, false, 0, | |
| 184 nullptr}, | |
| 185 {L"Microsoft\\Windows\\CurrentVersion\\Group Policy", false, false, 0, | |
| 186 nullptr}, | |
| 187 {L"Microsoft\\Windows\\CurrentVersion\\Policies", false, false, 0, nullptr}, | |
| 188 {L"Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", false, false, 0, | |
| 189 nullptr}, | |
| 190 {L"Microsoft\\Windows\\CurrentVersion\\Setup", false, false, 0, nullptr}, | |
| 191 | |
| 192 {L"Microsoft\\Windows\\CurrentVersion\\Telephony\\Locations", false, false, | |
| 193 0, nullptr}, | |
| 194 {L"Microsoft\\Windows NT\\CurrentVersion\\Console", false, false, 0, | |
| 195 nullptr}, | |
| 196 {L"Microsoft\\Windows NT\\CurrentVersion\\FontDpi", false, false, 0, | |
| 197 nullptr}, | |
| 198 {L"Microsoft\\Windows NT\\CurrentVersion\\FontLink", false, false, 0, | |
| 199 nullptr}, | |
| 200 {L"Microsoft\\Windows NT\\CurrentVersion\\FontMapper", false, false, 0, | |
| 201 nullptr}, | |
| 202 | |
| 203 {L"Microsoft\\Windows NT\\CurrentVersion\\Fonts", false, false, 0, nullptr}, | |
| 204 {L"Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", false, false, 0, | |
| 205 nullptr}, | |
| 206 {L"Microsoft\\Windows NT\\CurrentVersion\\Gre_Initialize", false, false, 0, | |
| 207 nullptr}, | |
| 208 {L"Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options", | |
| 209 false, false, 0, nullptr}, | |
| 210 {L"Microsoft\\Windows NT\\CurrentVersion\\LanguagePack", false, false, 0, | |
| 211 nullptr}, | |
| 212 | |
| 213 {L"Microsoft\\Windows NT\\CurrentVersion\\NetworkCards", false, false, 0, | |
| 214 nullptr}, | |
| 215 {L"Microsoft\\Windows NT\\CurrentVersion\\Perflib", false, false, 0, | |
| 216 nullptr}, | |
| 217 {L"Microsoft\\Windows NT\\CurrentVersion\\Ports", false, false, 0, nullptr}, | |
| 218 {L"Microsoft\\Windows NT\\CurrentVersion\\Print", false, false, 0, nullptr}, | |
| 219 {L"Microsoft\\Windows NT\\CurrentVersion\\ProfileList", false, false, 0, | |
| 220 nullptr}, | |
| 221 | |
| 222 {L"Microsoft\\Windows NT\\CurrentVersion\\Time Zones", false, false, 0, | |
| 223 nullptr}, | |
| 224 {L"Policies", false, false, 0, nullptr}, | |
| 225 {L"RegisteredApplications", false, false, 0, nullptr}, | |
| 226 }; | |
| 227 | |
| 228 const Node g_redirectionDecisionTreeHKCU = { | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
suggested comment:
// HKCU is shared by default wi
penny
2016/09/23 23:50:58
Acknowledged.
| |
| 229 L"SOFTWARE\\Classes", false, false, sizeof(classes_subtree) / sizeof(Node), | |
| 230 classes_subtree}; | |
| 231 | |
| 232 const Node g_redirectionDecisionTreeHKLM = { | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
suggested comment:
// HKLM\SOFTWARE is redirected
grt (UTC plus 2)
2016/09/21 10:14:06
i think this is more accurate, no?
// HKLM\SOFTWAR
penny
2016/09/23 23:50:57
Acknowledged.
penny
2016/09/23 23:50:58
Acknowledged.
| |
| 233 L"SOFTWARE", true, false, sizeof(hklm_software_subtree) / sizeof(Node), | |
| 234 hklm_software_subtree}; | |
| 235 | |
| 236 // Main redirection handler function. | |
| 237 // If redirection is required, change is made to |subkey_path| in place. | |
| 238 // | |
| 239 // This function should be called BEFORE concatenating |subkey_path| with the | |
| 240 // root hive or calling ParseFullRegPath(). Also, |subkey_path| should neither | |
| 241 // start nor end with a path seperator. | |
|
grt (UTC plus 2)
2016/09/21 10:14:06
DCHECK/assert this requirement? it seems like an e
penny
2016/09/23 23:50:58
Done.
| |
| 242 void ProcessRedirection(nt::ROOT_KEY root, | |
| 243 std::wstring* subkey_path, | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
swap the order of the last two args; in/out args s
penny
2016/09/23 23:50:57
Done.
| |
| 244 ACCESS_MASK access) { | |
| 245 const wchar_t* redirect_before = L"WOW6432Node\\"; | |
|
grt (UTC plus 2)
2016/09/20 10:39:53
static constexpr wchar_t kRedirectBefore[] = ...
penny
2016/09/23 23:50:58
Done.
| |
| 246 const wchar_t* redirect_after = L"\\WOW6432Node"; | |
| 247 | |
| 248 if (subkey_path == nullptr || subkey_path->empty() || | |
| 249 (access & KEY_WOW64_32KEY && access & KEY_WOW64_64KEY)) | |
| 250 return; | |
| 251 | |
| 252 // Get rid of nt::AUTO. | |
|
grt (UTC plus 2)
2016/09/20 10:39:53
nit: "Convert nt::AUTO to the appropriate root key
penny
2016/09/23 23:50:57
Done.
| |
| 253 nt::ROOT_KEY temp_root = root; | |
| 254 if (!root) { | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
be explicit rather than assume AUTO == 0, and dens
penny
2016/09/23 23:50:58
Done.
| |
| 255 if (g_system_install) | |
| 256 temp_root = nt::HKLM; | |
| 257 else | |
| 258 temp_root = nt::HKCU; | |
| 259 } | |
| 260 // No redirection during testing when there's already an override. | |
| 261 if (((temp_root == nt::HKCU) && (::wcslen(nt::HKCU_override) != 0)) || | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
don't compute a string length if you just want to
penny
2016/09/23 23:50:58
Done. Good one, thank you.
| |
| 262 ((temp_root == nt::HKLM) && (::wcslen(nt::HKLM_override) != 0))) | |
| 263 return; | |
| 264 | |
| 265 // WOW64 redirection only supported on x64 architecture. Return if x86. | |
| 266 SYSTEM_INFO system_info = {}; | |
| 267 ::GetNativeSystemInfo(&system_info); | |
| 268 if (system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) { | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
nit: omit braces for single-line conditional and b
penny
2016/09/23 23:50:58
Thank you - sometimes I slip back into old coding
| |
| 269 return; | |
| 270 } | |
| 271 | |
| 272 // Using BOOL type for compat with IsWow64Process() system API. | |
| 273 BOOL use_wow64 = false; | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
i think bool is more natural for this since that's
penny
2016/09/23 23:50:58
Done.
| |
| 274 if (g_defaultRedirection) { | |
| 275 // Check if running as wow64 process. | |
| 276 typedef decltype(IsWow64Process)* IsWow64ProcessFunc; | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
nit:
using IsWow64ProcessFunction = decltype(&
penny
2016/09/23 23:50:57
Done. This was a bit of a mind bend for my C mind
| |
| 277 IsWow64ProcessFunc is_wow64_process = reinterpret_cast<IsWow64ProcessFunc>( | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
nit: cache this since it won't change throughout t
penny
2016/09/23 23:50:58
Ack. I've moved this out into IsThisProcWow64().
| |
| 278 ::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "IsWow64Process")); | |
| 279 if (is_wow64_process) { | |
| 280 is_wow64_process(::GetCurrentProcess(), &use_wow64); | |
| 281 } | |
| 282 } | |
| 283 | |
| 284 // Consider KEY_WOW64_32KEY and KEY_WOW64_64KEY override access flags. | |
| 285 if (access & KEY_WOW64_32KEY) | |
| 286 use_wow64 = true; | |
| 287 | |
| 288 if (access & KEY_WOW64_64KEY) | |
| 289 use_wow64 = false; | |
| 290 | |
| 291 // If !use_wow64, there's nothing more to do. | |
| 292 if (!use_wow64) | |
| 293 return; | |
| 294 | |
| 295 // Pick which decision tree to use. | |
| 296 const Node* current = nullptr; | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
... = temp_root == nt::HKCU ? &g_redirectionDecisi
penny
2016/09/23 23:50:58
Done.
| |
| 297 if (temp_root == nt::HKCU) | |
| 298 current = &g_redirectionDecisionTreeHKCU; | |
| 299 else | |
| 300 current = &g_redirectionDecisionTreeHKLM; | |
| 301 | |
| 302 // The following loop works on the |subkey_path| from left to right. | |
| 303 // |position| tracks progress along |subkey_path|. | |
| 304 const wchar_t* position = subkey_path->data(); | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
use c_str() rather than data() since the code belo
penny
2016/09/23 23:50:58
Done.
| |
| 305 // |redirect| holds the latest state of whether redirection is required. | |
| 306 bool redirect = false; | |
| 307 // |insertion_point| tracks latest spot for redirection subkey to be inserted. | |
| 308 const wchar_t* insertion_point = nullptr; | |
| 309 // |insert_string| tracks which redirection string would be inserted. | |
| 310 const wchar_t* insert_string = nullptr; | |
| 311 | |
| 312 // The root of the tree is an array of 1. | |
| 313 size_t array_len = 1; | |
| 314 size_t index = 0; | |
| 315 while (index < array_len) { | |
| 316 size_t len = ::wcslen(current->to_match); | |
|
grt (UTC plus 2)
2016/09/21 10:14:06
it should be possible to get rid of this length co
penny
2016/09/23 23:50:58
wow. So you pushed me out of my comfort zone ther
| |
| 317 // Make sure the remainder of the path is at least as long as the current | |
| 318 // subkey to match. | |
| 319 if (::wcslen(position) >= len) { | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
rather than computing the string length through ea
penny
2016/09/23 23:50:57
Done. Did it a slightly different way - but no mor
| |
| 320 // Do case insensitive comparisons. | |
| 321 if (::wcsnicmp(position, current->to_match, len) == 0) { | |
| 322 // Make sure not to match on a substring. | |
| 323 if (*(position + len) == L'\\' || *(position + len) == L'\0') { | |
| 324 // MATCH! | |
| 325 // ------------------------------------------------------------------- | |
| 326 // 1) Update state of whether to redirect. | |
| 327 redirect = current->if_match_set_to; | |
| 328 if (redirect) { | |
| 329 // 1.5) If |redirect| state is now true, | |
| 330 // the new insertion point will be either right before or right | |
| 331 // after this match. | |
| 332 if (current->redirect_before) { | |
| 333 insertion_point = position; | |
| 334 insert_string = redirect_before; | |
| 335 } else { | |
| 336 insertion_point = position + len; | |
| 337 insert_string = redirect_after; | |
| 338 } | |
| 339 } | |
| 340 // 2) Adjust |position| along the subkey path. | |
| 341 position += len; | |
| 342 // 2.5) Increment the position, to move past path seperator(s). | |
| 343 while (*position == L'\\') | |
| 344 position++; | |
| 345 // 3) Move our loop parameters to the |next| array of Nodes. | |
| 346 array_len = current->array_len; | |
| 347 current = current->next; | |
| 348 index = 0; | |
| 349 // 4) Finish this loop and start on new array. | |
| 350 continue; | |
| 351 } | |
| 352 } | |
| 353 } | |
| 354 | |
| 355 // Move to the next node in the array if we didn't match this loop. | |
| 356 current += 1; | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
nit: ++current;
penny
2016/09/23 23:50:57
Done.
| |
| 357 index++; | |
|
grt (UTC plus 2)
2016/09/20 10:39:54
personal nit: prefer pre-increment even for scalar
penny
2016/09/23 23:50:57
Done.
| |
| 358 } | |
| 359 | |
| 360 if (!redirect) | |
| 361 return; | |
| 362 | |
| 363 // Insert the redirection into |subkey_path|, at |insertion_point|. | |
| 364 subkey_path->insert((insertion_point - subkey_path->data()), insert_string); | |
| 365 } | |
| 366 | |
| 367 //------------------------------------------------------------------------------ | |
| 368 // Reg Path Utilities - LOCAL | |
| 369 //------------------------------------------------------------------------------ | |
| 370 | |
| 108 const wchar_t* ConvertRootKey(nt::ROOT_KEY root) { | 371 const wchar_t* ConvertRootKey(nt::ROOT_KEY root) { |
| 109 nt::ROOT_KEY key = root; | 372 nt::ROOT_KEY key = root; |
| 110 | 373 |
| 111 if (!root) { | 374 if (!root) { |
| 112 // AUTO | 375 // AUTO |
| 113 key = g_system_install ? nt::HKLM : nt::HKCU; | 376 key = g_system_install ? nt::HKLM : nt::HKCU; |
| 114 } | 377 } |
| 115 | 378 |
| 116 if ((key == nt::HKCU) && (::wcslen(nt::HKCU_override) != 0)) { | 379 if ((key == nt::HKCU) && (::wcslen(nt::HKCU_override) != 0)) { |
| 117 std::wstring temp(g_kRegPathHKCU); | 380 std::wstring temp(g_kRegPathHKCU); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 191 out_base->push_back(L'\\'); | 454 out_base->push_back(L'\\'); |
| 192 } | 455 } |
| 193 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens); | 456 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens); |
| 194 } else { | 457 } else { |
| 195 out_base->assign(converted_root); | 458 out_base->assign(converted_root); |
| 196 } | 459 } |
| 197 | 460 |
| 198 return true; | 461 return true; |
| 199 } | 462 } |
| 200 | 463 |
| 464 //------------------------------------------------------------------------------ | |
| 465 // Misc wrapper functions - LOCAL | |
| 466 //------------------------------------------------------------------------------ | |
| 467 | |
| 201 NTSTATUS CreateKeyWrapper(const std::wstring& key_path, | 468 NTSTATUS CreateKeyWrapper(const std::wstring& key_path, |
| 202 ACCESS_MASK access, | 469 ACCESS_MASK access, |
| 203 HANDLE* out_handle, | 470 HANDLE* out_handle, |
| 204 ULONG* create_or_open OPTIONAL) { | 471 ULONG* create_or_open OPTIONAL) { |
| 205 UNICODE_STRING key_path_uni = {}; | 472 UNICODE_STRING key_path_uni = {}; |
| 206 g_rtl_init_unicode_string(&key_path_uni, key_path.c_str()); | 473 g_rtl_init_unicode_string(&key_path_uni, key_path.c_str()); |
| 207 | 474 |
| 208 OBJECT_ATTRIBUTES obj = {}; | 475 OBJECT_ATTRIBUTES obj = {}; |
| 209 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL, | 476 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL, |
| 210 nullptr); | 477 nullptr); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 225 // Create, open, delete, close functions | 492 // Create, open, delete, close functions |
| 226 //------------------------------------------------------------------------------ | 493 //------------------------------------------------------------------------------ |
| 227 | 494 |
| 228 bool CreateRegKey(ROOT_KEY root, | 495 bool CreateRegKey(ROOT_KEY root, |
| 229 const wchar_t* key_path, | 496 const wchar_t* key_path, |
| 230 ACCESS_MASK access, | 497 ACCESS_MASK access, |
| 231 HANDLE* out_handle OPTIONAL) { | 498 HANDLE* out_handle OPTIONAL) { |
| 232 if (!g_initialized) | 499 if (!g_initialized) |
| 233 InitNativeRegApi(); | 500 InitNativeRegApi(); |
| 234 | 501 |
| 502 std::wstring redirected_key_path; | |
| 503 if (key_path) { | |
| 504 redirected_key_path = key_path; | |
| 505 ProcessRedirection(root, &redirected_key_path, access); | |
| 506 } | |
| 507 | |
| 235 std::wstring current_path; | 508 std::wstring current_path; |
| 236 std::vector<std::wstring> subkeys; | 509 std::vector<std::wstring> subkeys; |
| 237 if (!ParseFullRegPath(ConvertRootKey(root), key_path, ¤t_path, | 510 if (!ParseFullRegPath(ConvertRootKey(root), redirected_key_path.data(), |
| 238 &subkeys)) | 511 ¤t_path, &subkeys)) |
| 239 return false; | 512 return false; |
| 240 | 513 |
| 241 // Open the base hive first. It should always exist already. | 514 // Open the base hive first. It should always exist already. |
| 242 HANDLE last_handle = INVALID_HANDLE_VALUE; | 515 HANDLE last_handle = INVALID_HANDLE_VALUE; |
| 243 NTSTATUS status = | 516 NTSTATUS status = |
| 244 CreateKeyWrapper(current_path, access, &last_handle, nullptr); | 517 CreateKeyWrapper(current_path, access, &last_handle, nullptr); |
| 245 if (!NT_SUCCESS(status)) | 518 if (!NT_SUCCESS(status)) |
| 246 return false; | 519 return false; |
| 247 | 520 |
| 248 size_t subkeys_size = subkeys.size(); | 521 size_t subkeys_size = subkeys.size(); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 305 HANDLE* out_handle, | 578 HANDLE* out_handle, |
| 306 NTSTATUS* error_code OPTIONAL) { | 579 NTSTATUS* error_code OPTIONAL) { |
| 307 if (!g_initialized) | 580 if (!g_initialized) |
| 308 InitNativeRegApi(); | 581 InitNativeRegApi(); |
| 309 | 582 |
| 310 NTSTATUS status = STATUS_UNSUCCESSFUL; | 583 NTSTATUS status = STATUS_UNSUCCESSFUL; |
| 311 UNICODE_STRING key_path_uni = {}; | 584 UNICODE_STRING key_path_uni = {}; |
| 312 OBJECT_ATTRIBUTES obj = {}; | 585 OBJECT_ATTRIBUTES obj = {}; |
| 313 *out_handle = INVALID_HANDLE_VALUE; | 586 *out_handle = INVALID_HANDLE_VALUE; |
| 314 | 587 |
| 315 std::wstring full_path(ConvertRootKey(root)); | 588 std::wstring full_path; |
| 316 full_path.append(key_path); | 589 if (key_path) { |
| 590 full_path = key_path; | |
| 591 ProcessRedirection(root, &full_path, access); | |
| 592 } | |
| 593 full_path.insert(0, ConvertRootKey(root)); | |
| 317 | 594 |
| 318 g_rtl_init_unicode_string(&key_path_uni, full_path.c_str()); | 595 g_rtl_init_unicode_string(&key_path_uni, full_path.c_str()); |
| 319 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL, | 596 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL, |
| 320 NULL); | 597 NULL); |
| 321 | 598 |
| 322 status = g_nt_open_key_ex(out_handle, access, &obj, 0); | 599 status = g_nt_open_key_ex(out_handle, access, &obj, 0); |
| 323 // See if caller wants the NTSTATUS. | 600 // See if caller wants the NTSTATUS. |
| 324 if (error_code) | 601 if (error_code) |
| 325 *error_code = status; | 602 *error_code = status; |
| 326 | 603 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 338 | 615 |
| 339 status = g_nt_delete_key(key); | 616 status = g_nt_delete_key(key); |
| 340 | 617 |
| 341 if (NT_SUCCESS(status)) | 618 if (NT_SUCCESS(status)) |
| 342 return true; | 619 return true; |
| 343 | 620 |
| 344 return false; | 621 return false; |
| 345 } | 622 } |
| 346 | 623 |
| 347 // wrapper function | 624 // wrapper function |
| 348 bool DeleteRegKey(ROOT_KEY root, const wchar_t* key_path) { | 625 bool DeleteRegKey(ROOT_KEY root, |
| 626 WOW64_OVERRIDE wow64_override, | |
| 627 const wchar_t* key_path) { | |
| 349 HANDLE key = INVALID_HANDLE_VALUE; | 628 HANDLE key = INVALID_HANDLE_VALUE; |
| 350 | 629 |
| 351 if (!OpenRegKey(root, key_path, DELETE, &key, nullptr)) | 630 if (!OpenRegKey(root, key_path, DELETE | wow64_override, &key, nullptr)) |
| 352 return false; | 631 return false; |
| 353 | 632 |
| 354 if (!DeleteRegKey(key)) { | 633 if (!DeleteRegKey(key)) { |
| 355 CloseRegKey(key); | 634 CloseRegKey(key); |
| 356 return false; | 635 return false; |
| 357 } | 636 } |
| 358 | 637 |
| 359 CloseRegKey(key); | 638 CloseRegKey(key); |
| 360 return true; | 639 return true; |
| 361 } | 640 } |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 423 return false; | 702 return false; |
| 424 | 703 |
| 425 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes)); | 704 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes)); |
| 426 | 705 |
| 427 delete[] value_bytes; | 706 delete[] value_bytes; |
| 428 return true; | 707 return true; |
| 429 } | 708 } |
| 430 | 709 |
| 431 // wrapper function | 710 // wrapper function |
| 432 bool QueryRegValueDWORD(ROOT_KEY root, | 711 bool QueryRegValueDWORD(ROOT_KEY root, |
| 712 WOW64_OVERRIDE wow64_override, | |
| 433 const wchar_t* key_path, | 713 const wchar_t* key_path, |
| 434 const wchar_t* value_name, | 714 const wchar_t* value_name, |
| 435 DWORD* out_dword) { | 715 DWORD* out_dword) { |
| 436 HANDLE key = INVALID_HANDLE_VALUE; | 716 HANDLE key = INVALID_HANDLE_VALUE; |
| 437 | 717 |
| 438 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key, | 718 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) |
| 439 NULL)) | |
| 440 return false; | 719 return false; |
| 441 | 720 |
| 442 if (!QueryRegValueDWORD(key, value_name, out_dword)) { | 721 if (!QueryRegValueDWORD(key, value_name, out_dword)) { |
| 443 CloseRegKey(key); | 722 CloseRegKey(key); |
| 444 return false; | 723 return false; |
| 445 } | 724 } |
| 446 | 725 |
| 447 CloseRegKey(key); | 726 CloseRegKey(key); |
| 448 return true; | 727 return true; |
| 449 } | 728 } |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 461 return false; | 740 return false; |
| 462 | 741 |
| 463 *out_sz = reinterpret_cast<wchar_t*>(value_bytes); | 742 *out_sz = reinterpret_cast<wchar_t*>(value_bytes); |
| 464 | 743 |
| 465 delete[] value_bytes; | 744 delete[] value_bytes; |
| 466 return true; | 745 return true; |
| 467 } | 746 } |
| 468 | 747 |
| 469 // wrapper function | 748 // wrapper function |
| 470 bool QueryRegValueSZ(ROOT_KEY root, | 749 bool QueryRegValueSZ(ROOT_KEY root, |
| 750 WOW64_OVERRIDE wow64_override, | |
| 471 const wchar_t* key_path, | 751 const wchar_t* key_path, |
| 472 const wchar_t* value_name, | 752 const wchar_t* value_name, |
| 473 std::wstring* out_sz) { | 753 std::wstring* out_sz) { |
| 474 HANDLE key = INVALID_HANDLE_VALUE; | 754 HANDLE key = INVALID_HANDLE_VALUE; |
| 475 | 755 |
| 476 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key, | 756 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) |
| 477 NULL)) | |
| 478 return false; | 757 return false; |
| 479 | 758 |
| 480 if (!QueryRegValueSZ(key, value_name, out_sz)) { | 759 if (!QueryRegValueSZ(key, value_name, out_sz)) { |
| 481 CloseRegKey(key); | 760 CloseRegKey(key); |
| 482 return false; | 761 return false; |
| 483 } | 762 } |
| 484 | 763 |
| 485 CloseRegKey(key); | 764 CloseRegKey(key); |
| 486 return true; | 765 return true; |
| 487 } | 766 } |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 515 // Handle the case of "empty multi_sz". | 794 // Handle the case of "empty multi_sz". |
| 516 if (out_multi_sz->size() == 0) | 795 if (out_multi_sz->size() == 0) |
| 517 out_multi_sz->push_back(L""); | 796 out_multi_sz->push_back(L""); |
| 518 | 797 |
| 519 delete[] value_bytes; | 798 delete[] value_bytes; |
| 520 return true; | 799 return true; |
| 521 } | 800 } |
| 522 | 801 |
| 523 // wrapper function | 802 // wrapper function |
| 524 bool QueryRegValueMULTISZ(ROOT_KEY root, | 803 bool QueryRegValueMULTISZ(ROOT_KEY root, |
| 804 WOW64_OVERRIDE wow64_override, | |
| 525 const wchar_t* key_path, | 805 const wchar_t* key_path, |
| 526 const wchar_t* value_name, | 806 const wchar_t* value_name, |
| 527 std::vector<std::wstring>* out_multi_sz) { | 807 std::vector<std::wstring>* out_multi_sz) { |
| 528 HANDLE key = INVALID_HANDLE_VALUE; | 808 HANDLE key = INVALID_HANDLE_VALUE; |
| 529 | 809 |
| 530 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key, | 810 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) |
| 531 NULL)) | |
| 532 return false; | 811 return false; |
| 533 | 812 |
| 534 if (!QueryRegValueMULTISZ(key, value_name, out_multi_sz)) { | 813 if (!QueryRegValueMULTISZ(key, value_name, out_multi_sz)) { |
| 535 CloseRegKey(key); | 814 CloseRegKey(key); |
| 536 return false; | 815 return false; |
| 537 } | 816 } |
| 538 | 817 |
| 539 CloseRegKey(key); | 818 CloseRegKey(key); |
| 540 return true; | 819 return true; |
| 541 } | 820 } |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 567 } | 846 } |
| 568 | 847 |
| 569 // wrapper function | 848 // wrapper function |
| 570 bool SetRegValueDWORD(HANDLE key, const wchar_t* value_name, DWORD value) { | 849 bool SetRegValueDWORD(HANDLE key, const wchar_t* value_name, DWORD value) { |
| 571 return SetRegKeyValue(key, value_name, REG_DWORD, | 850 return SetRegKeyValue(key, value_name, REG_DWORD, |
| 572 reinterpret_cast<BYTE*>(&value), sizeof(value)); | 851 reinterpret_cast<BYTE*>(&value), sizeof(value)); |
| 573 } | 852 } |
| 574 | 853 |
| 575 // wrapper function | 854 // wrapper function |
| 576 bool SetRegValueDWORD(ROOT_KEY root, | 855 bool SetRegValueDWORD(ROOT_KEY root, |
| 856 WOW64_OVERRIDE wow64_override, | |
| 577 const wchar_t* key_path, | 857 const wchar_t* key_path, |
| 578 const wchar_t* value_name, | 858 const wchar_t* value_name, |
| 579 DWORD value) { | 859 DWORD value) { |
| 580 HANDLE key = INVALID_HANDLE_VALUE; | 860 HANDLE key = INVALID_HANDLE_VALUE; |
| 581 | 861 |
| 582 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL)) | 862 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | wow64_override, &key, NULL)) |
| 583 return false; | 863 return false; |
| 584 | 864 |
| 585 if (!SetRegValueDWORD(key, value_name, value)) { | 865 if (!SetRegValueDWORD(key, value_name, value)) { |
| 586 CloseRegKey(key); | 866 CloseRegKey(key); |
| 587 return false; | 867 return false; |
| 588 } | 868 } |
| 589 | 869 |
| 590 return true; | 870 return true; |
| 591 } | 871 } |
| 592 | 872 |
| 593 // wrapper function | 873 // wrapper function |
| 594 bool SetRegValueSZ(HANDLE key, | 874 bool SetRegValueSZ(HANDLE key, |
| 595 const wchar_t* value_name, | 875 const wchar_t* value_name, |
| 596 const std::wstring& value) { | 876 const std::wstring& value) { |
| 597 // Make sure the number of bytes in |value|, including EoS, fits in a DWORD. | 877 // Make sure the number of bytes in |value|, including EoS, fits in a DWORD. |
| 598 if (std::numeric_limits<DWORD>::max() < | 878 if (std::numeric_limits<DWORD>::max() < |
| 599 ((value.length() + 1) * sizeof(wchar_t))) | 879 ((value.length() + 1) * sizeof(wchar_t))) |
| 600 return false; | 880 return false; |
| 601 | 881 |
| 602 DWORD size = (static_cast<DWORD>((value.length() + 1) * sizeof(wchar_t))); | 882 DWORD size = (static_cast<DWORD>((value.length() + 1) * sizeof(wchar_t))); |
| 603 return SetRegKeyValue(key, value_name, REG_SZ, | 883 return SetRegKeyValue(key, value_name, REG_SZ, |
| 604 reinterpret_cast<const BYTE*>(value.c_str()), size); | 884 reinterpret_cast<const BYTE*>(value.c_str()), size); |
| 605 } | 885 } |
| 606 | 886 |
| 607 // wrapper function | 887 // wrapper function |
| 608 bool SetRegValueSZ(ROOT_KEY root, | 888 bool SetRegValueSZ(ROOT_KEY root, |
| 889 WOW64_OVERRIDE wow64_override, | |
| 609 const wchar_t* key_path, | 890 const wchar_t* key_path, |
| 610 const wchar_t* value_name, | 891 const wchar_t* value_name, |
| 611 const std::wstring& value) { | 892 const std::wstring& value) { |
| 612 HANDLE key = INVALID_HANDLE_VALUE; | 893 HANDLE key = INVALID_HANDLE_VALUE; |
| 613 | 894 |
| 614 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL)) | 895 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | wow64_override, &key, NULL)) |
| 615 return false; | 896 return false; |
| 616 | 897 |
| 617 if (!SetRegValueSZ(key, value_name, value)) { | 898 if (!SetRegValueSZ(key, value_name, value)) { |
| 618 CloseRegKey(key); | 899 CloseRegKey(key); |
| 619 return false; | 900 return false; |
| 620 } | 901 } |
| 621 | 902 |
| 622 return true; | 903 return true; |
| 623 } | 904 } |
| 624 | 905 |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 648 if (std::numeric_limits<DWORD>::max() < builder.size()) | 929 if (std::numeric_limits<DWORD>::max() < builder.size()) |
| 649 return false; | 930 return false; |
| 650 | 931 |
| 651 return SetRegKeyValue( | 932 return SetRegKeyValue( |
| 652 key, value_name, REG_MULTI_SZ, reinterpret_cast<BYTE*>(builder.data()), | 933 key, value_name, REG_MULTI_SZ, reinterpret_cast<BYTE*>(builder.data()), |
| 653 (static_cast<DWORD>(builder.size()) + 1) * sizeof(wchar_t)); | 934 (static_cast<DWORD>(builder.size()) + 1) * sizeof(wchar_t)); |
| 654 } | 935 } |
| 655 | 936 |
| 656 // wrapper function | 937 // wrapper function |
| 657 bool SetRegValueMULTISZ(ROOT_KEY root, | 938 bool SetRegValueMULTISZ(ROOT_KEY root, |
| 939 WOW64_OVERRIDE wow64_override, | |
| 658 const wchar_t* key_path, | 940 const wchar_t* key_path, |
| 659 const wchar_t* value_name, | 941 const wchar_t* value_name, |
| 660 const std::vector<std::wstring>& values) { | 942 const std::vector<std::wstring>& values) { |
| 661 HANDLE key = INVALID_HANDLE_VALUE; | 943 HANDLE key = INVALID_HANDLE_VALUE; |
| 662 | 944 |
| 663 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL)) | 945 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | wow64_override, &key, NULL)) |
| 664 return false; | 946 return false; |
| 665 | 947 |
| 666 if (!SetRegValueMULTISZ(key, value_name, values)) { | 948 if (!SetRegValueMULTISZ(key, value_name, values)) { |
| 667 CloseRegKey(key); | 949 CloseRegKey(key); |
| 668 return false; | 950 return false; |
| 669 } | 951 } |
| 670 | 952 |
| 671 return true; | 953 return true; |
| 672 } | 954 } |
| 673 | 955 |
| 674 //------------------------------------------------------------------------------ | 956 //------------------------------------------------------------------------------ |
| 675 // Utils | 957 // Utils |
| 676 //------------------------------------------------------------------------------ | 958 //------------------------------------------------------------------------------ |
| 677 | 959 |
| 678 const wchar_t* GetCurrentUserSidString() { | 960 const wchar_t* GetCurrentUserSidString() { |
| 679 if (!g_initialized) | 961 if (!g_initialized) |
| 680 InitNativeRegApi(); | 962 InitNativeRegApi(); |
| 681 | 963 |
| 682 return g_current_user_sid_string; | 964 return g_current_user_sid_string; |
| 683 } | 965 } |
| 684 | 966 |
| 967 void ChangeDefaultWow64Redirection(bool default_on) { | |
| 968 g_defaultRedirection = default_on; | |
| 969 } | |
| 970 | |
| 685 }; // namespace nt | 971 }; // namespace nt |
| OLD | NEW |