Featured

wow64!ProcessInit re-entered

Description first (last version dated 2015-7-27):

**************************************

Affected

All 64bit Windows with WoW64

Problem

wow64!ProcessInit can be called more than once
and if it is called second time it crashes or
returns unsuccess and process is terminated.

Explanation

Every thread in WoW64 process enters
wow64!Wow64LdrpInitialize

VOID
Wow64LdrpInitialize(
  PCONTEXT pInitialContext)
{
  static
  BOOLEAN bProcessInited = FALSE;
  NTSTATUS st;

  if(!bProcessInited)
  {
    st = ProcessInit(&CpuThreadSize);

    LdrProcessInitializationComplete();

    if(!NT_SUCCESS(st))
    {
      ...
      NtTerminateProcess(NtCurrentProcess(), st);
    }

    bProcessInited = TRUE;
    ...
  }

  ...
}

LdrProcessInitializationComplete()
effectively unblocks threads (if any)
waiting in LdrInitialize
so they can enter Wow64LdrpInitialize
and reach “if(!bProcessInited)” before
the initial thread executes “bProcessInited = TRUE;”

**************************************

And now I add:

  • When I analyzed it first time, I inspected the stacks and saw there are more threads within ProcessInit
  • It manifests more likely on slower CPUs
  • On Windows versions below 8.1 it just ends in process termination, since 8.1+ typically crashes during .mrdata initialization (enable_write, write, disable_write)
  • Since Windows 10 build 17672 it manifests even more likely because there is LdrpInitCompleteEvent involved. LdrProcessInitializationComplete() sets it and the waiting secondary thread becomes ready
  • There’s no 3rd party solution. I’m mitigating the condition by waiting for Ldr32 ready for some time

Possible solution

Microsoft should rewrite the initial part. For example: apply the same mechanism on bProcessInited as in LdrpInitialize on LdrpProcessInitialized (InterlockedCompareExchange + Sleep). Why not to call ProcessInit in wow64!DllMain?

I did the tests and it seems that on newer Windows 10+ re-entering ProcessInit makes no harms. Nevertheles it is still a bug. There are still possibilities (btrcpu, wow64log) to fail.

Lamentatio rusticana: When it works it must be changed (1)

You know it, you use/rely on it for years and then comes an agile full-stack who makes a change. And no, it’s no camphors of hex-coding dino.

Ok, win32k was in C++ +object programming, now they master some parts are in rust.

The concrete thing why I am crying here

/*#define AX_GetCurrentTeb64() ((AX_TEB65 *)(SIZE_T)__readfsdword(0xF70))*/

#define AX_GetCurrentTeb64() ((AX_TEB65 *)((SIZE_T)AX_NtCurrentTeb()-AX_TEB64_SIZE_ALLOC))/*#define AX_GetCurrentTeb64() ((AX_TEB65 *)(SIZE_T)__readfsdword(0xF70))*/

When it works it MUST be changed

and no it is not working here I will publish my ouputs in .txt

Design a site like this with WordPress.com
Get started