joe85231 发表于 2017-6-1 12:16:02

使用NtUserBuildHwndList遍历窗口_win7x64



在我的上一篇文章中讲到
51604788



枚举窗口 使用EnumWinodws是调用内核中NtUserBuildHwndList 这个函数最后2个参数必须是R3的地址

不然会返回0xC0000008错误,并且如果使用控制台窗口测试,这时ETHREAD下的win32Thread是NULL 也会返回0xC0000008错误

去实现的时候,返回成功了,但只传回线程的窗口HWND

然后去看了看win32k.sys的这个函数

下面是我修改了好的IDA F5这个函数

// typedef NTSTATUS (__fastcall *PFN_NTUSERBULIDHWNDLIST)(
//                                                   __int64 hDesktop,
//                                                   __int64 hWndParent,
//                                                   BOOLEAN bChildren,
//                                                   unsigned int dwThreadId,
//                                                   unsigned int lParam,
//                                                   OUT PVOID pWnd,
//                                                   OUT PVOID pBufSize);

/*参考链接:
http://read.pudn.com/downloads3/sourcecode/windows/248345/win2k/private/ntos/w32/ntuser/kernel/enumwin.c__.htm (win2k\private\ntos\w32\ntuser\kernel\enumwin.c)
http://svn.netlabs.org/repos/odin32/trunk/include/win/win.h
https://www.reactos.org/wiki/Techwiki:Win32k/WND
https://www.reactos.org/wiki/Techwiki:Win32k/THREADINFO
http://bbs.pediy.com/showthread.php?t=100983
http://www.mengwuji.net/thread-99-1-1.html
http://bbs.pediy.com/showthread.php?t=131950
*/
__int64 __fastcall NtUserBuildHwndList(__int64 hDesktop, __int64 hWndParent, BOOL bChildren, unsigned int dwThreadId, unsigned int MaxNum_user, PVOID pWnd_User, unsigned __int64 pBuffSize_User)
{
int m_ThreadId; // ebx@1
BOOL m_bChildren; // er14@1
__int64 m_hWndParent; // rdi@1
__int64 m_hDesktop; // rsi@1
__int64 m_m_pBwl; // r12@1
UINT flags; // er13@1
__int64 v13; // rax@1
__int64 v14; // rdx@1
tagWND *m_tagWnd; // rax@4
NTSTATUS status; // ebx@5
tagTHREADINFO *m_pti; // rax@8
tagTHREADINFO *m_m_pti; // rdi@8
tagDESKTOP *m_rpdesk; // rax@9
tagDESKTOP *m_p_desk_top; // rsi@16
tagTHREADINFO *v21; // rax@16
tagWND *m_top_wnd; // rax@22
__int64 m_pBwl; // rax@27
unsigned int m_max_hwnd; // edi@29
__int64 m_max_num_user; // rbx@29
unsigned __int64 m_p_buff_size_user; // r13@31
unsigned __int64 m_m_p_buff_size_user; // rdx@31
int v29; // @16
tagTHREADINFO *v30; // @16
tagDESKTOP *v31; // @16
int v32; // @16
int v33; // @16
PVOID Object; // @14

m_ThreadId = dwThreadId;
m_bChildren = bChildren;
m_hWndParent = hWndParent;
m_hDesktop = hDesktop;
m_m_pBwl = 0i64;
flags = 2;
LODWORD(v13) = ExEnterPriorityRegionAndAcquireResourceExclusive(gpresUser);
gptiCurrent = v13;
gbValidateHandleForIL = 0;
if ( *(_BYTE *)gpsi & 4 )
    flags = 10;
if ( m_hWndParent )
{
    LODWORD(m_tagWnd) = ValidateHwnd(m_hWndParent);
    if ( !m_tagWnd )
    {
      status = 0xC0000008;
      goto LABEL_41;
    }
}
else
{
    m_tagWnd = 0i64;
}
if ( m_ThreadId )
{
    m_pti = (tagTHREADINFO *)PtiFromThreadId(m_ThreadId);
    m_m_pti = m_pti;
    if ( !m_pti || (m_rpdesk = m_pti->rpdesk) == 0i64 )
    {
      status = 0xC0000008;
      UserSetLastError(0x57);
      goto LABEL_41;
    }
    m_tagWnd = m_rpdesk->pDeskInfo->spwnd->spwndChild;
}
else
{
    m_m_pti = 0i64;
}
if ( !m_hDesktop )
{
    m_p_desk_top = 0i64;
    Object = 0i64;
    goto LABEL_20;
}
LOBYTE(v14) = 1;
if ( (int)ValidateHdesk((void *)m_hDesktop, v14, 1i64, &Object) < 0 )
{
    status = 0xC0000008;
    goto LABEL_41;
}
v32 = 0;
v33 = 0;
m_p_desk_top = (tagDESKTOP *)Object;
v31 = (tagDESKTOP *)Object;
v29 = 1;
LODWORD(v21) = PsGetCurrentProcess();
v30 = v21;
status = MapDesktop(&v29);
if ( status >= 0 )
{
    m_tagWnd = m_p_desk_top->pDeskInfo->spwnd->spwndChild;
LABEL_20:
    if ( m_tagWnd )
    {
      if ( m_bChildren )
      {
      flags |= 1u;
      m_tagWnd = m_tagWnd->spwndChild;
      }
    }
    else if ( !m_p_desk_top )
    {
      m_top_wnd = (tagWND *)GetThreadDesktopWindow((__int64)m_m_pti);// /*0x060*/   struct _tagWND* spwndChild;      
      if ( !m_top_wnd )
      {
      status = 0xC0000008;
      UserSetLastError(0x57);
      goto LABEL_41;
      }
      m_tagWnd = m_top_wnd->spwndChild;         // /*0x060*/   struct _tagWND* spwndChild;      
    }
    m_pBwl = BuildHwndList(m_tagWnd, flags, m_m_pti);
    m_m_pBwl = m_pBwl;                        // _BWL 这个结构符号里找不到
   /*
                ROS 中2k xp中定义如下:
                typedef struct _BWL
                {
                   struct _BWL *pbwlNext;
                   HWND      *phwndNext;
                   HWND      *phwndMax;
                   PTHREADINFOptiOwner;
                   HWND         rghwnd;
                } BWL, *PBWL;
      */
    if ( m_pBwl )
    {
      m_max_hwnd = (unsigned __int64)((*(_QWORD *)(m_pBwl + 8) - m_pBwl - 0x20) >> 3) + 1;
      m_max_num_user = MaxNum_user;
      if ( MaxNum_user > 0x1FFFFFFF )
      ExRaiseAccessViolation();
      ProbeForWrite(pWnd_User, 8 * m_max_num_user, 4u);
      m_p_buff_size_user = pBuffSize_User;
      m_m_p_buff_size_user = pBuffSize_User;
      if ( pBuffSize_User >= (unsigned __int64)W32UserProbeAddress )
      m_m_p_buff_size_user = (unsigned __int64)W32UserProbeAddress;
      *(_DWORD *)m_m_p_buff_size_user = *(_DWORD *)m_m_p_buff_size_user;
      if ( m_max_hwnd > (unsigned int)m_max_num_user )
      {
      status = 0xC0000023;
      }
      else
      {
      memmove(pWnd_User, (const void *)(m_m_pBwl + 0x20), 8i64 * m_max_hwnd);
      status = 0;
      }
      *(_DWORD *)m_p_buff_size_user = m_max_hwnd;
    }
    else
    {
      status = 0xC0000008;
      UserSetLastError(8);
    }
    goto LABEL_37;
}
UserSetLastError(6);
LABEL_37:
if ( m_m_pBwl )
    FreeHwndList(m_m_pBwl);
if ( m_p_desk_top )
    ObfDereferenceObject(m_p_desk_top);
LABEL_41:
UserSessionSwitchLeaveCrit();
return (unsigned int)status;
}可以看到 最后两个参数必须是R3的地址

