欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]XP下对GetWindowLong跨进程获取窗口例程浅析

[原创]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


目的已经达到,我也就不跟下去了,而且我能力有限

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功