| 407 | { |
| 408 | _IRQL_requires_max_(APC_LEVEL) |
| 409 | NTSTATUS QueueUserApc(PETHREAD Thread, PKNORMAL_ROUTINE NormalRoutine, PVOID Argument) |
| 410 | { |
| 411 | auto KeInitializeApc = static_cast<_KeInitializeApc>(Importer::GetKernelProcAddress(L"KeInitializeApc")); |
| 412 | auto KeInsertQueueApc = static_cast<_KeInsertQueueApc>(Importer::GetKernelProcAddress(L"KeInsertQueueApc")); |
| 413 | |
| 414 | if (!KeInitializeApc || !KeInsertQueueApc) |
| 415 | return STATUS_NOT_IMPLEMENTED; |
| 416 | |
| 417 | // Initializing user APC: |
| 418 | auto UserApc = static_cast<PKAPC>(VirtualMemory::AllocFromPool(sizeof(KAPC))); |
| 419 | KeInitializeApc(UserApc, Thread, OriginalApcEnvironment, |
| 420 | [](PRKAPC Apc, PKNORMAL_ROUTINE NormalRoutine, PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2) -> VOID |
| 421 | { |
| 422 | UNREFERENCED_PARAMETER(SystemArgument1); |
| 423 | UNREFERENCED_PARAMETER(SystemArgument2); |
| 424 | |
| 425 | if (PsIsThreadTerminating(PsGetCurrentThread())) |
| 426 | return; |
| 427 | |
| 428 | #ifdef _AMD64_ |
| 429 | // Fixing APC to Wow64-processes: |
| 430 | using _PsGetCurrentProcessWow64Process = PEPROCESS(NTAPI*)(); |
| 431 | auto GetWow64Process = static_cast<_PsGetCurrentProcessWow64Process>(Importer::GetKernelProcAddress(L"PsGetCurrentProcessWow64Process")); |
| 432 | if (!GetWow64Process || GetWow64Process()) |
| 433 | { |
| 434 | PsWrapApcWow64Thread(static_cast<PVOID*>(NormalContext), reinterpret_cast<PVOID*>(NormalRoutine)); |
| 435 | } |
| 436 | #else |
| 437 | UNREFERENCED_PARAMETER(NormalRoutine); |
| 438 | UNREFERENCED_PARAMETER(NormalContext); |
| 439 | #endif |
| 440 | |
| 441 | VirtualMemory::FreePoolMemory(Apc); |
| 442 | }, |
| 443 | |
| 444 | NULL, NormalRoutine, UserMode, Argument); |
| 445 | |
| 446 | // Enforcing delivery of user APCs: |
| 447 | auto KernelApc = static_cast<PKAPC>(VirtualMemory::AllocFromPool(sizeof(KAPC))); |
| 448 | KeInitializeApc(KernelApc, Thread, OriginalApcEnvironment, |
| 449 | [](PRKAPC Apc, PKNORMAL_ROUTINE NormalRoutine, PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2) -> VOID |
| 450 | { |
| 451 | UNREFERENCED_PARAMETER(NormalRoutine); |
| 452 | UNREFERENCED_PARAMETER(NormalContext); |
| 453 | UNREFERENCED_PARAMETER(SystemArgument1); |
| 454 | UNREFERENCED_PARAMETER(SystemArgument2); |
| 455 | |
| 456 | // Enforcing all user APCs delivery: |
| 457 | auto KeTestAlertThread = static_cast<_KeTestAlertThread>(Importer::GetKernelProcAddress(L"KeTestAlertThread")); |
| 458 | if (KeTestAlertThread) KeTestAlertThread(UserMode); |
| 459 | |
| 460 | VirtualMemory::FreePoolMemory(Apc); |
| 461 | }, |
| 462 | NULL, NULL, KernelMode, NULL |
| 463 | ); |
| 464 | |
| 465 | if (KeInsertQueueApc(UserApc, NULL, NULL, KernelMode)) |
| 466 | { |
no test coverage detected