使用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]