否则返回0xC0000008错误,还有一点是如果这个线程的win32Thread是NULL的话也会返回0xC0000008错误(在控制台程序中出现)

修改后的代码,很明显可以知道如果dwThreadId是NULL的话就是枚举所有HWND




以下代码在win7 x64下测试通过

代码没有查询窗口的进程是谁

要查询的话只要调用

NtUserQueryWindow 即可得到

例如NtUserQueryWindow(hWnd,0);

R0:#include <ntddk.h>

#define DEVICE_NAME L"\\device\\DjWow"
#define LINK_NAME L"\\dosdevices\\DjWow" //\\??\\xxxx


#define IOCTRL_BASE 0x800
   
#define IOCTL_CODE(i) \
                CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTRL_BASE+i, METHOD_BUFFERED,FILE_ANY_ACCESS)
   
#define CTL_HELLO                IOCTL_CODE(0)
#define CTL_ULONG                IOCTL_CODE(1)
#define CTL_WCHAR                IOCTL_CODE(2)
#define CTL_CALLLIST        IOCTL_CODE(3)

VOID testGetWndList(unsigned int ThreadId,PVOID OutputBuffer,ULONG BufferSize,PVOID Outbuflenbuf);

typedef NTSTATUS (__fastcall *PFN_NTUSERBULIDHWNDLIST)(
                                                                                                        __int64 hDesktop,
                                                                                                        __int64 hWndParent,
                                                                                                        BOOLEAN bChildren,
                                                                                                        unsigned int dwThreadId,
                                                                                                        unsigned int lParam,
                                                                                                        OUT PVOID pWnd,
                                                                                                        OUT PVOID pBufSize);
