Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10441)

Unified Diff: chrome_elf/nt_registry/nt_registry.cc

Issue 2345913003: [chrome_elf] NTRegistry - added wow64 redirection support. (Closed)
Patch Set: Code review fixes, part 3. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..09af8b9894483791050199a67e046111a6cd96a7 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,14 +21,22 @@ 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\\";
-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"";
+wchar_t g_kRegPathHKCU[nt::g_kRegMaxPathLen + 1] = L"";
+wchar_t g_current_user_sid_string[nt::g_kRegMaxPathLen + 1] = L"";
+wchar_t g_override_path[nt::g_kRegMaxPathLen + 1] = L"";
+
+// For testing only.
+wchar_t g_HKLM_override[nt::g_kRegMaxPathLen + 1] = L"";
+wchar_t g_HKCU_override[nt::g_kRegMaxPathLen + 1] = L"";
+
+//------------------------------------------------------------------------------
+// Initialization - LOCAL
+//------------------------------------------------------------------------------
-// Not using install_util, to prevent circular dependency.
+// Not using install_static, to prevent circular dependency.
bool IsThisProcSystem() {
wchar_t program_dir[MAX_PATH] = {};
wchar_t* cmd_line = GetCommandLineW();
@@ -42,6 +53,22 @@ bool IsThisProcSystem() {
return false;
}
+bool IsThisProcWow64() {
+ // 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");
@@ -89,42 +116,344 @@ bool InitNativeRegApi() {
return false;
// Finish setting up global HKCU path.
- ::wcsncat(g_kRegPathHKCU, current_user_reg_path.Buffer, (g_kMaxPathLen - 1));
+ ::wcsncat(g_kRegPathHKCU, current_user_reg_path.Buffer, nt::g_kRegMaxPathLen);
::wcsncat(g_kRegPathHKCU, L"\\",
- (g_kMaxPathLen - ::wcslen(g_kRegPathHKCU) - 1));
+ (nt::g_kRegMaxPathLen - ::wcslen(g_kRegPathHKCU)));
// Keep the sid string as well.
wchar_t* ptr = ::wcsrchr(current_user_reg_path.Buffer, L'\\');
ptr++;
- ::wcsncpy(g_current_user_sid_string, ptr, (g_kMaxPathLen - 1));
+ ::wcsncpy(g_current_user_sid_string, ptr, nt::g_kRegMaxPathLen);
rtl_free_unicode_str(&current_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 decision trees represent the information at the MSDN
+// 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 kClassesSubtree[] = {{L"CLSID", REDIRECTED_BEFORE},
+ {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 kHklmSoftwareSubtree[] = {
+ // TODO(pennymac): when MS fixes compiler bug, or bots are all using clang,
+ // remove the "Classes" subkeys below and replace with:
+ // {L"Classes", SHARED, kClassesSubtree},
+ // 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 kRedirectionDecisionTreeHkcu = {L"SOFTWARE\\Classes", SHARED,
+ kClassesSubtree};
+
+// HKLM\SOFTWARE is redirected by default to SOFTWARE\WOW6432Node. Specific
+// subkeys under SOFTWARE are shared though... see |hklm_software_subtree|.
+constexpr Node kRedirectionDecisionTreeHklm = {L"SOFTWARE", REDIRECTED_AFTER,
+ kHklmSoftwareSubtree};
+
+// 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
+// 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";
+
+ assert(subkey_path != nullptr);
+ assert(subkey_path->empty() || subkey_path->front() != L'\\');
+ assert(subkey_path->empty() || subkey_path->back() != L'\\');
+
+ // |subkey_path| could legitimately be empty.
+ if (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 && *g_HKCU_override) ||
+ (temp_root == nt::HKLM && *g_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;
+
+ // The root of the decision trees are an array of 1.
+ size_t node_array_len = 1;
+ // Pick which decision tree to use.
+ const Node* current_node = (temp_root == nt::HKCU)
+ ? &kRedirectionDecisionTreeHkcu
+ : &kRedirectionDecisionTreeHklm;
+
+ // 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;
+
+ size_t node_index = 0;
+ while (node_index < node_array_len) {
+ size_t current_to_match_len = current_node->to_match_len;
+ // Make sure the remainder of the path is at least as long as the current
+ // subkey to match.
+ if (chars_left >= current_to_match_len) {
+ // Do case insensitive comparisons.
+ if (::wcsnicmp(position, current_node->to_match, current_to_match_len) ==
grt (UTC plus 2) 2016/09/30 09:32:16 nit: !::wcsnicmp to make this fit on one line
penny 2016/10/01 01:44:25 Done.
+ 0) {
+ // Make sure not to match on a substring.
+ if (*(position + current_to_match_len) == L'\\' ||
+ *(position + current_to_match_len) == L'\0') {
+ // MATCH!
+ // -------------------------------------------------------------------
+ // 1) Update state of redirection.
+ redirect_state = current_node->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 + current_to_match_len;
+ insert_string = kRedirectAfter;
+ }
+ // 2) Adjust |position| along the subkey path.
+ position += current_to_match_len;
+ chars_left -= current_to_match_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.
+ node_array_len = current_node->next_len;
+ current_node = current_node->next;
+ node_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_node;
+ ++node_index;
+ }
+
+ if (redirect_state == SHARED)
+ return;
+
+ // Insert the redirection into |subkey_path|, at |insertion_point|.
+ subkey_path->insert((insertion_point - subkey_path->c_str()), insert_string);
+}
+
+//------------------------------------------------------------------------------
+// Reg Path Utilities - LOCAL
+//------------------------------------------------------------------------------
+
const wchar_t* ConvertRootKey(nt::ROOT_KEY root) {
nt::ROOT_KEY key = root;
- if (!root) {
- // AUTO
+ if (root == nt::AUTO) {
grt (UTC plus 2) 2016/09/30 09:32:16 nit: omit braces now that the comment is out of th
penny 2016/10/01 01:44:25 Done.
key = g_system_install ? nt::HKLM : nt::HKCU;
}
- if ((key == nt::HKCU) && (::wcslen(nt::HKCU_override) != 0)) {
+ if (key == nt::HKCU && *g_HKCU_override) {
std::wstring temp(g_kRegPathHKCU);
- temp.append(nt::HKCU_override);
+ temp.append(g_HKCU_override);
temp.append(L"\\");
- ::wcsncpy(g_override_path, temp.c_str(), g_kMaxPathLen - 1);
+ ::wcsncpy(g_override_path, temp.c_str(), nt::g_kRegMaxPathLen);
g_reg_redirection = true;
return g_override_path;
- } else if ((key == nt::HKLM) && (::wcslen(nt::HKLM_override) != 0)) {
+ } else if (key == nt::HKLM && *g_HKLM_override) {
+ // Yes, HKLM override goes into HKCU. This is not a typo.
std::wstring temp(g_kRegPathHKCU);
- temp.append(nt::HKLM_override);
+ temp.append(g_HKLM_override);
temp.append(L"\\");
- ::wcsncpy(g_override_path, temp.c_str(), g_kMaxPathLen - 1);
+ ::wcsncpy(g_override_path, temp.c_str(), nt::g_kRegMaxPathLen);
g_reg_redirection = true;
return g_override_path;
}
@@ -136,14 +465,36 @@ 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) {
+ assert(input != nullptr);
+
+ // Remove any trailing backslashes.
+ while (!input->empty() && input->back() == L'\\')
+ input->pop_back();
+
+ // Remove any starting backslashes.
+ size_t index = 0;
+ while ((*input)[index] == L'\\')
+ ++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,
+ const std::wstring& subkey_path,
std::wstring* out_base,
std::vector<std::wstring>* subkeys) {
+ assert(converted_root != nullptr);
+
out_base->clear();
subkeys->clear();
std::wstring temp = L"";
@@ -157,8 +508,7 @@ bool ParseFullRegPath(const wchar_t* converted_root,
// |subkey_path| = "SOFTWARE\Google\Chrome\BrowserSec".
temp.append(converted_root);
}
- if (subkey_path != nullptr)
- temp.append(subkey_path);
+ temp.append(subkey_path);
// Tokenize the full path.
size_t find_start = 0;
@@ -198,6 +548,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,
@@ -217,10 +571,6 @@ NTSTATUS CreateKeyWrapper(const std::wstring& key_path,
namespace nt {
-const size_t g_kRegMaxPathLen = 255;
-wchar_t HKLM_override[g_kRegMaxPathLen] = L"";
-wchar_t HKCU_override[g_kRegMaxPathLen] = L"";
-
//------------------------------------------------------------------------------
// Create, open, delete, close functions
//------------------------------------------------------------------------------
@@ -232,10 +582,23 @@ bool CreateRegKey(ROOT_KEY root,
if (!g_initialized)
InitNativeRegApi();
+ // |key_path| can be null or empty, but it can't be longer than
+ // |g_kRegMaxPathLen| at this point.
+ if (key_path != nullptr &&
+ ::wcsnlen(key_path, g_kRegMaxPathLen + 1) == g_kRegMaxPathLen + 1)
+ return false;
+
+ 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, &current_path,
- &subkeys))
+ if (!ParseFullRegPath(ConvertRootKey(root), redirected_key_path,
+ &current_path, &subkeys))
return false;
// Open the base hive first. It should always exist already.
@@ -307,13 +670,24 @@ bool OpenRegKey(ROOT_KEY root,
if (!g_initialized)
InitNativeRegApi();
+ // |key_path| can be null or empty, but it can't be longer than
+ // |g_kRegMaxPathLen| at this point.
+ if (key_path != nullptr &&
+ ::wcsnlen(key_path, g_kRegMaxPathLen + 1) == g_kRegMaxPathLen + 1)
+ return false;
+
NTSTATUS status = STATUS_UNSUCCESSFUL;
UNICODE_STRING key_path_uni = {};
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 +719,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)) {
@@ -378,6 +754,10 @@ bool QueryRegKeyValue(HANDLE key,
if (!g_initialized)
InitNativeRegApi();
+ if (value_name == nullptr || *value_name == L'\0' ||
grt (UTC plus 2) 2016/09/30 09:32:16 will g_nt_query_value_key already do this validati
penny 2016/10/01 01:44:25 Right, so yes, the ntdll functions should fail out
grt (UTC plus 2) 2016/10/02 20:10:54 Seems okay to me. Thanks.
+ ::wcsnlen(value_name, g_kRegMaxValueName) == g_kRegMaxValueName)
+ return false;
+
NTSTATUS ntstatus = STATUS_UNSUCCESSFUL;
UNICODE_STRING value_uni = {};
g_rtl_init_unicode_string(&value_uni, value_name);
@@ -430,13 +810,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 +848,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 +902,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)) {
@@ -552,6 +932,10 @@ bool SetRegKeyValue(HANDLE key,
if (!g_initialized)
InitNativeRegApi();
+ if (value_name == nullptr || *value_name == L'\0' ||
+ ::wcsnlen(value_name, g_kRegMaxValueName) == g_kRegMaxValueName)
+ return false;
+
NTSTATUS ntstatus = STATUS_UNSUCCESSFUL;
UNICODE_STRING value_uni = {};
g_rtl_init_unicode_string(&value_uni, value_name);
@@ -574,12 +958,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 +991,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 +1041,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 +1069,49 @@ const wchar_t* GetCurrentUserSidString() {
return g_current_user_sid_string;
}
+bool IsCurrentProcWow64() {
+ if (!g_initialized)
+ InitNativeRegApi();
+
+ return g_wow64_proc;
+}
+
+bool SetTestingOverride(nt::ROOT_KEY root, const std::wstring& new_path) {
grt (UTC plus 2) 2016/09/30 09:32:16 nit: omit "nt::" here and below since this is with
penny 2016/10/01 01:44:25 Done.
+ if (!g_initialized)
+ InitNativeRegApi();
+
+ std::wstring sani_new_path = new_path;
+ SanitizeSubkeyPath(&sani_new_path);
+ if (::wcsnlen(sani_new_path.c_str(), nt::g_kRegMaxPathLen + 1) ==
grt (UTC plus 2) 2016/09/30 09:32:16 why not sani_new_path.length() > g_kRegMaxPathLen?
penny 2016/10/01 01:44:25 Thank you. And good question.
+ nt::g_kRegMaxPathLen + 1)
+ return false;
+
+ // 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;
+
+ if (temp_root == nt::HKCU)
grt (UTC plus 2) 2016/09/30 09:32:16 how about doing away with temp_root and changing t
penny 2016/10/01 01:44:25 You know, for some reason I was thinking |root| ar
+ ::wcsncpy(g_HKCU_override, sani_new_path.c_str(), nt::g_kRegMaxPathLen);
+ else
+ ::wcsncpy(g_HKLM_override, sani_new_path.c_str(), nt::g_kRegMaxPathLen);
+
+ return true;
+}
+
+void GetTestingOverride(nt::ROOT_KEY root, std::wstring* out_path) {
+ if (!g_initialized)
+ InitNativeRegApi();
+
+ // 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;
+
+ if (temp_root == nt::HKCU)
+ out_path->assign(g_HKCU_override);
+ else
+ out_path->assign(g_HKLM_override);
+}
+
}; // namespace nt

Powered by Google App Engine
This is Rietveld 408576698