Improvements to locale syscalls, fix TimeZone query and add more syscalls (#223)

This PR aims to do the following:
- Add the `NtUserGetAtomName` syscall.
- Add stub handlers for `NtUserSetWindowsHookEx`,
`NtUserUnhookWindowsHookEx`, and `NtUserCreateWindowEx`.
- Implement `NtGetNlsSectionPtr` (for Code Pages), add
`NtQueryDefaultUILanguage`, and improve `NtQueryInstallUILanguage`.
- Handle `SystemTimeZoneInformation`,
`SystemCurrentTimeZoneInformation`, and
`SystemDynamicTimeZoneInformation` in `NtQuerySystemInformation`.
- Skip `ThreadAffinityMask` in `NtSetInformationThread`.
- Fix `NtConnectPort` to allow TimeZone queries to work properly. This
is probably the most problematic change here because it required messing
with the shared section and hardcoding an offset (2504). Initializing
the data in this offset seems necessary for calls like
`GetTimeZoneInformation` to succeed, so maybe there's no other way
around it.
This commit is contained in:
Maurice Heumann
2025-04-22 09:08:42 +02:00
committed by GitHub
9 changed files with 316 additions and 20 deletions

View File

@@ -34,8 +34,32 @@ namespace syscalls
return STATUS_SUCCESS;
}
NTSTATUS handle_NtGetNlsSectionPtr()
NTSTATUS handle_NtGetNlsSectionPtr(const syscall_context& c, ULONG section_type, ULONG section_data,
emulator_pointer /*context_data*/, emulator_object<uint64_t> section_pointer,
emulator_object<ULONG> section_size)
{
if (section_type == 11)
{
c.win_emu.log.print(color::dark_gray, "--> Code Page: %d\n", section_data);
const auto file_path = R"(C:\Windows\System32\C_)" + std::to_string(section_data) + ".NLS";
const auto locale_file = utils::io::read_file(c.win_emu.file_sys.translate(file_path));
if (locale_file.empty())
{
return STATUS_OBJECT_NAME_NOT_FOUND;
}
const auto size = static_cast<size_t>(page_align_up(locale_file.size()));
const auto section_memory = c.win_emu.memory.allocate_memory(size, memory_permission::read);
c.emu.write_memory(section_memory, locale_file.data(), locale_file.size());
section_pointer.write_if_valid(section_memory);
section_size.write_if_valid(static_cast<ULONG>(size));
return STATUS_SUCCESS;
}
c.win_emu.log.print(color::gray, "Unsupported section type: %X\n", section_type);
return STATUS_NOT_SUPPORTED;
}
@@ -54,8 +78,15 @@ namespace syscalls
return STATUS_NOT_SUPPORTED;
}
NTSTATUS handle_NtQueryInstallUILanguage()
NTSTATUS handle_NtQueryDefaultUILanguage(const syscall_context&, emulator_object<LANGID> language_id)
{
return STATUS_NOT_SUPPORTED;
language_id.write(0x407);
return STATUS_SUCCESS;
}
NTSTATUS handle_NtQueryInstallUILanguage(const syscall_context&, emulator_object<LANGID> language_id)
{
language_id.write(0x407);
return STATUS_SUCCESS;
}
}

View File

