mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-28 23:41:03 +00:00
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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user