[原创]XP下对GetWindowLong跨进程获取窗口例程浅析
看了论坛上某某人写的GetWindowLong获取WndProc,想到GetWindowLong既然没进内核,那我们就可以修改自己进程内User32.dll的代码,以达到跨进程获取窗口例程的目的
该方法我在xp3下测试有效,win7没有测试,相信差别不大,仅以此抛砖引玉,有不对的地方大家请指出
结合ReactOS源码,我们先看一下GetWindowLongW实现
GetWindowLongW代码
LONG
WINAPI
GetWindowLongW(HWND hWnd, int nIndex)
{
PWND Wnd;
Wnd = ValidateHwnd(hWnd);//不知道是干什么的,只知道返回一个指向ring3 WND结构的指针
if (Wnd == NULL)
return 0;
if (nIndex >= 0)
{
if ((DWORD)nIndex + sizeof(LONG) > Wnd->cbwndExtra)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
return *((LONG *)((PCHAR)(Wnd + 1) + nIndex));
}
else
{
switch (nIndex)
{
case GWL_EXSTYLE:
return Wnd->ExStyle;
case GWL_STYLE:
return Wnd->style;
case GWL_HINSTANCE:
return (LONG)Wnd->hModule;
case GWL_ID:
return Wnd->IDMenu;
case GWL_USERDATA:
return Wnd->dwUserData;
case GWL_HWNDPARENT:
{
HWND parent = GetAncestor( hWnd, GA_PARENT );
if (parent == GetDesktopWindow()) parent = GetWindow( hWnd, GW_OWNER );
return (LONG)parent;
}
case GWL_WNDPROC:
if (!TestWindowProcess(Wnd))//判断是否是本进程,只要TestWindowProcess返回TRUE的话,那么跨进程窗口例程也能获取
{
SetLastError(ERROR_ACCESS_DENIED);
return 0;
}
return IntGetWndProc(Wnd, FALSE);
default:
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
}
}
然后我来看一下WND结构,它里面包含了很多有用的信息
typedef struct _WND
{
THRDESKHEAD head;
DWORD state;
DWORD state2;
/* Extended style. */
DWORD ExStyle;//扩展样式
/* Style. */
DWORD style;//样式
/* Handle of the module that created the window. */
HINSTANCE hModule;//窗口实例句柄
DWORD fnid;//应该是窗口例程的类型,比喻编辑框,按钮
struct _WND *spwndNext;
struct _WND *spwndPrev;
struct _WND *spwndParent;
struct _WND *spwndChild;
struct _WND *spwndOwner;
RECT rcWindow;//窗口矩形,GetWindowRect
RECT rcClient;//窗口客户矩形,GetClientRect
WNDPROC lpfnWndProc;//是窗口函数地址吗?
/* Pointer to the window class. */
PCLS pcls;//指向一个CLS结构,包含类信息
HRGN hrgnUpdate;
/* Property list head.*/
LIST_ENTRY PropListHead;
ULONG PropListItems;
/* Scrollbar info */
PSBINFO pSBInfo;
/* system menu handle. */
HMENU SystemMenu;//系统菜单句柄
//PMENU spmenuSys;
/* Window menu handle or window id */
UINT IDMenu; // Use spmenu
//PMENU spmenu;
HRGN hrgnClip;
HRGN hrgnNewFrame;
/* Window name. */
UNICODE_STRING strName;//窗口标题,GetWindowText
/* Size of the extra data associated with the window. */
ULONG cbwndExtra;
HWND hWndLastActive;
struct _WND *spwndLastActive;
//HIMC hImc; // Input context associated with this window.
LONG dwUserData;
//PACTIVATION_CONTEXT pActCtx;
//PD3DMATRIX pTransForm;
struct _WND *spwndClipboardListener;
DWORD ExStyle2;
struct
{
RECT NormalRect;
POINT IconPos;
POINT MaxPos;
} InternalPos;
UINT Unicode : 1; // !(WNDS_ANSICREATOR|WNDS_ANSIWINDOWPROC) ?
/* Indicates whether the window is derived from a system class */
UINT InternalPosInitialized : 1;
UINT HideFocus : 1; // WS_EX_UISTATEFOCUSRECTHIDDEN ?
UINT HideAccel : 1; // WS_EX_UISTATEKBACCELHIDDEN ?
} WND, *PWND;
然后看一下CLS结构
typedef struct _CLS
{
struct _CLS *pclsNext;
RTL_ATOM atomClassName;
ATOM atomNVClassName;
DWORD fnid;
struct _DESKTOP *rpdeskParent;
PVOID pdce;
DWORD CSF_flags;
PSTR lpszClientAnsiMenuName; // For client use
PWSTR lpszClientUnicodeMenuName; // " " "
PCALLPROCDATA spcpdFirst;
struct _CLS *pclsBase;
struct _CLS *pclsClone;
ULONG cWndReferenceCount;
UINT style;//窗口样式
WNDPROC lpfnWndProc;;//是窗口函数地址吗?
INT cbclsExtra;
INT cbwndExtra;
HINSTANCE hModule;//窗口实例句柄
HANDLE hIcon; /* FIXME - Use pointer! */
//PCURSOR spicn;
HANDLE hCursor; /* FIXME - Use pointer! */
//PCURSOR spcur;
HBRUSH hbrBackground;//背景颜色
PWSTR lpszMenuName; // kernel use
PSTR lpszAnsiClassName; // 窗口类名
HANDLE hIconSm; /* FIXME - Use pointer! */
//PCURSOR spicnSm;
UINT Unicode : 1; // !CSF_ANSIPROC
UINT Global : 1; // CS_GLOBALCLASS or CSF_SERVERSIDEPROC
UINT MenuNameIsString : 1;
UINT NotUsed : 29;
} CLS, *PCLS;
再来看一下TestWindowProcess的实现
BOOL
FASTCALL
TestWindowProcess(PWND Wnd)
{
if (Wnd->head.pti == (PTHREADINFO)NtCurrentTeb()->Win32ThreadInfo)//用线程Teb里面的Win32ThreadInfo比较WND结构里面pti是否相同,一样的话说明是当前线程的窗口
return TRUE;
else
return (NtUserQueryWindow(Wnd->head.h, QUERY_WINDOW_UNIQUE_PROCESS_ID) ==
(DWORD)NtCurrentTeb()->ClientId.UniqueProcess );//进程PID是否一样,判断是否本进程的窗口
}
用OD反汇编GetWindowLongW
77D188A6 > 6A 08 PUSH 8 77D188A8 68 E088D177 PUSH USER32.77D188E0 77D188AD E8 0EFDFFFF CALL USER32.77D185C0 77D188B2 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+8] 77D188B5 E8 26FCFFFF CALL USER32.77D184E0 ; ValidateHwnd 77D188BA 85C0 TEST EAX,EAX 77D188BC 0F84 51490100 JE USER32.77D2D213 77D188C2 8365 FC 00 AND DWORD PTR SS:[EBP-4],0 77D188C6 6A 00 PUSH 0 77D188C8 FF75 0C PUSH DWORD PTR SS:[EBP+C] 77D188CB 50 PUSH EAX 77D188CC E8 8FFFFFFF CALL USER32.77D18860 ;F7跟进 77D188D1 834D FC FF OR DWORD PTR SS:[EBP-4],FFFFFFFF 77D188D5 E8 26FDFFFF CALL USER32.77D18600 77D188DA C2 0800 RETN 8
跟进77D188CC的调用后
77D18860 8BFF MOV EDI,EDI 77D18862 55 PUSH EBP 77D18863 8BEC MOV EBP,ESP 77D18865 8B45 0C MOV EAX,DWORD PTR SS:[EBP+C] 77D18868 56 PUSH ESI 77D18869 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8] 77D1886C 0FB74E 2A MOVZX ECX,WORD PTR DS:[ESI+2A] 77D18870 81E1 FF3FFFFF AND ECX,FFFF3FFF 77D18876 57 PUSH EDI 77D18877 0F85 E93E0100 JNZ USER32.77D2C766 77D1887D 85C0 TEST EAX,EAX 77D1887F 0F8C 97020000 JL USER32.77D18B1C ; 偏移量低于0,跟进 77D18885 8D48 04 LEA ECX,DWORD PTR DS:[EAX+4] 77D18888 3B8E 8C000000 CMP ECX,DWORD PTR DS:[ESI+8C] 77D1888E 0F87 FC720100 JA USER32.77D2FB90 77D18894 8B8406 A4000000 MOV EAX,DWORD PTR DS:[ESI+EAX+A4] 77D1889B 5F POP EDI 77D1889C 5E POP ESI 77D1889D 5D POP EBP 77D1889E C2 0C00 RETN 0C
跟进77D1887F的跳转来到下面
77D18B1C FF75 10 PUSH DWORD PTR SS:[EBP+10] 77D18B1F 50 PUSH EAX ; 偏移量 77D18B20 56 PUSH ESI ; 指向WND结构 77D18B21 E8 0A000000 CALL USER32.77D18B30 ; 跟进调用 77D18B26 ^ E9 70FDFFFF JMP USER32.77D1889B
跟进77D18B21的调用来到下面
77D18B30 8BFF MOV EDI,EDI 77D18B32 55 PUSH EBP 77D18B33 8BEC MOV EBP,ESP 77D18B35 8B45 0C MOV EAX,DWORD PTR SS:[EBP+C] ; 取偏移量 77D18B38 83F8 F8 CMP EAX,-8 77D18B3B 56 PUSH ESI 77D18B3C 57 PUSH EDI 77D18B3D 0F8F 0B120100 JG USER32.77D29D4E ; 高于-8,跟进跳转 77D18B43 0F84 79440100 JE USER32.77D2CFC2 77D18B49 83F8 EB CMP EAX,-15 77D18B4C 0F84 52010000 JE USER32.77D18CA4 77D18B52 83F8 EC CMP EAX,-14 77D18B55 0F84 97090100 JE USER32.77D294F2 77D18B5B 83F8 F0 CMP EAX,-10 77D18B5E 0F85 45250100 JNZ USER32.77D2B0A9 77D18B64 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] 77D18B67 F640 1D 08 TEST BYTE PTR DS:[EAX+1D],8 77D18B6B 8B40 20 MOV EAX,DWORD PTR DS:[EAX+20] 77D18B6E 74 05 JE SHORT USER32.77D18B75 77D18B70 0D 00000010 OR EAX,10000000 77D18B75 5F POP EDI 77D18B76 5E POP ESI 77D18B77 5D POP EBP 77D18B78 C2 0C00 RETN 0C
跟进77D18B3D的跳转来到下面
77D29D4E 83F8 FA CMP EAX,-6 77D29D51 74 1D JE SHORT USER32.77D29D70 77D29D53 83F8 FC CMP EAX,-4 77D29D56 0F84 422F0000 JE USER32.77D2CC9E ; 窗口例程地址,跟进 77D29D5C 83F8 FF CMP EAX,-1 77D29D5F 0F85 396E0100 JNZ USER32.77D40B9E 77D29D65 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] 77D29D68 83C0 14 ADD EAX,14 77D29D6B ^ E9 05EEFEFF JMP USER32.77D18B75 77D29D70 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] 77D29D73 8B40 24 MOV EAX,DWORD PTR DS:[EAX+24] 77D29D76 ^ E9 FAEDFEFF JMP USER32.77D18B75 77D29D7B E8 D5E8FEFF CALL USER32.77D18655 77D29D80 3B43 08 CMP EAX,DWORD PTR DS:[EBX+8] 77D29D83 0F85 F33C0100 JNZ USER32.77D3DA7C 77D29D89 837D 0C 00 CMP DWORD PTR SS:[EBP+C],0 77D29D8D 0F85 69770000 JNZ USER32.77D314FC 77D29D93 57 PUSH EDI 77D29D94 FF76 04 PUSH DWORD PTR DS:[ESI+4] 77D29D97 E8 C8FAFFFF CALL USER32.77D29864 77D29D9C A1 8010D777 MOV EAX,DWORD PTR DS:[77D71080] 77D29DA1 F640 02 04 TEST BYTE PTR DS:[EAX+2],4 77D29DA5 ^ 0F84 04ECFEFF JE USER32.77D189AF 77D29DAB E9 596A0100 JMP USER32.77D40809 77D29DB0 3BF1 CMP ESI,ECX 77D29DB2 0F83 8C040000 JNB USER32.77D2A244 77D29DB8 E9 62040000 JMP USER32.77D2A21F 77D29DBD 81FE A1000000 CMP ESI,0A1 77D29DC3 0F82 8F040000 JB USER32.77D2A258 77D29DC9 E9 A5040000 JMP USER32.77D2A273 77D29DCE 3BF1 CMP ESI,ECX 77D29DD0 0F82 C9040000 JB USER32.77D2A29F 77D29DD6 E9 C9040000 JMP USER32.77D2A2A4
跟进77D29D56的调用来到下面
77D2CC9E 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8] ; 取WND结构指针 77D2CCA1 56 PUSH ESI 77D2CCA2 E8 70C1FFFF CALL USER32.77D28E17 ; TestWindowProcess,判断窗口是否是本进程的 77D2CCA7 85C0 TEST EAX,EAX 77D2CCA9 0F84 F63E0100 JE USER32.77D40BA5 ; 改这儿,把这句NOP掉,窗口例程就能获取到了 77D2CCAF F646 16 04 TEST BYTE PTR DS:[ESI+16],4 77D2CCB3 0F85 51320100 JNZ USER32.77D3FF0A 77D2CCB9 0FB746 2A MOVZX EAX,WORD PTR DS:[ESI+2A] 77D2CCBD 25 FF3FFFFF AND EAX,FFFF3FFF 77D2CCC2 3D A5020000 CMP EAX,2A5 77D2CCC7 0F84 F2980000 JE USER32.77D365BF
目的已经达到,我也就不跟下去了,而且我能力有限