@@ -4,6 +4,18 @@
namespace syscalls
{
struct CSR_API_CONNECTINFO
{
uint64_t SharedSectionBase;
uint64_t SharedStaticServerData;
uint64_t SharedSectionHeap;
ULONG DebugFlags;
ULONG SizeOfPebData;
ULONG SizeOfTebData;
ULONG NumberOfServerDllNames;
EMULATOR_CAST(uint64_t, HANDLE) ServerProcessId;
};
NTSTATUS handle_NtConnectPort(const syscall_context& c, const emulator_object<handle> client_port_handle,
const emulator_object<UNICODE_STRING<EmulatorTraits<Emu64>>> server_port_name,
const emulator_object<SECURITY_QUALITY_OF_SERVICE> /*security_qos*/,
@@ -21,9 +33,34 @@ namespace syscalls
if (connection_info)
{
std::vector<uint8_t> zero_mem{};
zero_mem.resize(connection_info_length.read(), 0);
c.emu.write_memory(connection_info, zero_mem.data(), zero_mem.size());
if (p.name == u"\\Windows\\ApiPort")
{
CSR_API_CONNECTINFO connect_info{};
const auto expected_connect_length = connection_info_length.read();
if (expected_connect_length < sizeof(CSR_API_CONNECTINFO))
{
return STATUS_BUFFER_TOO_SMALL;
}
// TODO: Use client_shared_memory to get the section entry and get the address from it?
connect_info.SharedSectionBase = c.proc.shared_section_address;
c.emu.write_memory(c.proc.shared_section_address + 2504,
0xFFFFFFFF); // BaseStaticServerData->TermsrvClientTimeZoneId
const auto static_server_data =
c.win_emu.memory.allocate_memory(0x10000, memory_permission::read_write);
connect_info.SharedStaticServerData = static_server_data;
c.emu.write_memory(static_server_data + 8, connect_info.SharedSectionBase);
c.emu.write_memory(connection_info, &connect_info, sizeof(connect_info));
}
else
{
std::vector<uint8_t> zero_mem{};
zero_mem.resize(connection_info_length.read(), 0);
c.emu.write_memory(connection_info, zero_mem.data(), zero_mem.size());
}
}
client_shared_memory.access([&](PORT_VIEW64& view) {
@@ -39,6 +76,20 @@ namespace syscalls
return STATUS_SUCCESS;
}
NTSTATUS handle_NtSecureConnectPort(const syscall_context& c, emulator_object<handle> client_port_handle,
emulator_object<UNICODE_STRING<EmulatorTraits<Emu64>>> server_port_name,
emulator_object<SECURITY_QUALITY_OF_SERVICE> security_qos,
emulator_object<PORT_VIEW64> client_shared_memory,
emulator_pointer /*server_sid*/,
emulator_object<REMOTE_PORT_VIEW64> server_shared_memory,
emulator_object<ULONG> maximum_message_length, emulator_pointer connection_info,
emulator_object<ULONG> connection_info_length)
{
return handle_NtConnectPort(c, client_port_handle, server_port_name, security_qos, client_shared_memory,
server_shared_memory, maximum_message_length, connection_info,
connection_info_length);
}
NTSTATUS handle_NtAlpcSendWaitReceivePort(const syscall_context& c, const handle port_handle, const ULONG /*flags*/,
const emulator_object<PORT_MESSAGE64> /*send_message*/,
const emulator_object<ALPC_MESSAGE_ATTRIBUTES>

View File

@@ -64,12 +64,26 @@ namespace syscalls
if (filename == u"\\Windows\\SharedSection")
{
constexpr auto shared_section_size = 0x10000;
const auto address = c.win_emu.memory.find_free_allocation_base(shared_section_size);
c.win_emu.memory.allocate_memory(address, shared_section_size, memory_permission::read_write);
c.proc.shared_section_address = address;
c.proc.shared_section_size = shared_section_size;
section_handle.write(SHARED_SECTION);
return STATUS_SUCCESS;
}
if (filename == u"DBWIN_BUFFER")
{
constexpr auto dbwin_buffer_section_size = 0x1000;
const auto address = c.win_emu.memory.find_free_allocation_base(dbwin_buffer_section_size);
c.win_emu.memory.allocate_memory(address, dbwin_buffer_section_size, memory_permission::read_write);
c.proc.dbwin_buffer = address;
c.proc.dbwin_buffer_size = dbwin_buffer_section_size;
section_handle.write(DBWIN_BUFFER);
return STATUS_SUCCESS;
}
@@ -120,10 +134,8 @@ namespace syscalls
if (section_handle == SHARED_SECTION)
{
constexpr auto shared_section_size = 0x10000;
const auto address = c.win_emu.memory.find_free_allocation_base(shared_section_size);
c.win_emu.memory.allocate_memory(address, shared_section_size, memory_permission::read_write);
const auto shared_section_size = c.proc.shared_section_size;
const auto address = c.proc.shared_section_address;
const std::u16string_view windows_dir = c.proc.kusd.get().NtSystemRoot.arr;
const auto windows_dir_size = windows_dir.size() * 2;
@@ -168,11 +180,8 @@ namespace syscalls
if (section_handle == DBWIN_BUFFER)
{
constexpr auto dbwin_buffer_section_size = 0x1000;
const auto address = c.win_emu.memory.find_free_allocation_base(dbwin_buffer_section_size);
c.win_emu.memory.allocate_memory(address, dbwin_buffer_section_size, memory_permission::read_write);
c.proc.dbwin_buffer = address;
const auto dbwin_buffer_section_size = c.proc.dbwin_buffer_size;
const auto address = c.proc.dbwin_buffer;
if (view_size)
{
@@ -255,10 +264,17 @@ namespace syscalls
return STATUS_INVALID_PARAMETER;
}
if (base_address == c.proc.shared_section_address)
{
c.proc.shared_section_address = 0;
c.win_emu.memory.release_memory(base_address, static_cast<size_t>(c.proc.shared_section_size));
return STATUS_SUCCESS;
}
if (base_address == c.proc.dbwin_buffer)
{
c.proc.dbwin_buffer = 0;
c.win_emu.memory.release_memory(base_address, 0x1000);
c.win_emu.memory.release_memory(base_address, static_cast<size_t>(c.proc.dbwin_buffer_size));
return STATUS_SUCCESS;
}

View File

@@ -115,10 +115,88 @@ namespace syscalls
return handle_query<SYSTEM_TIMEOFDAY_INFORMATION64>(c.emu, system_information, system_information_length,
return_length,
[&](SYSTEM_TIMEOFDAY_INFORMATION64& info) {
memset(&info, 0, sizeof(info));
info.BootTime.QuadPart = 0;
info.TimeZoneId = 0x00000002;
// TODO: Fill
});
case SystemTimeZoneInformation:
case SystemCurrentTimeZoneInformation:
return handle_query<SYSTEM_TIMEZONE_INFORMATION>(
c.emu, system_information, system_information_length, return_length,
[&](SYSTEM_TIMEZONE_INFORMATION& tzi) {
memset(&tzi, 0, sizeof(tzi));
tzi.Bias = -60;
tzi.StandardBias = 0;
tzi.DaylightBias = -60;
constexpr std::u16string_view std_name{u"W. Europe Standard Time"};
memcpy(&tzi.StandardName.arr[0], std_name.data(), std_name.size() * sizeof(char16_t));
constexpr std::u16string_view dlt_name{u"W. Europe Daylight Time"};
memcpy(&tzi.DaylightName.arr[0], dlt_name.data(), dlt_name.size() * sizeof(char16_t));
// Standard Time: Last Sunday in October, 03:00
tzi.StandardDate.wMonth = 10;
tzi.StandardDate.wDayOfWeek = 0;
tzi.StandardDate.wDay = 5;
tzi.StandardDate.wHour = 3;
tzi.StandardDate.wMinute = 0;
tzi.StandardDate.wSecond = 0;
tzi.StandardDate.wMilliseconds = 0;
// Daylight Time: Last Sunday in March, 02:00
tzi.DaylightDate.wMonth = 3;
tzi.DaylightDate.wDayOfWeek = 0;
tzi.DaylightDate.wDay = 5;
tzi.DaylightDate.wHour = 2;
tzi.DaylightDate.wMinute = 0;
tzi.DaylightDate.wSecond = 0;
tzi.DaylightDate.wMilliseconds = 0;
});
case SystemDynamicTimeZoneInformation:
return handle_query<SYSTEM_DYNAMIC_TIMEZONE_INFORMATION>(
c.emu, system_information, system_information_length, return_length,
[&](SYSTEM_DYNAMIC_TIMEZONE_INFORMATION& dtzi) {
memset(&dtzi, 0, sizeof(dtzi));
dtzi.Bias = -60;
dtzi.StandardBias = 0;
dtzi.DaylightBias = -60;
constexpr std::u16string_view std_name{u"W. Europe Standard Time"};
memcpy(&dtzi.StandardName.arr[0], std_name.data(), std_name.size() * sizeof(char16_t));
constexpr std::u16string_view dlt_name{u"W. Europe Daylight Time"};
memcpy(&dtzi.DaylightName.arr[0], dlt_name.data(), dlt_name.size() * sizeof(char16_t));
constexpr std::u16string_view key_name{u"W. Europe Standard Time"};
memcpy(&dtzi.TimeZoneKeyName.arr[0], key_name.data(), key_name.size() * sizeof(char16_t));
// Standard Time: Last Sunday in October, 03:00
dtzi.StandardDate.wMonth = 10;
dtzi.StandardDate.wDayOfWeek = 0;
dtzi.StandardDate.wDay = 5;
dtzi.StandardDate.wHour = 3;
dtzi.StandardDate.wMinute = 0;
dtzi.StandardDate.wSecond = 0;
dtzi.StandardDate.wMilliseconds = 0;
// Daylight Time: Last Sunday in March, 02:00
dtzi.DaylightDate.wMonth = 3;
dtzi.DaylightDate.wDayOfWeek = 0;
dtzi.DaylightDate.wDay = 5;
dtzi.DaylightDate.wHour = 2;
dtzi.DaylightDate.wMinute = 0;
dtzi.DaylightDate.wSecond = 0;
dtzi.DaylightDate.wMilliseconds = 0;
dtzi.DynamicDaylightTimeDisabled = FALSE;
});
case SystemRangeStartInformation:
return handle_query<SYSTEM_RANGE_START_INFORMATION64>(c.emu, system_information, system_information_length,
return_length,

View File

@@ -18,7 +18,8 @@ namespace syscalls
return STATUS_INVALID_HANDLE;
}
if (info_class == ThreadSchedulerSharedDataSlot || info_class == ThreadBasePriority)
if (info_class == ThreadSchedulerSharedDataSlot || info_class == ThreadBasePriority ||
info_class == ThreadAffinityMask)
{
return STATUS_SUCCESS;
}