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 |