четверг, 13 июля 2017 г.

win32k calls filtering on w10

Lets see on some functions from W32pServiceTableFilter on w10 build 16215:
stub_UserSetSensorPresence:
  push    ebp
  mov     ebp, esp
  push    2 ; call index
  call    _IsWin32KSyscallFiltered@4    ; IsWin32KSyscallFiltered(x)
  test    al, al
  jz      short loc_1361D
  lea     ecx, aNtusersetsenso          ; "NtUserSetSensorPresence"
  mov     edx, 2
  call    @NtUserWin32kSysCallFilterStub@8 ; NtUserWin32kSysCallFilterStub(x,x)
  call    _PsIsWin32KFilterEnabled@0    ; PsIsWin32KFilterEnabled()
  test    al, al
  jz      short loc_1361D
  lea     edx, _W32pServiceTableFilter
  mov     ecx, cs:_W32pServiceLimitFilter
  mov     eax, 2 ; call index
  lea     edx, [edx+ecx*4]
  movsx   eax, byte ptr [eax+edx]
  or      eax, eax
  jle     short loc_13619
  mov     eax, 0C000001Ch ;
STATUS_INVALID_SYSTEM_SERVICE
loc_13619:
  mov     esp, ebp
  pop     ebp
  retn
loc_1361D: ; call original function
  mov     esp, ebp
  pop     ebp
  jmp     _NtUserSetSensorPresence@4    ; NtUserSetSensorPresence(x)


In some case this stub just pass control to original function (NtUserSetSensorPresence in this case) if IsWin32KSyscallFiltered or PsIsWin32KFilterEnabled returned 0, returns STATUS_INVALID_SYSTEM_SERVICE or just do nothing. Last condition depends from byte stored with call index behind W32pServiceTableFilter, so we can write simple idc script to dump all functions which will return STATUS_INVALID_SYSTEM_SERVICE:
#include

static main(void)
{
  auto  cnt, addr, tab, ftab, i, fp, name;
  addr = LocByName("_W32pServiceLimitFilter");
  if ( addr == BADADDR )
  {
    Warn("Cannot find W32pServiceLimitFilter");
    return;
  }
  cnt = Dword(addr);
  tab = LocByName("_W32pServiceTableFilter");
  if ( tab == BADADDR )
  {
    Warn("Cannot find W32pServiceTableFilter");
    return;
  }
  ftab = cnt * 4 + tab;
  fp = fopen("wf32.dmp", "w");
  for ( i = 0; i < cnt; i++, tab = tab + 4, ftab = ftab + 1 )
  {
    if ( Byte(ftab) )
    {
      addr = Dword(tab);
      name = Name(addr);
      fprintf(fp, "[%d] \"%s\",\n", i, name);
    }
  }
  fclose(fp);
}


четверг, 6 июля 2017 г.

DelegatedNtdll

It seems that since est. w10 build 15007 you can have more than one loaded 32bit ntdll.dll
Function LdrpLoadDelegatedNtdll query key DelegatedNtdll via LdrQueryImageFileKeyOption then appends this value to \\SystemRoot\\system32\\ and loads it. Sure this required changes in callbacks propagation logic

There is table LdrpDelegatedNtdllExports which just hold pairs of exported symbol and offset to it "delegated" ptr:
  • LdrInitializeThunk -> LdrDelegatedLdrInitializeThunk
  • RtlUserThreadStart -> LdrDelegatedRtlUserThreadStart
  • RtlDispatchAPC -> LdrDelegatedRtlDispatchAPC
  • KiUserExceptionDispatcher -> LdrDelegatedKiUserExceptionDispatcher
  • KiUserApcDispatcher -> LdrDelegatedKiUserApcDispatcher
  • KiUserCallbackDispatcher -> LdrDelegatedKiUserCallbackDispatcher
  • KiRaiseUserExceptionDispatcher -> LdrDelegatedKiRaiseUserExceptionDispatcher
  • LdrSystemDllInitBlock -> LdrDelegatedSystemDllInitBlock
  • LdrpChildNtdll -> LdrpChildNtdllPointer
  • LdrParentInterlockedPopEntrySList -> LdrpParentInterlockedPopEntrySListPointer
  • LdrParentRtlInitializeNtUserPfn -> LdrpParentRtlInitializeNtUserPfnPointer
  • LdrParentRtlResetNtUserPfn -> LdrpParentRtlResetNtUserPfnPointer
  • LdrParentRtlRetrieveNtUserPfn -> LdrpParentRtlRetrieveNtUserPfnPointer

Lets see how this "delegated" pfns works