首页
社区
课程
招聘
[原创]XP下对GetWindowLong跨进程获取窗口例程浅析
发表于: 2013-1-7 12:05 14251

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

2013-1-7 12:05
14251

看了论坛上某某人写的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;
        }
    }
}

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;

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;
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是否一样,判断是否本进程的窗口
}
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

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 6
支持
分享
最新回复 (8)
雪    币: 154
活跃值: (91)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
2
我竟然没想到去看ROS的代码,跪了。。。

呃,话说那个WND结构体不是在本进程里面的么,我原来也想到改TEB来模拟其他进程,这样方便多了而且不需要一大堆针对系统的硬编码,可句柄的信息表指针和那个句柄指向的窗口例程函数地址也并不在我的进程内,而在其他进程的地址空间啊,GetWindowLong拿到WND结构体指针明显直接当本进程的地址空间操作了。。结果不是错误的结果就是拒绝访问啊。。。
所以那个TestWindowProcess明显是有必要的吧。。。
还有WND结构体明显在XP和WIN7上完全不同。
2013-1-7 18:41
0
雪    币: 778
活跃值: (208)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
3
呃,WND结构体大概是共享的,所有进程都能访问,我试过在xp成功获取地址,跟本进程获取的比较,没有区别,绝对没你说的错误或者拒绝访问
而且你要知道GetWindowLong能跨进程获取GWL_STYLE,GWL_EXSTYLE等,没进内核,也没读取进程内存
2013-1-7 19:43
0
雪    币: 119
活跃值: (313)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
嘿嘿 这东西好!
2013-1-7 20:53
0
雪    币: 2194
活跃值: (1001)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
  是这个TestWindowProcess
2013-1-10 08:37
0
雪    币: 107
活跃值: (404)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
学习...........
2013-1-10 22:49
0
雪    币: 1283
活跃值: (46)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
7
学习一下,ReactOS之前了解了一下,貌似还不错,比较接近老版本的windows
2013-1-11 23:01
0
雪    币: 656
活跃值: (448)
能力值: ( LV12,RANK:360 )
在线值:
发帖
回帖
粉丝
8
调试了一下,用下面这个方法可以获取取,xp sp3 和win7 64位下测试成功

Hwnd textequ <1202A2H> ;这里是目标窗口的HWND
iatCall GetWindowThreadProcessId,Hwnd,addr ProcessId
mov     eax, dword ptr fs:[18H]
mov	ecx,[eax+20H]
mov	myProcessId,ecx
mov	ecx,ProcessId
mov	[eax+20H],ecx
iatCall GetWindowLongA,Hwnd,GWL_WNDPROC
push	myProcessId
mov     ecx, dword ptr fs:[18H]
pop	[ecx+20H]	
push	esi
mov	esi,esp
iatCall wsprintfA,addr buff,"wndproc:%X",eax
mov	esp,esi
pop	esi
iatCall MessageBoxA,0,addr buff,"hi",0
iatCall ExitProcess,0
2013-1-15 23:29
0
雪    币: 1276
活跃值: (5139)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
9
谢谢,太强了。

楼上的汇编代码,边个高手帮转成C++ 或DELPHI 的代码
2013-1-17 19:17
0
游客
登录 | 注册 方可回帖
返回
//