//硬编码了
PFN_NTUSERBULIDHWNDLIST g_NtUserBuildHwndList = (PFN_NTUSERBULIDHWNDLIST)0xfffff96000084630;


NTSTATUS DispatchCommon(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
        pIrp->IoStatus.Status = STATUS_SUCCESS;
        pIrp->IoStatus.Information = 0;

        UNREFERENCED_PARAMETER(pDeviceObject);

        IoCompleteRequest(pIrp, IO_NO_INCREMENT);

        return STATUS_SUCCESS;
}


NTSTATUS DispatchCreate(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
        pIrp->IoStatus.Status = STATUS_SUCCESS;
        pIrp->IoStatus.Information = 0;

        UNREFERENCED_PARAMETER(pDeviceObject);

        IoCompleteRequest(pIrp, IO_NO_INCREMENT);

        return STATUS_SUCCESS;
}


NTSTATUS DispatchClose(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
        pIrp->IoStatus.Status = STATUS_SUCCESS;
        pIrp->IoStatus.Information = 0;

        UNREFERENCED_PARAMETER(pDeviceObject);

        IoCompleteRequest(pIrp, IO_NO_INCREMENT);

        return STATUS_SUCCESS;
}


NTSTATUS DispatchClear(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
        pIrp->IoStatus.Status = STATUS_SUCCESS;
        pIrp->IoStatus.Information = 0;

        UNREFERENCED_PARAMETER(pDeviceObject);

        IoCompleteRequest(pIrp, IO_NO_INCREMENT);

        return STATUS_SUCCESS;
}


NTSTATUS DispatchRead(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
        PVOID pBuff = 0;
        ULONG pBuffLen = 0;
        ULONG pStackLen = 0;
        PIO_STACK_LOCATION pStack = 0;
        ULONG uMin = 0;

        UNREFERENCED_PARAMETER(pDeviceObject);

        pBuff = pIrp->AssociatedIrp.SystemBuffer;

        pStack = IoGetCurrentIrpStackLocation(pIrp);

        pStackLen = pStack->Parameters.Read.Length;

        pBuffLen = (wcslen(L"hello world") + 1) * sizeof(WCHAR);

        uMin = pBuffLen < pStackLen ? pBuffLen:pStackLen;

        RtlCopyMemory(pBuff, L"hello wolrd", uMin);

        pIrp->IoStatus.Status = STATUS_SUCCESS;
        pIrp->IoStatus.Information = uMin;

        IoCompleteRequest(pIrp, IO_NO_INCREMENT);

        return STATUS_SUCCESS;
}


NTSTATUS DispatchWrite(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
        PVOID pWriteBuff = 0;
        PVOID pBuff = 0;
        ULONG uWriteBuffLen = 0;
        PIO_STACK_LOCATION pStack = 0;

        UNREFERENCED_PARAMETER(pDeviceObject);

        pWriteBuff = pIrp->AssociatedIrp.SystemBuffer;

        pStack = IoGetCurrentIrpStackLocation(pIrp);

        uWriteBuffLen = pStack->Parameters.Write.Length;

        pBuff = ExAllocatePoolWithTag(PagedPool, uWriteBuffLen,'TSET');

        if(pBuff == NULL)
        {
                pIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
                pIrp->IoStatus.Information = 0;
                return STATUS_INSUFFICIENT_RESOURCES;
        }

        RtlZeroMemory(pBuff, uWriteBuffLen);

        RtlCopyMemory(pBuff,pWriteBuff, uWriteBuffLen);

        ExFreePool(pBuff);
        pBuff = 0;

        IoCompleteRequest(pIrp, IO_NO_INCREMENT);

        pIrp->IoStatus.Status = STATUS_SUCCESS;
        pIrp->IoStatus.Information = uWriteBuffLen;

        return STATUS_SUCCESS;
}


