• setwindowhook内部原理


    setwindowhook  ->  intsetwindowhookex  ->  NtUserSetWindowHookEx(工作在win32k.sys子系统层)

    Hook = UserCreateObject(gHandleTable, NULL, &Handle, otHook, sizeof(HOOK));

    同属于user32的用户对象的读写接口

    UserGetWindowObject   获取window对象 

    UserCreateObject  

    UserGetObject

    以下是handle和 用户对象地址的映射关系

    handle是 用户对象在用户全局对象列表中的序号的算法结果(有一个专门的算法可以使用), 有两个函数专门处理 index和对象地址之间的映射

    PUSER_HANDLE_ENTRY handle_to_entry(PUSER_HANDLE_TABLE ht, HANDLE handle )
    {
       unsigned short generation;
       int index = (((unsigned int)handle & 0xffff) - FIRST_USER_HANDLE) >> 1;
       if (index < 0 || index >= ht->nb_handles)
          return NULL;
       if (!ht->handles[index].type)
          return NULL;
       generation = (unsigned int)handle >> 16;
       if (generation == ht->handles[index].generation || !generation || generation == 0xffff)
          return &ht->handles[index];
       return NULL;
    }

    用户对象的原型

    typedef struct _USER_HANDLE_ENTRY
    {
        void          *ptr;          /* pointer to object */
        union
        {
            PVOID pi;
            PTHREADINFO pti;          // pointer to Win32ThreadInfo
            PPROCESSINFO ppi;         // pointer to W32ProcessInfo
        };
        unsigned char  type;         /* object type (0 if free) */
        unsigned char  flags;
        unsigned short generation;   /* generation counter */
    } USER_HANDLE_ENTRY, * PUSER_HANDLE_ENTRY;

    win32子系统介绍

    里面包含了所有用户对象的创建, hook机制的核心实现,
    线程hook和系统hook

    线程hook不允许

     WH_JOURNALRECORD
     WH_JOURNALPLAYBACK ||
     WH_KEYBOARD_LL ||
     WH_MOUSE_LL ||
     WH_SYSMSGFILTER)

    用户空间的用户对象有以下定义

    typedef enum _USER_OBJECT_TYPE
    {
      otFree = 0,
      otWindow,
      otMenu,
      otCursorIcon,
      otSMWP,
      otHook,      //hook钩子
      otClipBoardData,
      otCallProc,
      otAccel,
      otDDEaccess,
      otDDEconv,
      otDDExact,
      otMonitor,
      otKBDlayout,
      otKBDfile,
      otEvent,
      otTimer,
      otInputContext,
      otHidData,
      otDeviceInfo,
      otTouchInput,
      otGestureInfo
    } USER_OBJECT_TYPE;

    桌面窗口的内部结构

    typedef struct _DESKTOP
    {
        PDESKTOPINFO pDeskInfo;
        LIST_ENTRY ListEntry;
        /* Pointer to the associated window station. */
        struct _WINSTATION_OBJECT *rpwinstaParent;
        PWND spwndForeground;
        PWND spwndTray;
        PWND spwndMessage;
        PWND spwndTooltip;
        PSECTION_OBJECT hsectionDesktop;
        PWIN32HEAP pheapDesktop;
        ULONG_PTR ulHeapSize;
        LIST_ENTRY PtiList;
        /* use for tracking mouse moves. */
        PWND spwndTrack;
        DWORD htEx;
        RECT rcMouseHover;
        DWORD dwMouseHoverTime;

        /* ReactOS */
        /* Pointer to the active queue. */
        PVOID ActiveMessageQueue;
        /* Handle of the desktop window. */
        HANDLE DesktopWindow;
        /* Thread blocking input */
        PVOID BlockInputThread;
        LIST_ENTRY ShellHookWindows;
    } DESKTOP, *PDESKTOP;

    用户对象内部分配 句柄是采用递增的方式, 真实的情况如下:

    __inline static PUSER_HANDLE_ENTRY alloc_user_entry(PUSER_HANDLE_TABLE ht)
    {
       PUSER_HANDLE_ENTRY entry;

       DPRINT("handles used %i\n",gpsi->cHandleEntries);

       if (ht->freelist)
       {
          entry = ht->freelist;
          ht->freelist = entry->ptr;

          gpsi->cHandleEntries++;
          return entry;
       }

       if (ht->nb_handles >= ht->allocated_handles)  /* need to grow the array */
       {
    /**/
          int i, iFree = 0, iWindow = 0, iMenu = 0, iCursorIcon = 0,
              iHook = 0, iCallProc = 0, iAccel = 0, iMonitor = 0, iTimer = 0;
     /**/
          DPRINT1("Out of user handles! Used -> %i, NM_Handle -> %d\n", gpsi->cHandleEntries, ht->nb_handles);
    //#if 0
          for(i = 0; i < ht->nb_handles; i++)
          {
             switch (ht->handles[i].type)
             {
               case otFree: // Should be zero.
                iFree++;
                break;
               case otWindow:
                iWindow++;
                break;
               case otMenu:
                iMenu++;
                break;
               case otCursorIcon:
                iCursorIcon++;
                break;
               case otHook:
                iHook++;
                break;
               case otCallProc:
                iCallProc++;
                break;
               case otAccel:
                iAccel++;
                break;
               case otMonitor:
                iMonitor++;
                break;
               case otTimer:
                iTimer++;
                break;
               default:
                break;
             }
          }
          DPRINT1("Handle Count by Type:\n Free = %d Window = %d Menu = %d CursorIcon = %d Hook = %d\n CallProc = %d Accel = %d Monitor = %d Timer = %d\n",
          iFree, iWindow, iMenu, iCursorIcon, iHook, iCallProc, iAccel, iMonitor, iTimer );
    //#endif
          return NULL;
    #if 0
          PUSER_HANDLE_ENTRY new_handles;
          /* grow array by 50% (but at minimum 32 entries) */
          int growth = max( 32, ht->allocated_handles / 2 );
          int new_size = min( ht->allocated_handles + growth, (LAST_USER_HANDLE-FIRST_USER_HANDLE+1) >> 1 );
          if (new_size <= ht->allocated_handles)
             return NULL;
          if (!(new_handles = UserHeapReAlloc( ht->handles, new_size * sizeof(*ht->handles) )))
             return NULL;
          ht->handles = new_handles;
          ht->allocated_handles = new_size;
    #endif
       }

       entry = &ht->handles[ht->nb_handles++];

       entry->generation = 1;

       gpsi->cHandleEntries++;

       return entry;
    }

    //  windows的默认处理函数  里面的钩子是怎么弄的呢, 请看

    callwindowproc

    检查这连个全局变量 ghmodUserApiHook   gfUserApiHook 的指, 如果不为空,则有hook

    callwindowproc实际上是一个分发器, 分发器分发给谁了呢, 有以下朋友们来一一做掉

    USERAPIHOOK guah =
    {
      sizeof(USERAPIHOOK),
      (WNDPROC)RealDefWindowProcA,
      (WNDPROC)RealDefWindowProcW,
      {NULL, 0},
      (FARPROC)RealGetScrollInfo,
      (FARPROC)RealSetScrollInfo,
      (FARPROC)NtUserEnableScrollBar,
      (FARPROC)RealAdjustWindowRectEx,
      (FARPROC)NtUserSetWindowRgn,
      (WNDPROC_OWP)DefaultOWP,
      (WNDPROC_OWP)DefaultOWP,
      {NULL, 0},
      (WNDPROC_OWP)DefaultOWP,
      (WNDPROC_OWP)DefaultOWP,
      {NULL, 0},
      (FARPROC)RealGetSystemMetrics,
      (FARPROC)RealSystemParametersInfoA,
      (FARPROC)RealSystemParametersInfoW,
      (FARPROC)ForceResetUserApiHook,
      (FARPROC)RealDrawFrameControl,
      (FARPROC)NtUserDrawCaption,
      (FARPROC)RealMDIRedrawFrame,
      (FARPROC)GetRealWindowOwner,
    };

    RealDefWindowProcA这个函数里面我们发现了spy++的实现原理, 是通过对消息的过滤处理,记录了下来  实现在user32.dll里面

  • 相关阅读:
    Params参数的应用
    用反射动态创建委托
    Javascript中的Array的运用
    四个JS代码与jquery架构简单运用
    base 基本用法转载自(MSDN)
    Microsoft AJAX Library 新特性简单代码
    典型的委托的不同写法(转载)
    创建反射实例|反射过滤|反射搜索
    【软工】第1次个人作业
    【软工】第0次个人作业
  • 原文地址:https://www.cnblogs.com/maifengqiang/p/2127934.html
Copyright © 2020-2023  润新知