CreateMutex
까보면 다나와~

KiUserApcDispatcher

Kernel To User Callback 1 - KiUserApcDispatcher

 Application Stack Trace를 하게 되면 종종 KiUserApcDispatcher라는 녀석을 만나게됩니다.
기본적으로 Thread를 생성 초기화 하기위해서 User Level에서는 CreateThread , CreateThreadEx등을
이용하게 됩니다. 누구나 알다시피 CreateThread->NtCreateThread->ZwCreateThread 순으로 호출이
이루어지죠.

( SystemCallStub에 대한 내용은 설명하지 않겠습니다. ) ZwCreateThread는 Thread의 TCB 를 초기화 하고
Apc List, IRP List 등등을 초기화 합니다. 그리고 마지막으로 Thread 의 EntryPoint를 초기화할 System Routine과 Thread EntryPoint 등 바탕으로 Start Frame을 구성하고 Kernel Stack은 Switch Frame으로 초기화하여 Return
합니다.

 초기화 작업 완료 후 Task Switching 이 발생하게 되면 Thread의 System Routine을 통해서 User Level Thread의 Entry Point를 초기화 하게 되는데 이러한 과정에 KiUserApcDispatcher를 통해서 이루어집니다.
즉 Thread를 초기화 하는 System Routine은 User Level Thread의 Stack Frame의 EIP( Instruction Point )를 KiUserApcDispatcher로 지정하여 이를 Execute할 수 있도록해줍니다.

ReactOS 상의 관련 코드

VOID
NTAPI
PspUserThreadStartup(IN PKSTART_ROUTINE StartRoutine,
  IN PVOID StartContext)
{
...
  /* Make sure we're not already dead */
  if (!DeadThread)
  {
  /* Check if the Prefetcher is enabled */
  if (CcPfEnablePrefetcher)
  {
  /* FIXME: Prepare to prefetch this process */
  }
  /* Raise to APC */
  KeRaiseIrql(APC_LEVEL, &OldIrql);/* Queue the User APC */
  KiInitializeUserApc(NULL,
  (PVOID)((ULONG_PTR)Thread->Tcb.InitialStack -
  sizeof(KTRAP_FRAME) -
  SIZEOF_FX_SAVE_AREA),
  PspSystemDllEntryPoint,
  NULL,
  PspSystemDllBase,
  NULL);

/* Lower it back to passive */
  KeLowerIrql(PASSIVE_LEVEL);
  }
  else
  {
  /* We’re dead, kill us now */
  PspTerminateThreadByPointer(Thread,
  STATUS_THREAD_IS_TERMINATING,
  TRUE);
  }

}

VOID
NTAPI
KiInitializeUserApc(IN PKEXCEPTION_FRAME ExceptionFrame,
  IN PKTRAP_FRAME TrapFrame,
  IN PKNORMAL_ROUTINE NormalRoutine,
  IN PVOID NormalContext,
  IN PVOID SystemArgument1,
  IN PVOID SystemArgument2)
{
...
  /* Run at APC dispatcher */
  TrapFrame->Eip = (ULONG)KeUserApcDispatcher;
  TrapFrame->HardwareEsp = Stack;/* Setup Ring 3 state */
  TrapFrame->SegCs = Ke386SanitizeSeg(KGDT_R3_CODE, UserMode);
  TrapFrame->HardwareSegSs = Ke386SanitizeSeg(KGDT_R3_DATA, UserMode);
  TrapFrame->SegDs = Ke386SanitizeSeg(KGDT_R3_DATA, UserMode);
  TrapFrame->SegEs = Ke386SanitizeSeg(KGDT_R3_DATA, UserMode);
  TrapFrame->SegFs = Ke386SanitizeSeg(KGDT_R3_TEB, UserMode);
  TrapFrame->SegGs = 0;
  TrapFrame->ErrCode = 0;/* Sanitize EFLAGS */
  TrapFrame->EFlags = Ke386SanitizeFlags(Context.EFlags, UserMode);/* Check if thread has IOPL and force it enabled if so */
  if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= 0×3000;/* Setup the stack */
  *(PULONG_PTR)(Stack + 0 * sizeof(ULONG_PTR)) = (ULONG_PTR)NormalRoutine;
  *(PULONG_PTR)(Stack + 1 * sizeof(ULONG_PTR)) = (ULONG_PTR)NormalContext;
  *(PULONG_PTR)(Stack + 2 * sizeof(ULONG_PTR)) = (ULONG_PTR)SystemArgument1;
  *(PULONG_PTR)(Stack + 3 * sizeof(ULONG_PTR)) = (ULONG_PTR)SystemArgument2
;

}

KiUserApcDispatcher는 이러한 과정을 거치면서 UserMode 상에 Callback 되어지고 이러한 KiUserApcDispatcher는 LdrpInitialize를 통해서 Stack을 초기화 ZwContinue를 통해서 실제 Thread의 Entry Point를 Execute 하게 됩니다.

KiUserApcDispatcher는 Thread의 시작 뿐만아니라 Dll의 호출이나 User Level APC가 전달될때 발생하게 되며 이러한 경우 Stack 상에서 종종 볼수 있습니다.


- 출처 : http://www.insidewindows.kr/?p=30

  Comments,     Trackbacks