NTSTATUS DispatchIoctrl(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
        PIO_STACK_LOCATION pStack = 0;
        PVOID pBuff = 0;
        ULONG uOutLen = 0;
        ULONG uInLen = 0;
        ULONG uCtlCode = 0;
        ULONG_PTR *Context;

        PVOID64 outbuflenbuf;
        PVOID64 OutBuf;
        unsigned int ThreadId;

        UNREFERENCED_PARAMETER(pDeviceObject);

        pStack = IoGetCurrentIrpStackLocation(pIrp);

        uOutLen = pStack->Parameters.DeviceIoControl.OutputBufferLength;
        uInLen = pStack->Parameters.DeviceIoControl.InputBufferLength;

        pBuff = pIrp->AssociatedIrp.SystemBuffer;

        uCtlCode = pStack->Parameters.DeviceIoControl.IoControlCode;

        switch (uCtlCode)
        {
        case CTL_HELLO:
                DbgPrint("hello!\n");
                break;
        case CTL_ULONG:
                {
                        DbgPrint("pid:%d\n",*(ULONG*)pBuff);
                        RtlCopyMemory(pBuff,L"ok",uOutLen);
                        break;
                }
        case CTL_WCHAR:
                        DbgPrint("%ws",pBuff);
                        break;
        case CTL_CALLLIST:
                {
                        Context = (ULONG_PTR*)pBuff;
                        ThreadId = (unsigned int)Context;
                        OutBuf = (PVOID)Context;
                        uOutLen = Context;
                        outbuflenbuf = (PVOID)Context;
                        DbgPrint("Thread Id is %dOutpubBuffer=0x%08LLXBufLen=0x%X outbuflenbuf = 0x%08LLX\n",ThreadId,OutBuf,uOutLen,outbuflenbuf);
                        testGetWndList(ThreadId,OutBuf,uOutLen,outbuflenbuf);
                        break;
                }
        default:
                DbgPrint("UNKNUW CTLCODE!\n");
                break;
        }

        pIrp->IoStatus.Status = STATUS_SUCCESS;
        pIrp->IoStatus.Information = uOutLen;

        IoCompleteRequest(pIrp, IO_NO_INCREMENT);

        return STATUS_SUCCESS;
}

/*
参考:
http://bbs.pediy.com/showthread.php?t=100983
http://www.mengwuji.net/thread-99-1-1.html
http://bbs.pediy.com/showthread.php?t=131950
I:\IDA分析\win7 x64\win32k.sys / win32k.i64
*/
VOID testGetWndList(unsigned int ThreadId,PVOID64 OutputBuffer,ULONG BufferSize,PVOID64 Outbuflenbuf)
{
        //ULONG_PTR      *HwnBuf=NULL;
        ULONG   BufSize=0;
        ULONG   MaxNum = 0x1000;
        NTSTATUS status;
        int i = 0;
        __int64 hwnd = 0;
        __int64 *hwndtable = NULL;
       
        BufSize = BufferSize;
        MaxNum = BufferSize/sizeof(ULONG_PTR);
        //HwnBuf = (ULONG_PTR*)OutputBuffer;
        DbgPrint("MAXNUM:0x%x",MaxNum);
        DbgPrint("准备调用NtUserBuildHwndList...\n");
       
       
        status = g_NtUserBuildHwndList(0,
                                                                0,
                                                                FALSE,
                                                                NULL,//ThreadId,
                                                                MaxNum,//MaxNum
                                                                OutputBuffer,
                                                                Outbuflenbuf);
       
        hwndtable = (__int64*)OutputBuffer;
        DbgPrint("%d\n",*(ULONG_PTR*)Outbuflenbuf);

        /*
       0 d fffff960`00084862 e 1 0001 (0001) win32k!NtUserBuildHwndList+0x232
       1 e fffff960`000847fb e 1 0001 (0001) win32k!NtUserBuildHwndList+0x1cb
       3 e fffff960`00084804 e 1 0001 (0001) win32k!NtUserBuildHwndList+0x1d4
        */
        for (i = 0; i < *(ULONG_PTR*)Outbuflenbuf; i++)
        {
                __try
                {
                        hwnd = hwndtable;
                        DbgPrint("0x%llx\n",hwnd);
                }
                __except(1)
                {
                        DbgPrint("except!\n");
                }
        }
        DbgPrint("count:%d\n",i);
        DbgPrint("NtUserBuildHwndList Returned status = 0x%08X \n",status);       
}

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
        UNICODE_STRING strLinkName ={0};

        RtlInitUnicodeString(&strLinkName,LINK_NAME);

        IoDeleteSymbolicLink(&strLinkName);

        if(pDriverObject->DeviceObject)
        {
                IoDeleteDevice(pDriverObject->DeviceObject);
        }
       
        DbgPrint("DriverUnload");

        return;
}


NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
        UNICODE_STRING strDeviceName = {0};
        UNICODE_STRING strLinkName = {0};
        NTSTATUS status = 0;
        PDEVICE_OBJECT pDeviceObject = 0;
        ULONG i = 0;

        DbgPrint("DriverEntry!\n");

        UNREFERENCED_PARAMETER(pRegPath);

        RtlInitUnicodeString(&strDeviceName, DEVICE_NAME);
        RtlInitUnicodeString(&strLinkName, LINK_NAME);

        status = IoCreateDevice(pDriverObject, 0, &strDeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);

        if(!NT_SUCCESS(status))
        {
                DbgPrint("CretaDevice Faild:0x%x\n",status);
                return status;
        }

        pDeviceObject->Flags |= DO_BUFFERED_IO;

        status = IoCreateSymbolicLink(&strLinkName,&strDeviceName);

        if(!NT_SUCCESS(status))
        {
                IoDeleteDevice(pDeviceObject);
                DbgPrint("IoCreateSymbolicdLink Faild:0x%x\n",status);
                return status;
        }

        for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION + 1; i++)
        {
                pDriverObject->MajorFunction = DispatchCommon;
        }

        pDriverObject->MajorFunction = DispatchCreate;
        pDriverObject->MajorFunction = DispatchRead;
        pDriverObject->MajorFunction = DispatchWrite;
        pDriverObject->MajorFunction = DispatchIoctrl;
        pDriverObject->MajorFunction = DispatchClose;
        pDriverObject->MajorFunction = DispatchClear;

        pDriverObject->DriverUnload = DriverUnload;

        return STATUS_SUCCESS;

}


R3(也需要是x64):

int CMFC_EXEDlg::SendDeviceIoControl(void)
{
        DWORD byteRetned=0;
        DWORD retValue;
        char buffer = {0};
        char wndbuffer = {0};
        HWND* tmp = 0;
       
        ULONG_PTR IoContext={0};//ThreadId,Outputbuffer,outbuflen
        DWORD dwThreadId = GetCurrentThreadId();
        CString str;
        /*sprintf(buffer,"Current TheadId = %d\n",dwThreadId);
        OutputDebugStringA(buffer);*/
        //printf("Current TheadId = %d\n",dwThreadId);
        str.Format(L"%d",dwThreadId);
        m_edit_string = str;
        UpdateData(FALSE);
        /*sprintf(buffer,"WndList Buffer = 0x%08X\n",wndbuffer);
        OutputDebugStringA(buffer);*/
        //printf("WndList Buffer = 0x%08X\n",wndbuffer);
        str.Format(L"0x%08x\r\n",wndbuffer);
        m_edit_string += str;

        HANDLE hDevice = CreateFileA( "\\\\.\\DjWow",
                GENERIC_READ | GENERIC_WRITE,
                0,
                NULL,
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                NULL
                );
        if ( hDevice == ((HANDLE)0xFFFFFFFF) )
    {
                OutputDebugStringA("Open SymbolLink Failed!\n");
                return 0;
        }
        //填充buffer
        IoContext = dwThreadId;
        IoContext = (ULONG_PTR)wndbuffer;
        IoContext = 0x1000;
        IoContext = (ULONG_PTR)&IoContext;

        retValue=DeviceIoControl(hDevice,
                CTL_CALLLIST,
                IoContext,
                sizeof(ULONG_PTR)*4,
                wndbuffer,
                0x1000,
                &byteRetned,
                NULL);
        CloseHandle(hDevice);
        /*sprintf(buffer,"return value=%d\n",retValue);
        OutputDebugStringA(buffer);*/
        //printf("return value=%d\n",retValue);
        m_edit_string += "\r\nok!";
        //str.Format(L"%s",wndbuffer);
        //m_edit_string += L"\r\n" + str;
        tmp = (HWND*)wndbuffer;
        int i = 0;
        while (i < 100)
        {
                GetWindowTextA(tmp,buffer,MAX_PATH-1);
                str.Format(L"%s",buffer);
                m_edit_string += L"\r\n" + str;
                UpdateData(FALSE);
                i++;
        }
        UpdateData(FALSE);
        return 1;
}
为什么不用EnumWindows呢?

我就闲着无聊.....




   





页: [1]
查看完整版本: 使用NtUserBuildHwndList遍历窗口_win7x64