Index: chrome_elf/nt_registry/nt_registry.cc |
diff --git a/chrome_elf/nt_registry/nt_registry.cc b/chrome_elf/nt_registry/nt_registry.cc |
index 373f00945682e20e1c1108a244015bc4ec43ae2e..eb80359f529a261be6ad5cc142f3da8c243f3b00 100644 |
--- a/chrome_elf/nt_registry/nt_registry.cc |
+++ b/chrome_elf/nt_registry/nt_registry.cc |
@@ -4,6 +4,9 @@ |
#include "chrome_elf/nt_registry/nt_registry.h" |
+#include <assert.h> |
+#include <stdlib.h> |
+ |
namespace { |
// Function pointers used for registry access. |
@@ -18,6 +21,7 @@ NtSetValueKeyFunction g_nt_set_value_key = nullptr; |
// Lazy init. No concern about concurrency in chrome_elf. |
bool g_initialized = false; |
bool g_system_install = false; |
+bool g_wow64_proc = false; |
bool g_reg_redirection = false; |
const size_t g_kMaxPathLen = 255; |
wchar_t g_kRegPathHKLM[] = L"\\Registry\\Machine\\"; |
@@ -25,7 +29,11 @@ wchar_t g_kRegPathHKCU[g_kMaxPathLen] = L""; |
wchar_t g_current_user_sid_string[g_kMaxPathLen] = L""; |
wchar_t g_override_path[g_kMaxPathLen] = L""; |
-// Not using install_util, to prevent circular dependency. |
+//------------------------------------------------------------------------------ |
+// Initialization - LOCAL |
+//------------------------------------------------------------------------------ |
+ |
+// Not using install_static, to prevent circular dependency. |
bool IsThisProcSystem() { |
wchar_t program_dir[MAX_PATH] = {}; |
wchar_t* cmd_line = GetCommandLineW(); |
@@ -42,6 +50,22 @@ bool IsThisProcSystem() { |
return false; |
} |
+bool IsThisProcWow64() { |
robertshield
2016/09/28 23:49:23
This function looks an awful lot like https://code
penny
2016/09/30 05:28:22
Commonalizified. I've exposed this information wi
|
+ // Using BOOL type for compat with IsWow64Process() system API. |
+ BOOL is_wow64 = FALSE; |
+ |
+ // API might not exist, so dynamic lookup. |
+ using IsWow64ProcessFunction = decltype(&IsWow64Process); |
+ IsWow64ProcessFunction is_wow64_process = |
+ reinterpret_cast<IsWow64ProcessFunction>(::GetProcAddress( |
+ ::GetModuleHandle(L"kernel32.dll"), "IsWow64Process")); |
+ if (!is_wow64_process) |
+ return false; |
+ if (!is_wow64_process(::GetCurrentProcess(), &is_wow64)) |
+ return false; |
+ return is_wow64 ? true : false; |
+} |
+ |
bool InitNativeRegApi() { |
HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); |
@@ -98,13 +122,308 @@ bool InitNativeRegApi() { |
::wcsncpy(g_current_user_sid_string, ptr, (g_kMaxPathLen - 1)); |
rtl_free_unicode_str(¤t_user_reg_path); |
- // Figure out if we're a system or user install. |
+ // Figure out if this is a system or user install. |
g_system_install = IsThisProcSystem(); |
+ // Figure out if this is a WOW64 process. |
+ g_wow64_proc = IsThisProcWow64(); |
+ |
g_initialized = true; |
return true; |
} |
+//------------------------------------------------------------------------------ |
+// Reg WOW64 Redirection - LOCAL |
+// |
+// How registry redirection works directly calling NTDLL APIs: |
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
+// - NOTE: On >= Win7, reflection support was removed. |
+// - |
+// https://msdn.microsoft.com/en-us/library/windows/desktop/aa384253(v=vs.85).aspx |
+// |
+// - 1) 32-bit / WOW64 process: |
+// a) Default access WILL be redirected to WOW64. |
+// b) KEY_WOW64_32KEY access WILL be redirected to WOW64. |
+// c) KEY_WOW64_64KEY access will NOT be redirected to WOW64. |
+// |
+// - 2) 64-bit process: |
+// a) Default access will NOT be redirected to WOW64. |
+// b) KEY_WOW64_32KEY access will NOT be redirected to WOW64. |
+// c) KEY_WOW64_64KEY access will NOT be redirected to WOW64. |
+// |
+// - Key point from above is that NTDLL redirects and respects access |
+// overrides for WOW64 calling processes. But does NOT do any of that if the |
+// calling process is 64-bit. 2b is surprising and troublesome. |
+// |
+// How registry redirection works using these nt_registry APIs: |
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
+// - These APIs will behave the same as NTDLL above, EXCEPT for 2b. |
+// nt_registry APIs will respect the override access flags for all processes. |
+// |
+// - How the WOW64 redirection decision trees / Nodes work below: |
+// |
+// The HKLM and HKCU descision trees represent the information at the MSDN |
robertshield
2016/09/28 23:49:23
nit: decision
penny
2016/09/30 05:28:22
Thank you. I dislike spelling or grammatical erro
|
+// link above... but in a way that generates a decision about whether a |
+// registry path should be subject to WOW64 redirection. The tree is |
+// traversed as you scan along the registry path in question. |
+// |
+// - Each Node contains a chunk of registry subkey(s) to match. |
+// - If it is NOT matched, traversal is done. |
+// - If it is matched: |
+// - Current state of |redirection_type| for the whole registry path is |
+// updated. |
+// - If |next| is empty, traversal is done. |
+// - Otherwise, |next| is an array of child Nodes to try to match against. |
+// Loop. |
+//------------------------------------------------------------------------------ |
+ |
+// This enum defines states for how to handle redirection. |
+// NOTE: When WOW64 redirection should happen, the redirect subkey can be either |
+// before or after the latest Node match. Unfortunately not consistent. |
+enum RedirectionType { SHARED = 0, REDIRECTED_BEFORE, REDIRECTED_AFTER }; |
+ |
+struct Node { |
+ template <size_t len, size_t n_len> |
+ constexpr Node(const wchar_t (&wcs)[len], |
+ RedirectionType rt, |
+ const Node (&n)[n_len]) |
+ : to_match(wcs), |
+ to_match_len(len - 1), |
+ redirection_type(rt), |
+ next(n), |
+ next_len(n_len) {} |
+ |
+ template <size_t len> |
+ constexpr Node(const wchar_t (&wcs)[len], RedirectionType rt) |
+ : to_match(wcs), |
+ to_match_len(len - 1), |
+ redirection_type(rt), |
+ next(nullptr), |
+ next_len(0) {} |
+ |
+ const wchar_t* to_match; |
+ size_t to_match_len; |
+ // If a match, this is the new state of how to redirect. |
+ RedirectionType redirection_type; |
+ // |next| is nullptr or an array of Nodes of length |array_len|. |
+ const Node* next; |
+ size_t next_len; |
+}; |
+ |
+// HKLM or HKCU SOFTWARE\Classes is shared by default. Specific subkeys under |
+// Classes are redirected to SOFTWARE\WOW6432Node\Classes\<subkey> though. |
+constexpr Node classes_subtree[] = {{L"CLSID", REDIRECTED_BEFORE}, |
grt (UTC plus 2)
2016/09/29 10:30:22
nit: kClassesSubtree
penny
2016/09/30 05:28:22
Sorry - I should have changed these at the same ti
|
+ {L"DirectShow", REDIRECTED_BEFORE}, |
+ {L"Interface", REDIRECTED_BEFORE}, |
+ {L"Media Type", REDIRECTED_BEFORE}, |
+ {L"MediaFoundation", REDIRECTED_BEFORE}}; |
+ |
+// These specific HKLM\SOFTWARE subkeys are shared. Specific |
+// subkeys under Classes are redirected though... see classes_subtree. |
+constexpr Node hklm_software_subtree[] = { |
grt (UTC plus 2)
2016/09/29 10:30:22
nit: kHklmSoftwareSubtree
penny
2016/09/30 05:28:22
Sorry - I should have changed these at the same ti
|
+ // TODO(pennymac): when MS fixes compiler bug, or bots are all using clang, |
+ // remove the "Classes" subkeys below and replace with: |
+ // {L"Classes", SHARED, classes_subtree}, |
+ // https://connect.microsoft.com/VisualStudio/feedback/details/3104499 |
+ {L"Classes\\CLSID", REDIRECTED_BEFORE}, |
+ {L"Classes\\DirectShow", REDIRECTED_BEFORE}, |
+ {L"Classes\\Interface", REDIRECTED_BEFORE}, |
+ {L"Classes\\Media Type", REDIRECTED_BEFORE}, |
+ {L"Classes\\MediaFoundation", REDIRECTED_BEFORE}, |
+ {L"Classes", SHARED}, |
+ |
+ {L"Clients", SHARED}, |
+ {L"Microsoft\\COM3", SHARED}, |
+ {L"Microsoft\\Cryptography\\Calais\\Current", SHARED}, |
+ {L"Microsoft\\Cryptography\\Calais\\Readers", SHARED}, |
+ {L"Microsoft\\Cryptography\\Services", SHARED}, |
+ |
+ {L"Microsoft\\CTF\\SystemShared", SHARED}, |
+ {L"Microsoft\\CTF\\TIP", SHARED}, |
+ {L"Microsoft\\DFS", SHARED}, |
+ {L"Microsoft\\Driver Signing", SHARED}, |
+ {L"Microsoft\\EnterpriseCertificates", SHARED}, |
+ |
+ {L"Microsoft\\EventSystem", SHARED}, |
+ {L"Microsoft\\MSMQ", SHARED}, |
+ {L"Microsoft\\Non-Driver Signing", SHARED}, |
+ {L"Microsoft\\Notepad\\DefaultFonts", SHARED}, |
+ {L"Microsoft\\OLE", SHARED}, |
+ |
+ {L"Microsoft\\RAS", SHARED}, |
+ {L"Microsoft\\RPC", SHARED}, |
+ {L"Microsoft\\SOFTWARE\\Microsoft\\Shared Tools\\MSInfo", SHARED}, |
+ {L"Microsoft\\SystemCertificates", SHARED}, |
+ {L"Microsoft\\TermServLicensing", SHARED}, |
+ |
+ {L"Microsoft\\Transaction Server", SHARED}, |
+ {L"Microsoft\\Windows\\CurrentVersion\\App Paths", SHARED}, |
+ {L"Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cursors\\Schemes", |
+ SHARED}, |
+ {L"Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers", SHARED}, |
+ {L"Microsoft\\Windows\\CurrentVersion\\Explorer\\DriveIcons", SHARED}, |
+ |
+ {L"Microsoft\\Windows\\CurrentVersion\\Explorer\\KindMap", SHARED}, |
+ {L"Microsoft\\Windows\\CurrentVersion\\Group Policy", SHARED}, |
+ {L"Microsoft\\Windows\\CurrentVersion\\Policies", SHARED}, |
+ {L"Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", SHARED}, |
+ {L"Microsoft\\Windows\\CurrentVersion\\Setup", SHARED}, |
+ |
+ {L"Microsoft\\Windows\\CurrentVersion\\Telephony\\Locations", SHARED}, |
+ {L"Microsoft\\Windows NT\\CurrentVersion\\Console", SHARED}, |
+ {L"Microsoft\\Windows NT\\CurrentVersion\\FontDpi", SHARED}, |
+ {L"Microsoft\\Windows NT\\CurrentVersion\\FontLink", SHARED}, |
+ {L"Microsoft\\Windows NT\\CurrentVersion\\FontMapper", SHARED}, |
+ |
+ {L"Microsoft\\Windows NT\\CurrentVersion\\Fonts", SHARED}, |
+ {L"Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", SHARED}, |
+ {L"Microsoft\\Windows NT\\CurrentVersion\\Gre_Initialize", SHARED}, |
+ {L"Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options", |
+ SHARED}, |
+ {L"Microsoft\\Windows NT\\CurrentVersion\\LanguagePack", SHARED}, |
+ |
+ {L"Microsoft\\Windows NT\\CurrentVersion\\NetworkCards", SHARED}, |
+ {L"Microsoft\\Windows NT\\CurrentVersion\\Perflib", SHARED}, |
+ {L"Microsoft\\Windows NT\\CurrentVersion\\Ports", SHARED}, |
+ {L"Microsoft\\Windows NT\\CurrentVersion\\Print", SHARED}, |
+ {L"Microsoft\\Windows NT\\CurrentVersion\\ProfileList", SHARED}, |
+ |
+ {L"Microsoft\\Windows NT\\CurrentVersion\\Time Zones", SHARED}, |
+ {L"Policies", SHARED}, |
+ {L"RegisteredApplications", SHARED}}; |
+ |
+// HKCU is entirely shared, except for a few specific Classes subkeys which |
+// are redirected. See |classes_subtree|. |
+constexpr Node g_redirectionDecisionTreeHKCU = {L"SOFTWARE\\Classes", SHARED, |
grt (UTC plus 2)
2016/09/29 10:30:22
nit: kRedirectionDecisionTreeHkcu
penny
2016/09/30 05:28:22
Done.
|
+ classes_subtree}; |
+ |
+// HKLM\SOFTWARE is redirected by default to SOFTWARE\WOW6432Node. Specific |
+// subkeys under SOFTWARE are shared though... see |hklm_software_subtree|. |
+constexpr Node g_redirectionDecisionTreeHKLM = {L"SOFTWARE", REDIRECTED_AFTER, |
grt (UTC plus 2)
2016/09/29 10:30:22
nit: kRedirectionDecisionTreeHklm
penny
2016/09/30 05:28:22
Done.
|
+ hklm_software_subtree}; |
+ |
+// Main redirection handler function. |
+// If redirection is required, change is made to |subkey_path| in place. |
+// |
+// - This function should be called BEFORE concatenating |subkey_path| with the |
+// root hive or calling ParseFullRegPath(). |
+// - Also, |subkey_path| should be passed to SanitizeSubkeyPath() before calling |
grt (UTC plus 2)
2016/09/29 10:30:22
how about enforcing this by adding to the top of t
penny
2016/09/30 05:28:22
My take on this is that external APIs should be re
grt (UTC plus 2)
2016/09/30 09:32:16
Your philosophy on when to sanitize external input
penny
2016/10/01 01:44:25
I hear ya, and considered just changing ProcessRed
grt (UTC plus 2)
2016/10/02 20:10:53
Do the underlying Nt registry functions choke on m
penny
2016/10/03 19:18:48
I'm not sure at the moment. It (advapi or ntdll)
|
+// this function. |
+void ProcessRedirection(nt::ROOT_KEY root, |
+ ACCESS_MASK access, |
+ std::wstring* subkey_path) { |
+ static constexpr wchar_t kRedirectBefore[] = L"WOW6432Node\\"; |
+ static constexpr wchar_t kRedirectAfter[] = L"\\WOW6432Node"; |
+ |
+ if (subkey_path == nullptr || subkey_path->empty() || |
+ (access & KEY_WOW64_32KEY && access & KEY_WOW64_64KEY)) |
+ return; |
+ |
+ // Convert nt::AUTO to the appropriate root key. |
+ nt::ROOT_KEY temp_root = root; |
+ if (root == nt::AUTO) |
+ temp_root = g_system_install ? nt::HKLM : nt::HKCU; |
+ |
+ // No redirection during testing when there's already an override. |
+ // Otherwise, the testing redirect directory Software\Chromium\TempTestKeys |
+ // would get WOW64 redirected if root_key == HKLM in this function. |
+ if ((temp_root == nt::HKCU && *nt::HKCU_override) || |
+ (temp_root == nt::HKLM && *nt::HKLM_override)) |
+ return; |
+ |
+ // WOW64 redirection only supported on x64 architecture. Return if x86. |
+ SYSTEM_INFO system_info = {}; |
+ ::GetNativeSystemInfo(&system_info); |
+ if (system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) |
+ return; |
+ |
+ bool use_wow64 = g_wow64_proc; |
+ // Consider KEY_WOW64_32KEY and KEY_WOW64_64KEY override access flags. |
+ if (access & KEY_WOW64_32KEY) |
+ use_wow64 = true; |
+ if (access & KEY_WOW64_64KEY) |
+ use_wow64 = false; |
+ |
+ // If !use_wow64, there's nothing more to do. |
+ if (!use_wow64) |
+ return; |
+ |
+ // Pick which decision tree to use. |
+ const Node* current = (temp_root == nt::HKCU) |
+ ? &g_redirectionDecisionTreeHKCU |
+ : &g_redirectionDecisionTreeHKLM; |
+ |
+ // The following loop works on the |subkey_path| from left to right. |
+ // |position| tracks progress along |subkey_path|. |
+ const wchar_t* position = subkey_path->c_str(); |
+ // Hold a count of chars left after position, for efficient calculations. |
+ size_t chars_left = subkey_path->length(); |
+ // |redirect_state| holds the latest state of redirection requirement. |
+ RedirectionType redirect_state = SHARED; |
+ // |insertion_point| tracks latest spot for redirection subkey to be inserted. |
+ const wchar_t* insertion_point = nullptr; |
+ // |insert_string| tracks which redirection string would be inserted. |
+ const wchar_t* insert_string = nullptr; |
+ |
+ // The root of the tree is an array of 1. |
grt (UTC plus 2)
2016/09/29 10:30:22
uber-nit: move the definition of |array_len| up so
penny
2016/09/30 05:28:22
Done.
|
+ size_t array_len = 1; |
grt (UTC plus 2)
2016/09/29 10:30:22
nit: array_len -> node_array_len
penny
2016/09/30 05:28:23
I like this, thanks. More clear. I've also chang
|
+ size_t index = 0; |
grt (UTC plus 2)
2016/09/29 10:30:22
nit: index -> node_index
penny
2016/09/30 05:28:23
Done.
|
+ while (index < array_len) { |
+ size_t len = current->to_match_len; |
grt (UTC plus 2)
2016/09/29 10:30:22
nit: len -> to_match_len
penny
2016/09/30 05:28:22
Done. current_to_match_len. I don't want any conf
|
+ // Make sure the remainder of the path is at least as long as the current |
+ // subkey to match. |
+ if (chars_left >= len) { |
+ // Do case insensitive comparisons. |
+ if (::wcsnicmp(position, current->to_match, len) == 0) { |
+ // Make sure not to match on a substring. |
+ if (*(position + len) == L'\\' || *(position + len) == L'\0') { |
+ // MATCH! |
+ // ------------------------------------------------------------------- |
+ // 1) Update state of redirection. |
+ redirect_state = current->redirection_type; |
+ // 1.5) If new state is to redirect, the new insertion point will be |
+ // either right before or right after this match. |
+ if (redirect_state == REDIRECTED_BEFORE) { |
+ insertion_point = position; |
+ insert_string = kRedirectBefore; |
+ } else if (redirect_state == REDIRECTED_AFTER) { |
+ insertion_point = position + len; |
+ insert_string = kRedirectAfter; |
+ } |
+ // 2) Adjust |position| along the subkey path. |
+ position += len; |
+ chars_left -= len; |
+ // 2.5) Increment the position, to move past path seperator(s). |
+ while (*position == L'\\') { |
+ ++position; |
+ --chars_left; |
+ } |
+ // 3) Move our loop parameters to the |next| array of Nodes. |
+ array_len = current->next_len; |
+ current = current->next; |
+ index = 0; |
+ // 4) Finish this loop and start on new array. |
+ continue; |
+ } |
+ } |
+ } |
+ |
+ // Move to the next node in the array if we didn't match this loop. |
+ ++current; |
+ ++index; |
+ } |
+ |
+ if (redirect_state == SHARED) |
+ return; |
+ |
+ // Insert the redirection into |subkey_path|, at |insertion_point|. |
+ subkey_path->insert((insertion_point - subkey_path->data()), insert_string); |
grt (UTC plus 2)
2016/09/29 10:30:22
nit: data -> c_str for consistency with the code a
penny
2016/09/30 05:28:22
Done.
|
+} |
+ |
+//------------------------------------------------------------------------------ |
+// Reg Path Utilities - LOCAL |
+//------------------------------------------------------------------------------ |
+ |
const wchar_t* ConvertRootKey(nt::ROOT_KEY root) { |
nt::ROOT_KEY key = root; |
@@ -113,14 +432,14 @@ const wchar_t* ConvertRootKey(nt::ROOT_KEY root) { |
key = g_system_install ? nt::HKLM : nt::HKCU; |
} |
- if ((key == nt::HKCU) && (::wcslen(nt::HKCU_override) != 0)) { |
+ if (key == nt::HKCU && *nt::HKCU_override) { |
std::wstring temp(g_kRegPathHKCU); |
temp.append(nt::HKCU_override); |
temp.append(L"\\"); |
::wcsncpy(g_override_path, temp.c_str(), g_kMaxPathLen - 1); |
g_reg_redirection = true; |
return g_override_path; |
- } else if ((key == nt::HKLM) && (::wcslen(nt::HKLM_override) != 0)) { |
+ } else if (key == nt::HKLM && *nt::HKLM_override) { |
std::wstring temp(g_kRegPathHKCU); |
temp.append(nt::HKLM_override); |
temp.append(L"\\"); |
@@ -136,9 +455,30 @@ const wchar_t* ConvertRootKey(nt::ROOT_KEY root) { |
return g_kRegPathHKLM; |
} |
+// This utility should be called on an externally provided subkey path. |
+// - Ensures there are no starting or trailing backslashes. |
+// - Note from MSDN: "Key names cannot include the backslash character (\), |
+// but any other printable character can be used." |
+void SanitizeSubkeyPath(std::wstring* input) { |
+ if (input == nullptr || input->empty()) |
grt (UTC plus 2)
2016/09/29 10:30:22
two comments here:
since this is a private functi
penny
2016/09/30 05:28:22
I fully agree. Thank you.
|
+ return; |
+ |
+ // Remove any trailing backslashes. |
+ while (input->back() == L'\\') |
grt (UTC plus 2)
2016/09/29 10:30:22
this provokes undefined behavior if the string con
penny
2016/09/30 05:28:22
TIL, don't call front/back on an empty std::wstrin
grt (UTC plus 2)
2016/09/30 09:32:16
I think it's much more clear and safe to use the s
penny
2016/10/01 01:44:25
I'm fully agreeing with you now. This is much nic
|
+ input->pop_back(); |
+ |
+ // Remove any starting backslashes. |
+ size_t index = 0; |
+ while (input->at(index) == L'\\') |
grt (UTC plus 2)
2016/09/29 10:30:22
fyi: at() does bounds checking and throws exceptio
penny
2016/09/30 05:28:22
TIL. Thanks. Reading the docs, I think [] operat
|
+ ++index; |
+ if (!index) |
+ *input = input->substr(index); |
+} |
+ |
// Turns a root and subkey path into the registry base hive and the rest of the |
// subkey tokens. |
// - |converted_root| should come directly out of ConvertRootKey function. |
+// - |subkey_path| should be passed to SanitizeSubkeyPath() first. |
// - E.g. base hive: "\Registry\Machine\", "\Registry\User\<SID>\". |
bool ParseFullRegPath(const wchar_t* converted_root, |
const wchar_t* subkey_path, |
@@ -198,6 +538,10 @@ bool ParseFullRegPath(const wchar_t* converted_root, |
return true; |
} |
+//------------------------------------------------------------------------------ |
+// Misc wrapper functions - LOCAL |
+//------------------------------------------------------------------------------ |
+ |
NTSTATUS CreateKeyWrapper(const std::wstring& key_path, |
ACCESS_MASK access, |
HANDLE* out_handle, |
@@ -232,10 +576,17 @@ bool CreateRegKey(ROOT_KEY root, |
if (!g_initialized) |
InitNativeRegApi(); |
+ std::wstring redirected_key_path; |
+ if (key_path) { |
+ redirected_key_path = key_path; |
+ SanitizeSubkeyPath(&redirected_key_path); |
+ ProcessRedirection(root, access, &redirected_key_path); |
+ } |
+ |
std::wstring current_path; |
std::vector<std::wstring> subkeys; |
- if (!ParseFullRegPath(ConvertRootKey(root), key_path, ¤t_path, |
- &subkeys)) |
+ if (!ParseFullRegPath(ConvertRootKey(root), redirected_key_path.c_str(), |
grt (UTC plus 2)
2016/09/29 10:30:22
pass redirected_key_path directly as a const std::
penny
2016/09/30 05:28:22
Done.
|
+ ¤t_path, &subkeys)) |
return false; |
// Open the base hive first. It should always exist already. |
@@ -312,8 +663,13 @@ bool OpenRegKey(ROOT_KEY root, |
OBJECT_ATTRIBUTES obj = {}; |
*out_handle = INVALID_HANDLE_VALUE; |
- std::wstring full_path(ConvertRootKey(root)); |
- full_path.append(key_path); |
+ std::wstring full_path; |
+ if (key_path) { |
+ full_path = key_path; |
+ SanitizeSubkeyPath(&full_path); |
+ ProcessRedirection(root, access, &full_path); |
+ } |
+ full_path.insert(0, ConvertRootKey(root)); |
g_rtl_init_unicode_string(&key_path_uni, full_path.c_str()); |
InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL, |
@@ -345,10 +701,12 @@ bool DeleteRegKey(HANDLE key) { |
} |
// wrapper function |
-bool DeleteRegKey(ROOT_KEY root, const wchar_t* key_path) { |
+bool DeleteRegKey(ROOT_KEY root, |
+ WOW64_OVERRIDE wow64_override, |
+ const wchar_t* key_path) { |
HANDLE key = INVALID_HANDLE_VALUE; |
- if (!OpenRegKey(root, key_path, DELETE, &key, nullptr)) |
+ if (!OpenRegKey(root, key_path, DELETE | wow64_override, &key, nullptr)) |
return false; |
if (!DeleteRegKey(key)) { |
@@ -430,13 +788,13 @@ bool QueryRegValueDWORD(HANDLE key, |
// wrapper function |
bool QueryRegValueDWORD(ROOT_KEY root, |
+ WOW64_OVERRIDE wow64_override, |
const wchar_t* key_path, |
const wchar_t* value_name, |
DWORD* out_dword) { |
HANDLE key = INVALID_HANDLE_VALUE; |
- if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key, |
- NULL)) |
+ if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) |
return false; |
if (!QueryRegValueDWORD(key, value_name, out_dword)) { |
@@ -468,13 +826,13 @@ bool QueryRegValueSZ(HANDLE key, |
// wrapper function |
bool QueryRegValueSZ(ROOT_KEY root, |
+ WOW64_OVERRIDE wow64_override, |
const wchar_t* key_path, |
const wchar_t* value_name, |
std::wstring* out_sz) { |
HANDLE key = INVALID_HANDLE_VALUE; |
- if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key, |
- NULL)) |
+ if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) |
return false; |
if (!QueryRegValueSZ(key, value_name, out_sz)) { |
@@ -522,13 +880,13 @@ bool QueryRegValueMULTISZ(HANDLE key, |
// wrapper function |
bool QueryRegValueMULTISZ(ROOT_KEY root, |
+ WOW64_OVERRIDE wow64_override, |
const wchar_t* key_path, |
const wchar_t* value_name, |
std::vector<std::wstring>* out_multi_sz) { |
HANDLE key = INVALID_HANDLE_VALUE; |
- if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key, |
- NULL)) |
+ if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) |
return false; |
if (!QueryRegValueMULTISZ(key, value_name, out_multi_sz)) { |
@@ -574,12 +932,13 @@ bool SetRegValueDWORD(HANDLE key, const wchar_t* value_name, DWORD value) { |
// wrapper function |
bool SetRegValueDWORD(ROOT_KEY root, |
+ WOW64_OVERRIDE wow64_override, |
const wchar_t* key_path, |
const wchar_t* value_name, |
DWORD value) { |
HANDLE key = INVALID_HANDLE_VALUE; |
- if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL)) |
+ if (!OpenRegKey(root, key_path, KEY_SET_VALUE | wow64_override, &key, NULL)) |
return false; |
if (!SetRegValueDWORD(key, value_name, value)) { |
@@ -606,12 +965,13 @@ bool SetRegValueSZ(HANDLE key, |
// wrapper function |
bool SetRegValueSZ(ROOT_KEY root, |
+ WOW64_OVERRIDE wow64_override, |
const wchar_t* key_path, |
const wchar_t* value_name, |
const std::wstring& value) { |
HANDLE key = INVALID_HANDLE_VALUE; |
- if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL)) |
+ if (!OpenRegKey(root, key_path, KEY_SET_VALUE | wow64_override, &key, NULL)) |
return false; |
if (!SetRegValueSZ(key, value_name, value)) { |
@@ -655,12 +1015,13 @@ bool SetRegValueMULTISZ(HANDLE key, |
// wrapper function |
bool SetRegValueMULTISZ(ROOT_KEY root, |
+ WOW64_OVERRIDE wow64_override, |
const wchar_t* key_path, |
const wchar_t* value_name, |
const std::vector<std::wstring>& values) { |
HANDLE key = INVALID_HANDLE_VALUE; |
- if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL)) |
+ if (!OpenRegKey(root, key_path, KEY_SET_VALUE | wow64_override, &key, NULL)) |
return false; |
if (!SetRegValueMULTISZ(key, value_name, values)) { |