Chromium Code Reviews| 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..ff2e8451f0ab4c7623a6c63926879a0b0fbed8ce 100644 |
| --- a/chrome_elf/nt_registry/nt_registry.cc |
| +++ b/chrome_elf/nt_registry/nt_registry.cc |
| @@ -4,6 +4,8 @@ |
| #include "chrome_elf/nt_registry/nt_registry.h" |
| +#include <mutex> |
| + |
| namespace { |
| // Function pointers used for registry access. |
| @@ -25,7 +27,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(); |
| @@ -105,6 +111,263 @@ bool InitNativeRegApi() { |
| return true; |
| } |
| +//------------------------------------------------------------------------------ |
| +// Reg Redirection - LOCAL |
| +// NOTE: On >= Win7, reflection support was removed. |
| +// |
| +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa384253(v=vs.85).aspx |
| +//------------------------------------------------------------------------------ |
| + |
| +// By default no WOW64 redirection will be done for any process, unless |
| +// explicitly requested with the KEY_WOW64_32KEY access flag. |
| +// This global setting can be changed via nt::ChangeDefaultWow64Redirection(). |
| +bool g_defaultRedirection = false; |
| + |
| +typedef struct Node { |
|
grt (UTC plus 2)
2016/09/20 10:39:54
nit: remove typedef
penny
2016/09/23 23:50:58
Done.
|
| + const wchar_t* to_match; |
| + // If a match, the state of whether to redirect or not becomes: |
| + 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.
|
| + // If redirect state was set to true, the WOW64 subkey should be inserted |
| + // right before (or after) this match. Unfortunately not consistent. |
| + bool redirect_before; |
| + // |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.
|
| + 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.
|
| + const Node* next; |
| +} Node; |
| + |
| +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!
|
| + {L"DirectShow", true, true, 0, nullptr}, |
| + {L"Interface", true, true, 0, nullptr}, |
| + {L"Media Type", true, true, 0, nullptr}, |
| + {L"MediaFoundation", true, true, 0, nullptr}}; |
| + |
| +const Node hklm_software_subtree[49] = { |
| + {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.
|
| + classes_subtree}, |
| + |
| + {L"Clients", false, false, 0, nullptr}, |
| + {L"Microsoft\\COM3", false, false, 0, nullptr}, |
| + {L"Microsoft\\Cryptography\\Calais\\Current", false, false, 0, nullptr}, |
| + {L"Microsoft\\Cryptography\\Calais\\Readers", false, false, 0, nullptr}, |
| + {L"Microsoft\\Cryptography\\Services", false, false, 0, nullptr}, |
| + |
| + {L"Microsoft\\CTF\\SystemShared", false, false, 0, nullptr}, |
| + {L"Microsoft\\CTF\\TIP", false, false, 0, nullptr}, |
| + {L"Microsoft\\DFS", false, false, 0, nullptr}, |
| + {L"Microsoft\\Driver Signing", false, false, 0, nullptr}, |
| + {L"Microsoft\\EnterpriseCertificates", false, false, 0, nullptr}, |
| + |
| + {L"Microsoft\\EventSystem", false, false, 0, nullptr}, |
| + {L"Microsoft\\MSMQ", false, false, 0, nullptr}, |
| + {L"Microsoft\\Non-Driver Signing", false, false, 0, nullptr}, |
| + {L"Microsoft\\Notepad\\DefaultFonts", false, false, 0, nullptr}, |
| + {L"Microsoft\\OLE", false, false, 0, nullptr}, |
| + |
| + {L"Microsoft\\RAS", false, false, 0, nullptr}, |
| + {L"Microsoft\\RPC", false, false, 0, nullptr}, |
| + {L"Microsoft\\SOFTWARE\\Microsoft\\Shared Tools\\MSInfo", false, false, 0, |
| + nullptr}, |
| + {L"Microsoft\\SystemCertificates", false, false, 0, nullptr}, |
| + {L"Microsoft\\TermServLicensing", false, false, 0, nullptr}, |
| + |
| + {L"Microsoft\\Transaction Server", false, false, 0, nullptr}, |
| + {L"Microsoft\\Windows\\CurrentVersion\\App Paths", false, false, 0, |
| + nullptr}, |
| + {L"Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cursors\\Schemes", |
| + false, false, 0, nullptr}, |
| + {L"Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers", false, |
| + false, 0, nullptr}, |
| + {L"Microsoft\\Windows\\CurrentVersion\\Explorer\\DriveIcons", false, false, |
| + 0, nullptr}, |
| + |
| + {L"Microsoft\\Windows\\CurrentVersion\\Explorer\\KindMap", false, false, 0, |
| + nullptr}, |
| + {L"Microsoft\\Windows\\CurrentVersion\\Group Policy", false, false, 0, |
| + nullptr}, |
| + {L"Microsoft\\Windows\\CurrentVersion\\Policies", false, false, 0, nullptr}, |
| + {L"Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", false, false, 0, |
| + nullptr}, |
| + {L"Microsoft\\Windows\\CurrentVersion\\Setup", false, false, 0, nullptr}, |
| + |
| + {L"Microsoft\\Windows\\CurrentVersion\\Telephony\\Locations", false, false, |
| + 0, nullptr}, |
| + {L"Microsoft\\Windows NT\\CurrentVersion\\Console", false, false, 0, |
| + nullptr}, |
| + {L"Microsoft\\Windows NT\\CurrentVersion\\FontDpi", false, false, 0, |
| + nullptr}, |
| + {L"Microsoft\\Windows NT\\CurrentVersion\\FontLink", false, false, 0, |
| + nullptr}, |
| + {L"Microsoft\\Windows NT\\CurrentVersion\\FontMapper", false, false, 0, |
| + nullptr}, |
| + |
| + {L"Microsoft\\Windows NT\\CurrentVersion\\Fonts", false, false, 0, nullptr}, |
| + {L"Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", false, false, 0, |
| + nullptr}, |
| + {L"Microsoft\\Windows NT\\CurrentVersion\\Gre_Initialize", false, false, 0, |
| + nullptr}, |
| + {L"Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options", |
| + false, false, 0, nullptr}, |
| + {L"Microsoft\\Windows NT\\CurrentVersion\\LanguagePack", false, false, 0, |
| + nullptr}, |
| + |
| + {L"Microsoft\\Windows NT\\CurrentVersion\\NetworkCards", false, false, 0, |
| + nullptr}, |
| + {L"Microsoft\\Windows NT\\CurrentVersion\\Perflib", false, false, 0, |
| + nullptr}, |
| + {L"Microsoft\\Windows NT\\CurrentVersion\\Ports", false, false, 0, nullptr}, |
| + {L"Microsoft\\Windows NT\\CurrentVersion\\Print", false, false, 0, nullptr}, |
| + {L"Microsoft\\Windows NT\\CurrentVersion\\ProfileList", false, false, 0, |
| + nullptr}, |
| + |
| + {L"Microsoft\\Windows NT\\CurrentVersion\\Time Zones", false, false, 0, |
| + nullptr}, |
| + {L"Policies", false, false, 0, nullptr}, |
| + {L"RegisteredApplications", false, false, 0, nullptr}, |
| +}; |
| + |
| +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.
|
| + L"SOFTWARE\\Classes", false, false, sizeof(classes_subtree) / sizeof(Node), |
| + classes_subtree}; |
| + |
| +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.
|
| + L"SOFTWARE", true, false, sizeof(hklm_software_subtree) / sizeof(Node), |
| + 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 neither |
| +// 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.
|
| +void ProcessRedirection(nt::ROOT_KEY root, |
| + 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.
|
| + ACCESS_MASK access) { |
| + 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.
|
| + const wchar_t* redirect_after = L"\\WOW6432Node"; |
| + |
| + if (subkey_path == nullptr || subkey_path->empty() || |
| + (access & KEY_WOW64_32KEY && access & KEY_WOW64_64KEY)) |
| + return; |
| + |
| + // 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.
|
| + nt::ROOT_KEY temp_root = root; |
| + 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.
|
| + if (g_system_install) |
| + temp_root = nt::HKLM; |
| + else |
| + temp_root = nt::HKCU; |
| + } |
| + // No redirection during testing when there's already an override. |
| + 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.
|
| + ((temp_root == nt::HKLM) && (::wcslen(nt::HKLM_override) != 0))) |
| + 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) { |
|
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
|
| + return; |
| + } |
| + |
| + // Using BOOL type for compat with IsWow64Process() system API. |
| + 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.
|
| + if (g_defaultRedirection) { |
| + // Check if running as wow64 process. |
| + 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
|
| + 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().
|
| + ::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "IsWow64Process")); |
| + if (is_wow64_process) { |
| + is_wow64_process(::GetCurrentProcess(), &use_wow64); |
| + } |
| + } |
| + |
| + // 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 = 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.
|
| + if (temp_root == nt::HKCU) |
| + current = &g_redirectionDecisionTreeHKCU; |
| + else |
| + current = &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->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.
|
| + // |redirect| holds the latest state of whether redirection is required. |
| + bool redirect = false; |
| + // |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. |
| + size_t array_len = 1; |
| + size_t index = 0; |
| + while (index < array_len) { |
| + 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
|
| + // Make sure the remainder of the path is at least as long as the current |
| + // subkey to match. |
| + 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
|
| + // 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 whether to redirect. |
| + redirect = current->if_match_set_to; |
| + if (redirect) { |
| + // 1.5) If |redirect| state is now true, |
| + // the new insertion point will be either right before or right |
| + // after this match. |
| + if (current->redirect_before) { |
| + insertion_point = position; |
| + insert_string = redirect_before; |
| + } else { |
| + insertion_point = position + len; |
| + insert_string = redirect_after; |
| + } |
| + } |
| + // 2) Adjust |position| along the subkey path. |
| + position += len; |
| + // 2.5) Increment the position, to move past path seperator(s). |
| + while (*position == L'\\') |
| + position++; |
| + // 3) Move our loop parameters to the |next| array of Nodes. |
| + array_len = current->array_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 += 1; |
|
grt (UTC plus 2)
2016/09/20 10:39:54
nit: ++current;
penny
2016/09/23 23:50:57
Done.
|
| + 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.
|
| + } |
| + |
| + if (!redirect) |
| + return; |
| + |
| + // Insert the redirection into |subkey_path|, at |insertion_point|. |
| + subkey_path->insert((insertion_point - subkey_path->data()), insert_string); |
| +} |
| + |
| +//------------------------------------------------------------------------------ |
| +// Reg Path Utilities - LOCAL |
| +//------------------------------------------------------------------------------ |
| + |
| const wchar_t* ConvertRootKey(nt::ROOT_KEY root) { |
| nt::ROOT_KEY key = root; |
| @@ -198,6 +461,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 +499,16 @@ bool CreateRegKey(ROOT_KEY root, |
| if (!g_initialized) |
| InitNativeRegApi(); |
| + std::wstring redirected_key_path; |
| + if (key_path) { |
| + redirected_key_path = key_path; |
| + ProcessRedirection(root, &redirected_key_path, access); |
| + } |
| + |
| 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.data(), |
| + ¤t_path, &subkeys)) |
| return false; |
| // Open the base hive first. It should always exist already. |
| @@ -312,8 +585,12 @@ 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; |
| + ProcessRedirection(root, &full_path, access); |
| + } |
| + 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 +622,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 +709,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 +747,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 +801,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 +853,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 +886,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 +936,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)) { |
| @@ -682,4 +964,8 @@ const wchar_t* GetCurrentUserSidString() { |
| return g_current_user_sid_string; |
| } |
| +void ChangeDefaultWow64Redirection(bool default_on) { |
| + g_defaultRedirection = default_on; |
| +} |
| + |
| }; // namespace nt |