hookCCI函数先把正常的ClientCopyImage地址重新存入g_ppCCI中,然后调用SetWindowLongPtr函数,然后再调用g_originalCCI也就是ClientCopyImage函数,完成功能,这样就在正常执行ClientCopyImage函数之前先执行了SetWindowLongPtr函数。通过查找相关资料可知,SetWindowLongPtr是设置窗口相关数据、属性的函数,这里GWLP_WNDPROC这个功能索引(index)的作用是对窗口进行子类化(subclass)/去子类化(unsubclass),可以通过子类化,替换窗口的调用过程为自己的函数,来接管窗口的一些处理,也可以通过设置为DefWindowProc来去子类化,取消接管过程。这里面GetFirestThreadHWND是一个获得当前正在被创建的窗口句柄的一个技巧,因为现在CreateWindowEx正在被中断在内核过程中,仅仅通过用户模式的代码和CreateClassSmIcon的信息,是无法得知当前正在被创建的窗口对象/句柄的。但是在Win32k内核中,所有的内核窗口信息是全部被映射到用户模式的一块内存地址上的,通过user32!gSharedInfo可以得到它的地址(是内核模式窗口信息列表的一个只读映射),而刚才说过内核窗口对象在中断时已经经由HMAllocateObject被创建了,那么它实际就已经可以在gSharedInfo中检索到。这里代码使用SetWindowLongPtr将当前线程正在创建的窗口的WindowProc替换为了DefWindowProc。SetWindowLongPtr,当index(GWLP_WNDPROC(-4) ) lpfnWndProc=ptr;}这里的逻辑,是检查此处GWLP_WNDPROC是不是一个去子类化操作(unsubclass),如果是的话,就认为这里需要设置为内核来接管窗口过程,给窗口设置Server Side Proc的标志,这个标志的含义是窗口的窗口过程函数将在内核模式下调用。同时将窗口过程函数修改为DefWindowProc对应的内核处理函数。从CreateClassSmIcon返回,继续调用MapClientNeuterToClientPfn转化当前窗口类函数的默认WindowProc(也就是用户模式可控的函数),再将窗口对象的WindowProc设置为用户自己的窗口对象因为这个中断过程恰好在CreateWindowProc为窗口设置WindowProc前面,所以SetWindowData修改窗口的WindowProc为DefWindowProc是无效的,窗口的WindowProc还是被修改为用户模式应用程序设置的WindowProc,窗口过程处理函数也变成了MainWindowProc。而此时,这个窗口的标志已经被设置为是需要在内核模式执行WindowProc,那么接下来再遇到SendMessage等函数对这个窗口发送消息时,就会在内核模式下直接跳转、调用实际在用户模式的函数来进行处理,从而直接导致内核模式代码执行。MainWindowProc函数如下图所示