On Mon Jan 1 12:36:54 2024 +0000, Jinoh Kang wrote:
You're correct that `NtContinue()` indeed already tests for the alerts. There's something you've missed, though: `NtContinue` is only called when there is a pending [APC][], which is usually not the case if you're calling it directly outside of an APC. In fact, the heavy lifting here is done by `pBTCpuSetContext` alone. You're looking at an "emulator," called WoW64[^fname]. WoW64 works by switching[^hg] between 32bit mode and 64bit mode in the [user space][]. The 32bit guest app uses `I386_CONTEXT`, while the host process uses `AMD64_CONTEXT`. This means two things:
- `NtContinue` here will accept host `CONTEXT`, which is synonymous
with `AMD64_CONTEXT`. Therefore, this cannot be used to restore 32bit guest context. 2. `pBTCpuSetContext` is actually responsible for setting the 32bit guest context. After this context is set, the next 64bit-to-32bit transition[^hg] will restore this guest context. Note that `frame == NULL` in the usual case (no APC pending), which means that `NtTestAlert` is still needed[^null]. If `frame != NULL`, then `NtContinue` (which is almost a "noreturn" function) will continue executing from the context, which means the `NtTestAlert()` below won't be executed at all. [^fname]: This is evident in the filename, `dlls/wow64/syscall.c`. [^hg]: This is made possible by x86 far jump which can switch from 64-bit code segment to a 32-bit code segment, and vice versa. This technique is also known as "Heaven's Gate." [^null]: If `frame == NULL`, then the condition in `if (frame) NtContinue( frame->context, alertable );` is false. Therefore, the if body won't be executed. Then, the execution continues to `if (alertable) NtTestAlert();` [APC]: https://en.wikipedia.org/wiki/Asynchronous_procedure_call [user space]: https://en.wikipedia.org/wiki/User_space_and_kernel_space
Notice that you could have spot this: `if (frame)` is conditional, so `NtContinue` won't always be executed and the control will transfer to `NtTestAlert()` in this case.