mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-19 03:33:56 +00:00
Implement APC support (#198)
Still not completely done and clean. I think some stuff is still broken
This commit is contained in:
@@ -670,6 +670,20 @@ typedef struct DECLSPEC_ALIGN(16) _CONTEXT64
|
||||
DWORD64 LastExceptionFromRip;
|
||||
} CONTEXT64, *PCONTEXT64;
|
||||
|
||||
typedef struct _CONTEXT_CHUNK
|
||||
{
|
||||
LONG Offset; // Offset may be negative.
|
||||
ULONG Length;
|
||||
} CONTEXT_CHUNK, *PCONTEXT_CHUNK;
|
||||
|
||||
typedef struct _CONTEXT_EX
|
||||
{
|
||||
CONTEXT_CHUNK All;
|
||||
CONTEXT_CHUNK Legacy;
|
||||
CONTEXT_CHUNK XState;
|
||||
CONTEXT_CHUNK KernelCet;
|
||||
} CONTEXT_EX, *PCONTEXT_EX;
|
||||
|
||||
template <typename Traits>
|
||||
struct EMU_EXCEPTION_RECORD
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using NTSTATUS = std::uint32_t;
|
||||
|
||||
#ifndef OS_WINDOWS
|
||||
#define STATUS_WAIT_0 ((NTSTATUS)0x00000000L)
|
||||
#define STATUS_USER_APC ((NTSTATUS)0x000000C0L)
|
||||
#define STATUS_TIMEOUT ((NTSTATUS)0x00000102L)
|
||||
#define STATUS_PENDING ((NTSTATUS)0x00000103L)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// NOLINTBEGIN(modernize-use-using)
|
||||
// NOLINTBEGIN(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
|
||||
typedef enum _THREADINFOCLASS
|
||||
{
|
||||
@@ -90,4 +90,32 @@ typedef struct _THREAD_TEB_INFORMATION
|
||||
ULONG BytesToRead; // Number of bytes to read.
|
||||
} THREAD_TEB_INFORMATION, *PTHREAD_TEB_INFORMATION;
|
||||
|
||||
// NOLINTEND(modernize-use-using)
|
||||
typedef enum _KCONTINUE_TYPE
|
||||
{
|
||||
KCONTINUE_UNWIND,
|
||||
KCONTINUE_RESUME,
|
||||
KCONTINUE_LONGJUMP,
|
||||
KCONTINUE_SET,
|
||||
KCONTINUE_LAST,
|
||||
} KCONTINUE_TYPE;
|
||||
|
||||
typedef struct _KCONTINUE_ARGUMENT
|
||||
{
|
||||
KCONTINUE_TYPE ContinueType;
|
||||
ULONG ContinueFlags;
|
||||
ULONGLONG Reserved[2];
|
||||
} KCONTINUE_ARGUMENT, *PKCONTINUE_ARGUMENT;
|
||||
|
||||
#define KCONTINUE_FLAG_TEST_ALERT 0x00000001
|
||||
#define KCONTINUE_FLAG_DELIVER_APC 0x00000002
|
||||
|
||||
#ifndef OS_WINDOWS
|
||||
typedef enum _QUEUE_USER_APC_FLAGS
|
||||
{
|
||||
QUEUE_USER_APC_FLAGS_NONE,
|
||||
QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC,
|
||||
QUEUE_USER_APC_CALLBACK_DATA_CONTEXT
|
||||
} QUEUE_USER_APC_FLAGS;
|
||||
#endif
|
||||
|
||||
// NOLINTEND(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
|
||||
@@ -431,6 +431,28 @@ namespace
|
||||
const auto epoch_time = std::chrono::system_clock::now().time_since_epoch();
|
||||
printf("Time: %lld\n", std::chrono::duration_cast<std::chrono::nanoseconds>(epoch_time).count());
|
||||
}
|
||||
|
||||
bool test_apc()
|
||||
{
|
||||
int executions = 0;
|
||||
|
||||
auto* apc_func = +[](ULONG_PTR param) {
|
||||
*reinterpret_cast<int*>(param) += 1; //
|
||||
};
|
||||
|
||||
QueueUserAPC(apc_func, GetCurrentThread(), reinterpret_cast<ULONG_PTR>(&executions));
|
||||
QueueUserAPC(apc_func, GetCurrentThread(), reinterpret_cast<ULONG_PTR>(&executions));
|
||||
|
||||
Sleep(1);
|
||||
|
||||
if (executions != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SleepEx(1, TRUE);
|
||||
return executions == 2;
|
||||
}
|
||||
}
|
||||
|
||||
#define RUN_TEST(func, name) \
|
||||
@@ -461,8 +483,7 @@ int main(const int argc, const char* argv[])
|
||||
RUN_TEST(test_native_exceptions, "Native Exceptions")
|
||||
RUN_TEST(test_tls, "TLS")
|
||||
RUN_TEST(test_socket, "Socket")
|
||||
|
||||
Sleep(1);
|
||||
RUN_TEST(test_apc, "APC")
|
||||
|
||||
return valid ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,33 @@
|
||||
|
||||
struct process_context;
|
||||
|
||||
struct pending_apc
|
||||
{
|
||||
uint32_t flags{};
|
||||
uint64_t apc_routine{};
|
||||
uint64_t apc_argument1{};
|
||||
uint64_t apc_argument2{};
|
||||
uint64_t apc_argument3{};
|
||||
|
||||
void serialize(utils::buffer_serializer& buffer) const
|
||||
{
|
||||
buffer.write(this->flags);
|
||||
buffer.write(this->apc_routine);
|
||||
buffer.write(this->apc_argument1);
|
||||
buffer.write(this->apc_argument2);
|
||||
buffer.write(this->apc_argument3);
|
||||
}
|
||||
|
||||
void deserialize(utils::buffer_deserializer& buffer)
|
||||
{
|
||||
buffer.read(this->flags);
|
||||
buffer.read(this->apc_routine);
|
||||
buffer.read(this->apc_argument1);
|
||||
buffer.read(this->apc_argument2);
|
||||
buffer.read(this->apc_argument3);
|
||||
}
|
||||
};
|
||||
|
||||
class emulator_thread : public ref_counted_object
|
||||
{
|
||||
public:
|
||||
@@ -57,6 +84,9 @@ class emulator_thread : public ref_counted_object
|
||||
uint32_t suspended{0};
|
||||
std::optional<std::chrono::steady_clock::time_point> await_time{};
|
||||
|
||||
bool apc_alertable{false};
|
||||
std::vector<pending_apc> pending_apcs{};
|
||||
|
||||
std::optional<NTSTATUS> pending_status{};
|
||||
|
||||
std::optional<emulator_allocator> gs_segment;
|
||||
@@ -125,8 +155,11 @@ class emulator_thread : public ref_counted_object
|
||||
buffer.write(this->alerted);
|
||||
|
||||
buffer.write(this->suspended);
|
||||
|
||||
buffer.write_optional(this->await_time);
|
||||
|
||||
buffer.write(this->apc_alertable);
|
||||
buffer.write_vector(this->pending_apcs);
|
||||
|
||||
buffer.write_optional(this->pending_status);
|
||||
buffer.write_optional(this->gs_segment);
|
||||
buffer.write_optional(this->teb);
|
||||
@@ -160,8 +193,11 @@ class emulator_thread : public ref_counted_object
|
||||
buffer.read(this->alerted);
|
||||
|
||||
buffer.read(this->suspended);
|
||||
|
||||
buffer.read_optional(this->await_time);
|
||||
|
||||
buffer.read(this->apc_alertable);
|
||||
buffer.read_vector(this->pending_apcs);
|
||||
|
||||
buffer.read_optional(this->pending_status);
|
||||
buffer.read_optional(this->gs_segment, [this] { return emulator_allocator(*this->memory_ptr); });
|
||||
buffer.read_optional(this->teb, [this] { return emulator_object<TEB64>(*this->memory_ptr); });
|
||||
|
||||
@@ -161,6 +161,11 @@ class emulator_object
|
||||
this->address_ = address;
|
||||
}
|
||||
|
||||
emulator_object<T> shift(const int64_t offset) const
|
||||
{
|
||||
return emulator_object<T>(*this->memory_, this->address_ + offset);
|
||||
}
|
||||
|
||||
private:
|
||||
memory_interface* memory_{};
|
||||
uint64_t address_{};
|
||||
|
||||
@@ -119,6 +119,7 @@ void process_context::setup(x64_emulator& emu, memory_manager& memory, const app
|
||||
this->ntdll_image_base = ntdll.image_base;
|
||||
this->ldr_initialize_thunk = ntdll.find_export("LdrInitializeThunk");
|
||||
this->rtl_user_thread_start = ntdll.find_export("RtlUserThreadStart");
|
||||
this->ki_user_apc_dispatcher = ntdll.find_export("KiUserApcDispatcher");
|
||||
this->ki_user_exception_dispatcher = ntdll.find_export("KiUserExceptionDispatcher");
|
||||
|
||||
this->default_register_set = emu.save_registers();
|
||||
@@ -139,6 +140,7 @@ void process_context::serialize(utils::buffer_serializer& buffer) const
|
||||
buffer.write(this->ntdll_image_base);
|
||||
buffer.write(this->ldr_initialize_thunk);
|
||||
buffer.write(this->rtl_user_thread_start);
|
||||
buffer.write(this->ki_user_apc_dispatcher);
|
||||
buffer.write(this->ki_user_exception_dispatcher);
|
||||
|
||||
buffer.write(this->events);
|
||||
@@ -173,6 +175,7 @@ void process_context::deserialize(utils::buffer_deserializer& buffer)
|
||||
buffer.read(this->ntdll_image_base);
|
||||
buffer.read(this->ldr_initialize_thunk);
|
||||
buffer.read(this->rtl_user_thread_start);
|
||||
buffer.read(this->ki_user_apc_dispatcher);
|
||||
buffer.read(this->ki_user_exception_dispatcher);
|
||||
|
||||
buffer.read(this->events);
|
||||
|
||||
@@ -75,6 +75,7 @@ struct process_context
|
||||
uint64_t ntdll_image_base{};
|
||||
uint64_t ldr_initialize_thunk{};
|
||||
uint64_t rtl_user_thread_start{};
|
||||
uint64_t ki_user_apc_dispatcher{};
|
||||
uint64_t ki_user_exception_dispatcher{};
|
||||
|
||||
handle_store<handle_types::event, event> events{};
|
||||
|
||||
@@ -270,7 +270,9 @@ namespace syscalls
|
||||
NTSTATUS handle_NtResumeThread(const syscall_context& c, handle thread_handle,
|
||||
emulator_object<ULONG> previous_suspend_count);
|
||||
NTSTATUS handle_NtContinue(const syscall_context& c, emulator_object<CONTEXT64> thread_context,
|
||||
BOOLEAN /*raise_alert*/);
|
||||
BOOLEAN raise_alert);
|
||||
NTSTATUS handle_NtContinueEx(const syscall_context& c, emulator_object<CONTEXT64> thread_context,
|
||||
uint64_t continue_argument);
|
||||
NTSTATUS handle_NtGetNextThread(const syscall_context& c, handle process_handle, handle thread_handle,
|
||||
ACCESS_MASK /*desired_access*/, ULONG /*handle_attributes*/, ULONG flags,
|
||||
emulator_object<handle> new_thread_handle);
|
||||
@@ -289,6 +291,14 @@ namespace syscalls
|
||||
emulator_object<PS_ATTRIBUTE_LIST<EmulatorTraits<Emu64>>> attribute_list);
|
||||
NTSTATUS handle_NtGetCurrentProcessorNumberEx(const syscall_context&,
|
||||
emulator_object<PROCESSOR_NUMBER> processor_number);
|
||||
NTSTATUS handle_NtQueueApcThreadEx2(const syscall_context& c, handle thread_handle, handle reserve_handle,
|
||||
uint32_t apc_flags, uint64_t apc_routine, uint64_t apc_argument1,
|
||||
uint64_t apc_argument2, uint64_t apc_argument3);
|
||||
NTSTATUS handle_NtQueueApcThreadEx(const syscall_context& c, handle thread_handle, handle reserve_handle,
|
||||
uint64_t apc_routine, uint64_t apc_argument1, uint64_t apc_argument2,
|
||||
uint64_t apc_argument3);
|
||||
NTSTATUS handle_NtQueueApcThread(const syscall_context& c, handle thread_handle, uint64_t apc_routine,
|
||||
uint64_t apc_argument1, uint64_t apc_argument2, uint64_t apc_argument3);
|
||||
|
||||
// syscalls/timer.cpp:
|
||||
NTSTATUS handle_NtQueryTimerResolution(const syscall_context&, emulator_object<ULONG> maximum_time,
|
||||
@@ -413,10 +423,10 @@ namespace syscalls
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtTestAlert()
|
||||
NTSTATUS handle_NtTestAlert(const syscall_context& c)
|
||||
{
|
||||
// puts("NtTestAlert not supported");
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
c.win_emu.yield_thread(true);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtUserSystemParametersInfo()
|
||||
@@ -664,6 +674,7 @@ void syscall_dispatcher::add_handlers(std::map<std::string, syscall_handler>& ha
|
||||
add_handler(NtQueryLicenseValue);
|
||||
add_handler(NtTestAlert);
|
||||
add_handler(NtContinue);
|
||||
add_handler(NtContinueEx);
|
||||
add_handler(NtTerminateProcess);
|
||||
add_handler(NtWriteFile);
|
||||
add_handler(NtRaiseHardError);
|
||||
@@ -749,6 +760,9 @@ void syscall_dispatcher::add_handlers(std::map<std::string, syscall_handler>& ha
|
||||
add_handler(NtClearEvent);
|
||||
add_handler(NtTraceControl);
|
||||
add_handler(NtUserGetProcessUIContextInformation);
|
||||
add_handler(NtQueueApcThreadEx2);
|
||||
add_handler(NtQueueApcThreadEx);
|
||||
add_handler(NtQueueApcThread);
|
||||
|
||||
#undef add_handler
|
||||
}
|
||||
@@ -116,11 +116,6 @@ namespace syscalls
|
||||
const emulator_object<handle> handles, const WAIT_TYPE wait_type,
|
||||
const BOOLEAN alertable, const emulator_object<LARGE_INTEGER> timeout)
|
||||
{
|
||||
if (alertable)
|
||||
{
|
||||
c.win_emu.log.print(color::gray, "Alertable NtWaitForMultipleObjects not supported yet!\n");
|
||||
}
|
||||
|
||||
if (wait_type != WaitAny && wait_type != WaitAll)
|
||||
{
|
||||
c.win_emu.log.error("Wait type not supported!\n");
|
||||
@@ -151,18 +146,13 @@ namespace syscalls
|
||||
t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.clock(), timeout.read());
|
||||
}
|
||||
|
||||
c.win_emu.yield_thread();
|
||||
c.win_emu.yield_thread(alertable);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtWaitForSingleObject(const syscall_context& c, const handle h, const BOOLEAN alertable,
|
||||
const emulator_object<LARGE_INTEGER> timeout)
|
||||
{
|
||||
if (alertable)
|
||||
{
|
||||
c.win_emu.log.print(color::gray, "Alertable NtWaitForSingleObject not supported yet!\n");
|
||||
}
|
||||
|
||||
if (!is_awaitable_object_type(h))
|
||||
{
|
||||
c.win_emu.log.print(color::gray, "Unsupported handle type for NtWaitForSingleObject: %d!\n", h.value.type);
|
||||
@@ -178,7 +168,7 @@ namespace syscalls
|
||||
t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.clock(), timeout.read());
|
||||
}
|
||||
|
||||
c.win_emu.yield_thread();
|
||||
c.win_emu.yield_thread(alertable);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -282,17 +282,9 @@ namespace syscalls
|
||||
NTSTATUS handle_NtDelayExecution(const syscall_context& c, const BOOLEAN alertable,
|
||||
const emulator_object<LARGE_INTEGER> delay_interval)
|
||||
{
|
||||
if (alertable)
|
||||
{
|
||||
c.win_emu.log.error("Alertable NtDelayExecution not supported yet!\n");
|
||||
c.emu.stop();
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
auto& t = c.win_emu.current_thread();
|
||||
t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.clock(), delay_interval.read());
|
||||
|
||||
c.win_emu.yield_thread();
|
||||
c.win_emu.yield_thread(alertable);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
@@ -369,17 +361,38 @@ namespace syscalls
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtContinue(const syscall_context& c, const emulator_object<CONTEXT64> thread_context,
|
||||
const BOOLEAN /*raise_alert*/)
|
||||
NTSTATUS handle_NtContinueEx(const syscall_context& c, const emulator_object<CONTEXT64> thread_context,
|
||||
const uint64_t continue_argument)
|
||||
{
|
||||
c.write_status = false;
|
||||
|
||||
KCONTINUE_ARGUMENT argument{};
|
||||
if (continue_argument <= 0xFF)
|
||||
{
|
||||
argument.ContinueFlags = KCONTINUE_FLAG_TEST_ALERT;
|
||||
}
|
||||
else
|
||||
{
|
||||
argument = c.emu.read_memory<KCONTINUE_ARGUMENT>(continue_argument);
|
||||
}
|
||||
|
||||
const auto context = thread_context.read();
|
||||
cpu_context::restore(c.emu, context);
|
||||
|
||||
if (argument.ContinueFlags & KCONTINUE_FLAG_TEST_ALERT)
|
||||
{
|
||||
c.win_emu.yield_thread(true);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtContinue(const syscall_context& c, const emulator_object<CONTEXT64> thread_context,
|
||||
const BOOLEAN raise_alert)
|
||||
{
|
||||
return handle_NtContinueEx(c, thread_context, raise_alert ? 1 : 0);
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtGetNextThread(const syscall_context& c, const handle process_handle, const handle thread_handle,
|
||||
const ACCESS_MASK /*desired_access*/, const ULONG /*handle_attributes*/,
|
||||
const ULONG flags, const emulator_object<handle> new_thread_handle)
|
||||
@@ -549,4 +562,60 @@ namespace syscalls
|
||||
processor_number.write(number);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtQueueApcThreadEx2(const syscall_context& c, const handle thread_handle,
|
||||
const handle /*reserve_handle*/, const uint32_t apc_flags,
|
||||
const uint64_t apc_routine, const uint64_t apc_argument1,
|
||||
const uint64_t apc_argument2, const uint64_t apc_argument3)
|
||||
{
|
||||
auto* thread = thread_handle == CURRENT_THREAD ? c.proc.active_thread : c.proc.threads.get(thread_handle);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (apc_flags)
|
||||
{
|
||||
c.win_emu.log.error("Unsupported APC flags: %X\n", apc_flags);
|
||||
c.emu.stop();
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
thread->pending_apcs.push_back({
|
||||
.flags = apc_flags,
|
||||
.apc_routine = apc_routine,
|
||||
.apc_argument1 = apc_argument1,
|
||||
.apc_argument2 = apc_argument2,
|
||||
.apc_argument3 = apc_argument3,
|
||||
});
|
||||
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtQueueApcThreadEx(const syscall_context& c, const handle thread_handle,
|
||||
const handle reserve_handle, const uint64_t apc_routine,
|
||||
const uint64_t apc_argument1, const uint64_t apc_argument2,
|
||||
const uint64_t apc_argument3)
|
||||
{
|
||||
uint32_t flags{0};
|
||||
auto real_reserve_handle = reserve_handle;
|
||||
if (reserve_handle.bits == QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC)
|
||||
{
|
||||
real_reserve_handle.bits = 0;
|
||||
flags = QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC;
|
||||
static_assert(QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC == 1);
|
||||
}
|
||||
|
||||
return handle_NtQueueApcThreadEx2(c, thread_handle, real_reserve_handle, flags, apc_routine, apc_argument1,
|
||||
apc_argument2, apc_argument3);
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtQueueApcThread(const syscall_context& c, const handle thread_handle, const uint64_t apc_routine,
|
||||
const uint64_t apc_argument1, const uint64_t apc_argument2,
|
||||
const uint64_t apc_argument3)
|
||||
{
|
||||
return handle_NtQueueApcThreadEx(c, thread_handle, make_handle(0), apc_routine, apc_argument1, apc_argument2,
|
||||
apc_argument3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,51 @@ namespace
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void dispatch_next_apc(windows_emulator& win_emu, emulator_thread& thread)
|
||||
{
|
||||
assert(&win_emu.current_thread() == &thread);
|
||||
|
||||
auto& emu = win_emu.emu();
|
||||
auto& apcs = thread.pending_apcs;
|
||||
if (apcs.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
win_emu.log.print(color::dark_gray, "Dispatching APC...\n");
|
||||
|
||||
const auto next_apx = apcs.front();
|
||||
apcs.erase(apcs.begin());
|
||||
|
||||
struct
|
||||
{
|
||||
CONTEXT64 context{};
|
||||
CONTEXT_EX context_ex{};
|
||||
KCONTINUE_ARGUMENT continue_argument{};
|
||||
} stack_layout;
|
||||
|
||||
static_assert(offsetof(decltype(stack_layout), continue_argument) == 0x4F0);
|
||||
|
||||
stack_layout.context.P1Home = next_apx.apc_argument1;
|
||||
stack_layout.context.P2Home = next_apx.apc_argument2;
|
||||
stack_layout.context.P3Home = next_apx.apc_argument3;
|
||||
stack_layout.context.P4Home = next_apx.apc_routine;
|
||||
|
||||
stack_layout.continue_argument.ContinueFlags |= KCONTINUE_FLAG_TEST_ALERT;
|
||||
|
||||
auto& ctx = stack_layout.context;
|
||||
ctx.ContextFlags = CONTEXT64_ALL;
|
||||
cpu_context::save(emu, ctx);
|
||||
|
||||
const auto initial_sp = emu.reg(x64_register::rsp);
|
||||
const auto new_sp = align_down(initial_sp - sizeof(stack_layout), 0x100);
|
||||
|
||||
emu.write_memory(new_sp, stack_layout);
|
||||
|
||||
emu.reg(x64_register::rsp, new_sp);
|
||||
emu.reg(x64_register::rip, win_emu.process.ki_user_apc_dispatcher);
|
||||
}
|
||||
|
||||
bool switch_to_thread(windows_emulator& win_emu, emulator_thread& thread, const bool force = false)
|
||||
{
|
||||
if (thread.is_terminated())
|
||||
@@ -90,30 +135,38 @@ namespace
|
||||
auto& context = win_emu.process;
|
||||
|
||||
const auto is_ready = thread.is_thread_ready(context, win_emu.clock());
|
||||
const auto can_dispatch_apcs = thread.apc_alertable && !thread.pending_apcs.empty();
|
||||
|
||||
if (!is_ready && !force)
|
||||
if (!is_ready && !force && !can_dispatch_apcs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* active_thread = context.active_thread;
|
||||
|
||||
if (active_thread == &thread)
|
||||
if (active_thread != &thread)
|
||||
{
|
||||
thread.setup_if_necessary(emu, context);
|
||||
return true;
|
||||
if (active_thread)
|
||||
{
|
||||
win_emu.log.print(color::dark_gray, "Performing thread switch: %X -> %X\n", active_thread->id,
|
||||
thread.id);
|
||||
active_thread->save(emu);
|
||||
}
|
||||
|
||||
context.active_thread = &thread;
|
||||
|
||||
thread.restore(emu);
|
||||
}
|
||||
|
||||
if (active_thread)
|
||||
{
|
||||
win_emu.log.print(color::dark_gray, "Performing thread switch: %X -> %X\n", active_thread->id, thread.id);
|
||||
active_thread->save(emu);
|
||||
}
|
||||
|
||||
context.active_thread = &thread;
|
||||
|
||||
thread.restore(emu);
|
||||
thread.setup_if_necessary(emu, context);
|
||||
|
||||
if (can_dispatch_apcs)
|
||||
{
|
||||
thread.mark_as_ready(STATUS_USER_APC);
|
||||
dispatch_next_apc(win_emu, thread);
|
||||
}
|
||||
|
||||
thread.apc_alertable = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -298,9 +351,10 @@ void windows_emulator::setup_process(const application_settings& app_settings)
|
||||
switch_to_thread(*this, main_thread_id);
|
||||
}
|
||||
|
||||
void windows_emulator::yield_thread()
|
||||
void windows_emulator::yield_thread(const bool alertable)
|
||||
{
|
||||
this->switch_thread_ = true;
|
||||
this->current_thread().apc_alertable = alertable;
|
||||
this->emu().stop();
|
||||
}
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ class windows_emulator
|
||||
bool buffer_stdout{false};
|
||||
bool fuzzing{false};
|
||||
|
||||
void yield_thread();
|
||||
void yield_thread(bool alertable = false);
|
||||
void perform_thread_switch();
|
||||
bool activate_thread(uint32_t id);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user