Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Before Posting...
Please check out the Community Guidelines in the Announcements and Administration Category.

NtUserBuildHwndList fails

patrickdanielpatrickdaniel Member Posts: 11

here is my code. I am basically calling NtUserBuildHwndList but for some reason it fails with STATUS_INVALID_HANDLE.

    typedef NTSTATUS(NTAPI *_NtUserBuildHwndList)(
HDESK hDesktop,
HWND hwndParent,
BOOLEAN bChildren,
ULONG dwThreadId,
ULONG lParam,
HWND *pWnd,
ULONG *pBufSize
);
    _NtUserBuildHwndList NtUserBuildHwndList;
    HMODULE win32 = LoadLibraryW(L"win32u.dll");
NtUserBuildHwndList = (_NtUserBuildHwndList)GetProcAddress(win32, "NtUserBuildHwndList");
if (!NtUserGetThreadDesktop)
    puts("major err");

printf("gle: %d\n", GetLastError());
DWORD dwBuffer = 0;
HWND* pBuf = NULL;
DWORD dwThread = GetCurrentThreadId();
HDESK hDesktopWindow = OpenInputDesktop(0, 0, GENERIC_ALL);

NTSTATUS Status = NtUserBuildHwndList(hDesktopWindow, NULL, FALSE, 0, 0, NULL, &dwBuffer);
if (!NT_SUCCESS(Status)) {
    printf("status 123: %x\n", Status);
}

The exported function is resolved correctly but calling NtUserBuildHwndList fails with STATUS_INVALID_HANDLE. What is the reason for this? I have not done anything incorrectly at all that I can tell of.

