A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about kernel-mode development.
 #28226  by myid
 Wed Apr 06, 2016 5:09 pm
Hi. I use KeInsertQueueApc to inject user mode shellcode. How can I wait until the user mode shellcode execution finished.
 #28236  by Brock
 Thu Apr 07, 2016 6:18 am
Generally that's a deadlock waiting to happen if the target thread becomes preempted for another reason or perhaps the thread that is to process the APC becomes suspended indefinitely. Using synchronization primitives such as events might be an option for you. Note: you'll notice that I use a pre-defined wait timeout to avoid what I said in the first sentence of my post. There may be better options available but in all honesty it's generally not a great idea especially when sharing events between kernel and usermode, however it can be done somewhat safely if you've a grasp of Windows security, understanding of namespaces (Global\BaseNamedObjects vs. Session-Based) and of course understanding thread contexts and process vs. the system handle table. Here's a small usermode-only example that you can apply to kernel mode using similar logic and design.
Code: Select all
procedure ApcProc(hEvent: THandle); stdcall;
begin
   // execute shellcode & trigger event when done
   SetEvent(hEvent);
end;


procedure ThreadProc(lpParam: Pointer); stdcall;
begin
   ExitThread(0);
end;


procedure WaitQueuedApc();
var
  hThread: THandle;
  hEvent: THandle;
  dwThreadId: DWORD;
const
  MAX_WAIT = 5000; // 5 seconds
  TYPE_FLAGS = (MB_ICONINFORMATION or MB_TOPMOST);
begin
  hEvent := CreateEvent(nil, False, False, '__evtApc');
  if hEvent <> 0 then
  begin
  hThread := CreateThread(nil,
                          0,
                          @ThreadProc,
                          nil,
                          CREATE_SUSPENDED,
                          dwThreadId);
  if hThread <> 0 then
  begin
  if QueueUserApc(@ApcProc,
                   hThread,
                   hEvent) then
  begin
  ResumeThread(hThread);
  if WaitForSingleObject(hEvent,
                         MAX_WAIT) = WAIT_OBJECT_0 then
  MessageBox(0,
             'Apc shellcode completed',
             'success',
             TYPE_FLAGS);
  end;
  CloseHandle(hThread);
  end;
  CloseHandle(hEvent);
  end;
end;