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

Unified Diff: chrome_elf/nt_registry/nt_registry.cc

Issue 2345913003: [chrome_elf] NTRegistry - added wow64 redirection support. (Closed)
Patch Set: Final nits. Created 4 years, 2 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
« no previous file with comments | « chrome_elf/nt_registry/nt_registry.h ('k') | chrome_elf/nt_registry/nt_registry_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..4c65af8daff7c76ea5a9e4a0255da0225aeb58a4 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,20 @@ 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_reg_redirection = false;
-const size_t g_kMaxPathLen = 255;
+bool g_wow64_proc = false;
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"";
+
+// 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 +51,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,96 +114,415 @@ 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;
}
-const wchar_t* ConvertRootKey(nt::ROOT_KEY root) {
- nt::ROOT_KEY key = root;
+//------------------------------------------------------------------------------
+// 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'\\');
+ assert(root != nt::AUTO);
+
+ // |subkey_path| could legitimately be empty.
+ if (subkey_path->empty() ||
+ (access & KEY_WOW64_32KEY && access & KEY_WOW64_64KEY))
+ return;
+
+ // 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 (root == nt::HKCU ? *g_HKCU_override : *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 = (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)) {
+ // 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;
+ }
+ }
+ }
- if (!root) {
- // AUTO
- key = g_system_install ? nt::HKLM : nt::HKCU;
+ // Move to the next node in the array if we didn't match this loop.
+ ++current_node;
+ ++node_index;
}
- if ((key == nt::HKCU) && (::wcslen(nt::HKCU_override) != 0)) {
- std::wstring temp(g_kRegPathHKCU);
- temp.append(nt::HKCU_override);
+ 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
+//------------------------------------------------------------------------------
+
+std::wstring ConvertRootKey(nt::ROOT_KEY root) {
+ assert(root != nt::AUTO);
+
+ if (root == nt::HKCU && *g_HKCU_override) {
+ std::wstring temp = g_kRegPathHKCU;
+ temp.append(g_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)) {
- std::wstring temp(g_kRegPathHKCU);
- temp.append(nt::HKLM_override);
+ return temp;
+ } else if (root == nt::HKLM && *g_HKLM_override) {
+ // Yes, HKLM override goes into HKCU. This is not a typo.
+ std::wstring temp = g_kRegPathHKCU;
+ temp.append(g_HKLM_override);
temp.append(L"\\");
- ::wcsncpy(g_override_path, temp.c_str(), g_kMaxPathLen - 1);
- g_reg_redirection = true;
- return g_override_path;
+ return temp;
}
- g_reg_redirection = false;
- if (key == nt::HKCU)
- return g_kRegPathHKCU;
- else
- return g_kRegPathHKLM;
+ return (root == nt::HKCU) ? g_kRegPathHKCU : g_kRegPathHKLM;
+}
+
+// This utility should be called on an externally provided subkey path.
+// - Ensures there are no starting or trailing backslashes, and no more than
+// - one backslash in a row.
+// - Note from MSDN: "Key names cannot include the backslash character (\),
+// but any other printable character can be used. Value names and data can
+// include the backslash character."
+void SanitizeSubkeyPath(std::wstring* input) {
+ assert(input != nullptr);
+
+ // Remove trailing backslashes.
+ size_t last_valid_pos = input->find_last_not_of(L'\\');
+ if (last_valid_pos == std::wstring::npos) {
+ // The string is all backslashes, or it's empty. Clear and abort.
+ input->clear();
+ return;
+ }
+ // Chop off the trailing backslashes.
+ input->resize(last_valid_pos + 1);
+
+ // Remove leading backslashes.
+ input->erase(0, input->find_first_not_of(L'\\'));
+
+ // Replace any occurances of more than 1 backslash in a row with just 1.
+ size_t index = input->find_first_of(L"\\");
+ while (index != std::wstring::npos) {
+ // Remove a second consecutive backslash, and leave index where it is,
+ // or move to the next backslash in the string.
+ if ((*input)[index + 1] == L'\\')
+ input->erase(index + 1, 1);
+ else
+ index = input->find_first_of(L"\\", index + 1);
+ }
}
// 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,
+bool ParseFullRegPath(const std::wstring& converted_root,
+ const std::wstring& subkey_path,
std::wstring* out_base,
std::vector<std::wstring>* subkeys) {
out_base->clear();
subkeys->clear();
- std::wstring temp = L"";
+ std::wstring temp_path;
- if (g_reg_redirection) {
+ // Special case if there is testing redirection set up.
+ if (*g_HKCU_override || *g_HKLM_override) {
// Why process |converted_root|? To handle reg redirection used by tests.
// E.g.:
// |converted_root| = "\REGISTRY\USER\S-1-5-21-39260824-743453154-142223018-
// 716772\Software\Chromium\TempTestKeys\13110669370890870$94c6ed9d-bc34-
// 44f3-a0b3-9eee2d3f2f82\".
// |subkey_path| = "SOFTWARE\Google\Chrome\BrowserSec".
- temp.append(converted_root);
+ //
+ // Note: bypassing the starting backslash in the |converted_root|.
+ temp_path.append(converted_root, 1, converted_root.size() - 1);
}
- if (subkey_path != nullptr)
- temp.append(subkey_path);
+ temp_path.append(subkey_path);
// Tokenize the full path.
size_t find_start = 0;
- size_t delimiter = temp.find_first_of(L'\\');
+ size_t delimiter = temp_path.find_first_of(L'\\');
while (delimiter != std::wstring::npos) {
- std::wstring token = temp.substr(find_start, delimiter - find_start);
- if (!token.empty())
- subkeys->push_back(token);
+ subkeys->emplace_back(temp_path, find_start, delimiter - find_start);
+ // Move past the backslash.
find_start = delimiter + 1;
- delimiter = temp.find_first_of(L'\\', find_start);
+ delimiter = temp_path.find_first_of(L'\\', find_start);
}
- if (!temp.empty() && find_start < temp.length())
- // Get the last token.
- subkeys->push_back(temp.substr(find_start));
+ // Get the last token if there is one.
+ if (!temp_path.empty())
+ subkeys->emplace_back(temp_path, find_start);
- if (g_reg_redirection) {
+ // Special case if there is testing redirection set up.
+ if (*g_HKCU_override || *g_HKLM_override) {
// The base hive for HKCU needs to include the user SID.
uint32_t num_base_tokens = 2;
- const wchar_t* hkcu = L"\\REGISTRY\\USER\\";
- if (0 == ::wcsnicmp(converted_root, hkcu, ::wcslen(hkcu)))
+ if (0 == temp_path.compare(0, 14, L"REGISTRY\\USER\\"))
num_base_tokens = 3;
if (subkeys->size() < num_base_tokens)
@@ -186,8 +530,8 @@ bool ParseFullRegPath(const wchar_t* converted_root,
// Pull out the base hive tokens.
out_base->push_back(L'\\');
- for (size_t i = 0; i < num_base_tokens; i++) {
- out_base->append((*subkeys)[i].c_str());
+ for (size_t i = 0; i < num_base_tokens; ++i) {
+ out_base->append((*subkeys)[i]);
out_base->push_back(L'\\');
}
subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens);
@@ -198,6 +542,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 +565,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
//------------------------------------------------------------------------------
@@ -229,13 +573,29 @@ bool CreateRegKey(ROOT_KEY root,
const wchar_t* key_path,
ACCESS_MASK access,
HANDLE* out_handle OPTIONAL) {
+ // |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;
+
if (!g_initialized)
InitNativeRegApi();
+ if (root == nt::AUTO)
+ root = g_system_install ? nt::HKLM : nt::HKCU;
+
+ 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.
@@ -304,6 +664,12 @@ bool OpenRegKey(ROOT_KEY root,
ACCESS_MASK access,
HANDLE* out_handle,
NTSTATUS* error_code OPTIONAL) {
+ // |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;
+
if (!g_initialized)
InitNativeRegApi();
@@ -312,8 +678,16 @@ bool OpenRegKey(ROOT_KEY root,
OBJECT_ATTRIBUTES obj = {};
*out_handle = INVALID_HANDLE_VALUE;
- std::wstring full_path(ConvertRootKey(root));
- full_path.append(key_path);
+ if (root == nt::AUTO)
+ root = g_system_install ? nt::HKLM : nt::HKCU;
+
+ 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)) {
@@ -430,13 +806,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 +844,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 +898,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 +950,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 +983,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 +1033,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 +1061,38 @@ const wchar_t* GetCurrentUserSidString() {
return g_current_user_sid_string;
}
+bool IsCurrentProcWow64() {
+ if (!g_initialized)
+ InitNativeRegApi();
+
+ return g_wow64_proc;
+}
+
+bool SetTestingOverride(ROOT_KEY root, const std::wstring& new_path) {
+ if (!g_initialized)
+ InitNativeRegApi();
+
+ std::wstring sani_new_path = new_path;
+ SanitizeSubkeyPath(&sani_new_path);
+ if (sani_new_path.length() > g_kRegMaxPathLen)
+ return false;
+
+ if (root == HKCU || (root == AUTO && !g_system_install))
+ ::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;
+}
+
+std::wstring GetTestingOverride(ROOT_KEY root) {
+ if (!g_initialized)
+ InitNativeRegApi();
+
+ if (root == HKCU || (root == AUTO && !g_system_install))
+ return g_HKCU_override;
+
+ return g_HKLM_override;
+}
+
}; // namespace nt
« no previous file with comments | « chrome_elf/nt_registry/nt_registry.h ('k') | chrome_elf/nt_registry/nt_registry_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698