Comments

  • patrickdanielpatrickdaniel Member Posts: 11
    edited June 28

    I have tried it again it still does not work? what am i doing wrong

  • raj_rraj_r Member - All Emails Posts: 981

    I dont think this is the right place to ask about usermode code and undocumented at that but you should atleast be able to verify some of the undocumentedness with a debugger in hand

    Your Prototype appears to be Wrong the function appears to be take 8 parameters instead of 7 as in your prototype

    you should be aware win32u.dll is just a stub that does a syscall
    the actual implementation is in win32kfull.sys

    dumping the UNWIND_INFO for that particular function and looking for further argumets apart from 4 passed in registers

    i can notice it takes 4 more parameters (total 8 in all)

    here is how to do it

    : kd> .fnent win32kfull!NtUserBuildHwndList
    Debugger function entry 000001b6`b2179ae8 for:
    (fffff65d`7aabc6c0)   win32kfull!NtUserBuildHwndList   |  (fffff65d`7aabc9ec)   win32kfull!xxxImeWindowPosChanged
    Exact matches:
        win32kfull!NtUserBuildHwndList (void)
    
    BeginAddress      = 00000000`0005c6c0
    EndAddress        = 00000000`0005c9e5
    UnwindInfoAddress = 00000000`002e5060
    
    Unwind info at fffff65d`7ad45060, 1c bytes
      version 2, flags 1, prolog 16, codes 8
      handler routine: win32kfull!_C_specific_handler (fffff65d`7abaacd2), data 1
      00: offs 9, unwind op 6, op info 0    UWOP_EPILOG Length: 9. Flags: 0
      01: offs 5, unwind op 6, op info 1    UWOP_EPILOG Offset from end: 105 (FFFFF65D7AABC8E0)
      02: offs 16, unwind op 2, op info d   UWOP_ALLOC_SMALL.
      03: offs 12, unwind op 0, op info f   UWOP_PUSH_NONVOL reg: r15.
      04: offs 10, unwind op 0, op info d   UWOP_PUSH_NONVOL reg: r13.
      05: offs e, unwind op 0, op info c    UWOP_PUSH_NONVOL reg: r12.
      06: offs c, unwind op 0, op info 7    UWOP_PUSH_NONVOL reg: rdi.
      07: offs b, unwind op 0, op info 6    UWOP_PUSH_NONVOL reg: rsi.
    0: kd> $$ UWOP_ALLOC_SMALL  opinfo is 0xd  so size allocated is 0xd * 0x8 + 0x8
    0: kd> ? 0xd * 0x8 + 0x8
    Evaluate expression: 112 = 00000000`00000070
    0: kd> $$ homeparamspace = 0x20 + ret addr = 0x8 + 5 nv regs are saved = 0x28 
    0: kd> so the fifth arg will be at 0xc0 and so on
    Debug Options: <none>
    0: kd> # mov*,*rsp+*c0  win32kfull+5c6c0 win32kfull + 5c9e5
    win32kfull!NtUserBuildHwndList+0xb8:
    fffff65d`7aabc778 8b8c24c0000000  mov     ecx,dword ptr [rsp+0C0h]
    win32kfull!xxxImeWindowPosChanged+0x28d:
    fffff65d`7aabcc79 4c8bbc24c0000000 mov     r15,qword ptr [rsp+0C0h]
    win32kfull!FindWindowEx+0x1fe:
    fffff65d`7aabd226 488b8c24c0000000 mov     rcx,qword ptr [rsp+0C0h]
    0: kd> # mov*,*rsp+*c8  win32kfull+5c6c0 win32kfull + 5c9e5
    win32kfull!NtUserBuildHwndList+0x12e:
    fffff65d`7aabc7ee 8b9424c8000000  mov     edx,dword ptr [rsp+0C8h]
    win32kfull!xxxImeWindowPosChanged+0x295:
    fffff65d`7aabcc81 4c8bac24c8000000 mov     r13,qword ptr [rsp+0C8h]
    win32kfull!FindWindowEx+0x246:
    fffff65d`7aabd26e 4c8b8424c8000000 mov     r8,qword ptr [rsp+0C8h]
    0: kd> # mov*,*rsp+*d0  win32kfull+5c6c0 win32kfull + 5c9e5
    win32kfull!NtUserBuildHwndList+0x13f:
    fffff65d`7aabc7ff 488b8c24d0000000 mov     rcx,qword ptr [rsp+0D0h]
    win32kfull!NtUserBuildHwndList+0x189:
    fffff65d`7aabc849 488b8c24d0000000 mov     rcx,qword ptr [rsp+0D0h]
    win32kfull!FindWindowEx+0x2b7:
    fffff65d`7aabd2df 448bb424d0000000 mov     r14d,dword ptr [rsp+0D0h]
    0: kd> # mov*,*rsp+*d8  win32kfull+5c6c0 win32kfull + 5c9e5
    win32kfull!NtUserBuildHwndList+0x153:
    fffff65d`7aabc813 4c8ba424d8000000 mov     r12,qword ptr [rsp+0D8h]
    0: kd> # mov*,*rsp+*e0  win32kfull+5c6c0 win32kfull + 5c9e5
    0: kd> $$ function takes 8 params 
    0: kd> $$ where did you find the prototype
    

    just prototyping with random type it seems to work properly with here

    #include <stdio.h>
    #include <windows.h>
    typedef NTSTATUS ( NTAPI * NtUserBuildHwndList)(
        UINT64 a, UINT64 b, UINT64 c, UINT64 d, UINT64 e, UINT64 f, UINT64 *g, UINT64 *h );
    int main( void )
    {
        NtUserBuildHwndList nubhwlist;  
        HMODULE hMod = LoadLibraryA("win32u.dll");
        printf("%I64x\n", hMod);
        if (hMod) {
            nubhwlist = (NtUserBuildHwndList) GetProcAddress(hMod, "NtUserBuildHwndList");
            if (nubhwlist) {
                printf("%I64x\n", nubhwlist);
                UINT64 count = 0xbeadb0b5beadb0b5;
                UINT64 List[4096] = {  0xbeadb0b5 };
                NTSTATUS stat = nubhwlist(0, 0, 0, 0, 0, 512 , List, &count);
                printf("%x\t%I64x\n", stat, count);
            }
        }    
    } 
    

    resulting in 0x164 handles

    :\>ntubhwlist.exe
    7ff8710a0000
    7ff8710a1410
    0       beadb0b500000164
    
  • patrickdanielpatrickdaniel Member Posts: 11

    @raj_r said:
    I dont think this is the right place to ask about usermode code and undocumented at that but you should atleast be able to verify some of the undocumentedness with a debugger in hand

    Your Prototype appears to be Wrong the function appears to be take 8 parameters instead of 7 as in your prototype

    you should be aware win32u.dll is just a stub that does a syscall
    the actual implementation is in win32kfull.sys

    dumping the UNWIND_INFO for that particular function and looking for further argumets apart from 4 passed in registers

    i can notice it takes 4 more parameters (total 8 in all)

    here is how to do it

    : kd> .fnent win32kfull!NtUserBuildHwndList
    Debugger function entry 000001b6`b2179ae8 for:
    (fffff65d`7aabc6c0)   win32kfull!NtUserBuildHwndList   |  (fffff65d`7aabc9ec)   win32kfull!xxxImeWindowPosChanged
    Exact matches:
        win32kfull!NtUserBuildHwndList (void)
    
    BeginAddress      = 00000000`0005c6c0
    EndAddress        = 00000000`0005c9e5
    UnwindInfoAddress = 00000000`002e5060
    
    Unwind info at fffff65d`7ad45060, 1c bytes
      version 2, flags 1, prolog 16, codes 8
      handler routine: win32kfull!_C_specific_handler (fffff65d`7abaacd2), data 1
      00: offs 9, unwind op 6, op info 0  UWOP_EPILOG Length: 9. Flags: 0
      01: offs 5, unwind op 6, op info 1  UWOP_EPILOG Offset from end: 105 (FFFFF65D7AABC8E0)
      02: offs 16, unwind op 2, op info d UWOP_ALLOC_SMALL.
      03: offs 12, unwind op 0, op info f UWOP_PUSH_NONVOL reg: r15.
      04: offs 10, unwind op 0, op info d UWOP_PUSH_NONVOL reg: r13.
      05: offs e, unwind op 0, op info c  UWOP_PUSH_NONVOL reg: r12.
      06: offs c, unwind op 0, op info 7  UWOP_PUSH_NONVOL reg: rdi.
      07: offs b, unwind op 0, op info 6  UWOP_PUSH_NONVOL reg: rsi.
    0: kd> $$ UWOP_ALLOC_SMALL  opinfo is 0xd  so size allocated is 0xd * 0x8 + 0x8
    0: kd> ? 0xd * 0x8 + 0x8
    Evaluate expression: 112 = 00000000`00000070
    0: kd> $$ homeparamspace = 0x20 + ret addr = 0x8 + 5 nv regs are saved = 0x28 
    0: kd> so the fifth arg will be at 0xc0 and so on
    Debug Options: <none>
    0: kd> # mov*,*rsp+*c0  win32kfull+5c6c0 win32kfull + 5c9e5
    win32kfull!NtUserBuildHwndList+0xb8:
    fffff65d`7aabc778 8b8c24c0000000  mov     ecx,dword ptr [rsp+0C0h]
    win32kfull!xxxImeWindowPosChanged+0x28d:
    fffff65d`7aabcc79 4c8bbc24c0000000 mov     r15,qword ptr [rsp+0C0h]
    win32kfull!FindWindowEx+0x1fe:
    fffff65d`7aabd226 488b8c24c0000000 mov     rcx,qword ptr [rsp+0C0h]
    0: kd> # mov*,*rsp+*c8  win32kfull+5c6c0 win32kfull + 5c9e5
    win32kfull!NtUserBuildHwndList+0x12e:
    fffff65d`7aabc7ee 8b9424c8000000  mov     edx,dword ptr [rsp+0C8h]
    win32kfull!xxxImeWindowPosChanged+0x295:
    fffff65d`7aabcc81 4c8bac24c8000000 mov     r13,qword ptr [rsp+0C8h]
    win32kfull!FindWindowEx+0x246:
    fffff65d`7aabd26e 4c8b8424c8000000 mov     r8,qword ptr [rsp+0C8h]
    0: kd> # mov*,*rsp+*d0  win32kfull+5c6c0 win32kfull + 5c9e5
    win32kfull!NtUserBuildHwndList+0x13f:
    fffff65d`7aabc7ff 488b8c24d0000000 mov     rcx,qword ptr [rsp+0D0h]
    win32kfull!NtUserBuildHwndList+0x189:
    fffff65d`7aabc849 488b8c24d0000000 mov     rcx,qword ptr [rsp+0D0h]
    win32kfull!FindWindowEx+0x2b7:
    fffff65d`7aabd2df 448bb424d0000000 mov     r14d,dword ptr [rsp+0D0h]
    0: kd> # mov*,*rsp+*d8  win32kfull+5c6c0 win32kfull + 5c9e5
    win32kfull!NtUserBuildHwndList+0x153:
    fffff65d`7aabc813 4c8ba424d8000000 mov     r12,qword ptr [rsp+0D8h]
    0: kd> # mov*,*rsp+*e0  win32kfull+5c6c0 win32kfull + 5c9e5
    0: kd> $$ function takes 8 params 
    0: kd> $$ where did you find the prototype
    

    just prototyping with random type it seems to work properly with here

    #include <stdio.h>
    #include <windows.h>
    typedef NTSTATUS ( NTAPI * NtUserBuildHwndList)(
      UINT64 a, UINT64 b, UINT64 c, UINT64 d, UINT64 e, UINT64 f, UINT64 *g, UINT64 *h );
    int main( void )
    {
      NtUserBuildHwndList nubhwlist;  
      HMODULE hMod = LoadLibraryA("win32u.dll");
      printf("%I64x\n", hMod);
      if (hMod) {
          nubhwlist = (NtUserBuildHwndList) GetProcAddress(hMod, "NtUserBuildHwndList");
          if (nubhwlist) {
              printf("%I64x\n", nubhwlist);
              UINT64 count = 0xbeadb0b5beadb0b5;
              UINT64 List[4096] = {  0xbeadb0b5 };
              NTSTATUS stat = nubhwlist(0, 0, 0, 0, 0, 512 , List, &count);
              printf("%x\t%I64x\n", stat, count);
          }
      }    
    } 
    

    resulting in 0x164 handles

    :\>ntubhwlist.exe
    7ff8710a0000
    7ff8710a1410
    0       beadb0b500000164
    

    thank you!, Im guessing the function definition changed across different versions?))
    That is what I am assuming :) I will go and see across different win32u versions if anything is changed.

  • raj_rraj_r Member - All Emails Posts: 981

    do not quote the entrie reply quote only parts or fragments generally refrain from quoting unless it is an absolutely necessary context

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Upcoming OSR Seminars
Developing Minifilters 29 July 2019 OSR Seminar Space
Writing WDF Drivers 23 Sept 2019 OSR Seminar Space
Kernel Debugging 21 Oct 2019 OSR Seminar Space
Internals & Software Drivers 18 Nov 2019 Dulles, VA