diff --git a/src/common/platform/process.hpp b/src/common/platform/process.hpp index e02d8f99..0fc6adbb 100644 --- a/src/common/platform/process.hpp +++ b/src/common/platform/process.hpp @@ -770,6 +770,12 @@ struct TOKEN_USER64 SID_AND_ATTRIBUTES64 User; }; +struct TOKEN_GROUPS64 +{ + ULONG GroupCount; + SID_AND_ATTRIBUTES64 Groups[1]; +}; + struct TOKEN_OWNER64 { EMULATOR_CAST(EmulatorTraits::PVOID, PSID) Owner; diff --git a/src/samples/test-sample/test.cpp b/src/samples/test-sample/test.cpp index a3b03a34..7923e6d1 100644 --- a/src/samples/test-sample/test.cpp +++ b/src/samples/test-sample/test.cpp @@ -273,16 +273,189 @@ namespace return {std::string(data, std::min(static_cast(length - 1), sizeof(data)))}; } + std::optional> get_all_registry_keys(const HKEY root, const char* path) + { + HKEY key{}; + if (RegOpenKeyExA(root, path, 0, KEY_READ | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) + { + return std::nullopt; + } + + std::vector keys; + std::vector name_buffer(MAX_PATH + 1); + + for (DWORD i = 0;; ++i) + { + auto name_buffer_len = static_cast(name_buffer.size()); + const LSTATUS status = + RegEnumKeyExA(key, i, name_buffer.data(), &name_buffer_len, nullptr, nullptr, nullptr, nullptr); + if (status == ERROR_SUCCESS) + { + keys.emplace_back(name_buffer.data(), name_buffer_len); + } + else if (status == ERROR_NO_MORE_ITEMS) + { + break; + } + else + { + keys.clear(); + break; + } + } + + if (keys.empty()) + { + RegCloseKey(key); + return std::nullopt; + } + + if (RegCloseKey(key) != ERROR_SUCCESS) + { + return std::nullopt; + } + + return keys; + } + + std::optional> get_all_registry_values(const HKEY root, const char* path) + { + HKEY key{}; + if (RegOpenKeyExA(root, path, 0, KEY_READ | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) + { + return std::nullopt; + } + + std::vector values; + std::vector name_buffer(MAX_PATH + 1); + + for (DWORD i = 0;; ++i) + { + auto name_buffer_len = static_cast(name_buffer.size()); + const auto status = + RegEnumValueA(key, i, name_buffer.data(), &name_buffer_len, nullptr, nullptr, nullptr, nullptr); + if (status == ERROR_SUCCESS) + { + values.emplace_back(name_buffer.data(), name_buffer_len); + } + else if (status == ERROR_NO_MORE_ITEMS) + { + break; + } + else + { + values.clear(); + break; + } + } + + if (values.empty()) + { + RegCloseKey(key); + return std::nullopt; + } + + if (RegCloseKey(key) != ERROR_SUCCESS) + { + return std::nullopt; + } + + return values; + } + bool test_registry() { - const auto val = + // Basic Reading Test + const auto prog_files_dir = read_registry_string(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows\CurrentVersion)", "ProgramFilesDir"); - if (!val) + if (!prog_files_dir || *prog_files_dir != "C:\\Program Files") { return false; } - return *val == "C:\\Program Files"; + // WOW64 Redirection Test + const auto pst_display = read_registry_string( + HKEY_LOCAL_MACHINE, + R"(SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\Time Zones\Pacific Standard Time)", "Display"); + if (!pst_display || pst_display->empty()) + { + return false; + } + + // Key Sub-keys Enumeration Test + const auto subkeys_opt = + get_all_registry_keys(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)"); + if (!subkeys_opt) + { + return false; + } + + bool found_fonts = false; + for (const auto& key_name : *subkeys_opt) + { + if (key_name == "Fonts") + { + found_fonts = true; + break; + } + } + if (!found_fonts) + { + return false; + } + + // Key Values Enumeration Test + const auto values_opt = + get_all_registry_values(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)"); + if (!values_opt) + { + return false; + } + + bool found_product_name = false; + for (const auto& val_name : *values_opt) + { + if (val_name == "ProductName") + { + found_product_name = true; + break; + } + } + if (!found_product_name) + { + return false; + } + + return true; + } + + bool test_system_info() + { + char sys_dir[MAX_PATH]; + if (GetSystemDirectoryA(sys_dir, sizeof(sys_dir)) == 0) + { + return false; + } + if (strlen(sys_dir) != 19) + { + return false; + } + + // TODO: This currently doesn't work. + /* + char username[256]; + DWORD username_len = sizeof(username); + if (!GetUserNameA(username, &username_len)) + { + return false; + } + if (username_len <= 1) + { + return false; + } + */ + + return true; } void throw_exception() @@ -477,6 +650,7 @@ int main(const int argc, const char* argv[]) RUN_TEST(test_dir_io, "Dir I/O") RUN_TEST(test_working_directory, "Working Directory") RUN_TEST(test_registry, "Registry") + RUN_TEST(test_system_info, "System Info") RUN_TEST(test_threads, "Threads") RUN_TEST(test_env, "Environment") RUN_TEST(test_exceptions, "Exceptions") diff --git a/src/tools/create-root.bat b/src/tools/create-root.bat index c93361c2..07936796 100644 --- a/src/tools/create-root.bat +++ b/src/tools/create-root.bat @@ -130,6 +130,7 @@ CALL :collect msacm32.dll CALL :collect locale.nls CALL :collect c_1252.nls CALL :collect c_850.nls +CALL :collect c_437.nls EXIT /B 0 diff --git a/src/windows-emulator/registry/registry_manager.cpp b/src/windows-emulator/registry/registry_manager.cpp index 3309f1e5..b6d7c860 100644 --- a/src/windows-emulator/registry/registry_manager.cpp +++ b/src/windows-emulator/registry/registry_manager.cpp @@ -110,12 +110,12 @@ std::optional registry_manager::get_key(const utils::path_key& key if (!entry) { - constexpr std::wstring_view wowPrefix = L"wow6432node\\"; + constexpr std::wstring_view wowPrefix = L"wow6432node"; const auto pathStr = path.wstring(); if (pathStr.starts_with(wowPrefix)) { - path = pathStr.substr(wowPrefix.size()); + path = pathStr.substr(wowPrefix.size() + 1); reg_key.path = path; entry = iterator->second->get_sub_key(path); } diff --git a/src/windows-emulator/syscalls/system.cpp b/src/windows-emulator/syscalls/system.cpp index 991f1aa9..2cee38e8 100644 --- a/src/windows-emulator/syscalls/system.cpp +++ b/src/windows-emulator/syscalls/system.cpp @@ -105,6 +105,7 @@ namespace syscalls case SystemFeatureConfigurationInformation: case SystemSupportedProcessorArchitectures2: case SystemFeatureConfigurationSectionInformation: + case SystemFirmwareTableInformation: return STATUS_NOT_SUPPORTED; case SystemControlFlowTransition: diff --git a/src/windows-emulator/syscalls/token.cpp b/src/windows-emulator/syscalls/token.cpp index 52857c72..b917bf14 100644 --- a/src/windows-emulator/syscalls/token.cpp +++ b/src/windows-emulator/syscalls/token.cpp @@ -75,6 +75,26 @@ namespace syscalls return STATUS_SUCCESS; } + if (token_information_class == TokenGroups) + { + constexpr auto required_size = sizeof(TOKEN_GROUPS64) + sizeof(sid); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + TOKEN_GROUPS64 groups{}; + groups.GroupCount = 1; + groups.Groups[0].Attributes = 0; + groups.Groups[0].Sid = token_information + sizeof(TOKEN_GROUPS64); + + emulator_object{c.emu, token_information}.write(groups); + c.emu.write_memory(token_information + sizeof(TOKEN_GROUPS64), sid, sizeof(sid)); + return STATUS_SUCCESS; + } + if (token_information_class == TokenOwner) { constexpr auto required_size = sizeof(sid) + sizeof(TOKEN_OWNER64);