CHECKER2程序包含一个键盘接口,内容与CHECKER1完全相同。利用←、→、↑、↓四个方向键可以在25个矩形之间移动鼠标指针。Home键把鼠标指针移动到左上角的矩形;End键使鼠标指针落到右下角的矩形。空格键和回车键都可以切换X形标记。

Tomcat
Native是用于Tomcat的一个可选组件,能够允许Tomcat使用一定的本地资源、性能、兼容性。

————————————————————————————————————————————————————————————————

图片 1图片 2

具体来说,Tomcat Native给了Tomcat访问 Apache Portable
Runtime(APR)的网络连接实施和随机数发生器。

在上一篇文章中,我们已经看到
IopParseDevice() 如何对传入的 OPEN_PACKET 结构进行验证。假设
ObReferenceObjectByName() 的调用者没有分配并初始化第七个参数
ParseContext,而仅是简单地传入 “NULL” ,那么当调用链深入到
IopParseDevice()
内部时,就会因验证失败返回 C0000024(STATUS_OBJECT_TYPE_MISMATCH)。

  1 /*---------------------------------------------
  2 CHECKER2.C -- Mouse Hit-Test Demo Program No.2
  3               (c) Charles Petzold, 1998
  4 ---------------------------------------------*/
  5 
  6 #include <Windows.h>
  7 
  8 #define DIVISIONS 5
  9 
 10 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
 11 
 12 int WINAPI WinMain( __in HINSTANCE hInstance
 13                     , __in_opt HINSTANCE hPrevInstance
 14                     , __in LPSTR lpCmdLine
 15                     , __in int nShowCmd )
 16 {
 17     static TCHAR szAppName[] = TEXT("Checker2");
 18     HWND hwnd;
 19     MSG msg;
 20     WNDCLASS wndclass;
 21 
 22     wndclass.style = CS_HREDRAW | CS_VREDRAW;
 23     wndclass.lpfnWndProc = WndProc;
 24     wndclass.cbClsExtra = 0;
 25     wndclass.cbWndExtra = 0;
 26     wndclass.hInstance = hInstance;
 27     wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
 28     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
 29     wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
 30     wndclass.lpszMenuName = NULL;
 31     wndclass.lpszClassName = szAppName;
 32 
 33     if (!RegisterClass(&wndclass))
 34     {
 35         MessageBox(NULL, TEXT("Program requires Windows NT!")
 36             , szAppName, MB_ICONERROR);
 37         return 0;
 38     }
 39 
 40     hwnd = CreateWindow(szAppName, TEXT("Checker2 Mouse Hit-Test Demo")
 41         , WS_OVERLAPPEDWINDOW
 42         , CW_USEDEFAULT, CW_USEDEFAULT
 43         , CW_USEDEFAULT, CW_USEDEFAULT
 44         , NULL, NULL, hInstance, NULL);
 45 
 46     ShowWindow(hwnd, nShowCmd);
 47     UpdateWindow(hwnd);
 48 
 49     while (GetMessage(&msg, NULL, 0, 0))
 50     {
 51         TranslateMessage(&msg);
 52         DispatchMessage(&msg);
 53     }
 54 
 55     return msg.wParam;
 56 }
 57 
 58 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 59 {
 60     static BOOL fState[DIVISIONS][DIVISIONS];
 61     static int cxBlock, cyBlock;
 62     HDC hdc;
 63     int x, y;
 64     PAINTSTRUCT ps;
 65     POINT point;
 66     RECT rect;
 67 
 68     switch (message)
 69     {
 70     case WM_SIZE:
 71         cxBlock = LOWORD(lParam) / DIVISIONS;
 72         cyBlock = HIWORD(lParam) / DIVISIONS;
 73         return 0;
 74 
 75     case WM_SETFOCUS:
 76         ShowCursor(TRUE);
 77         return 0;
 78 
 79     case WM_KILLFOCUS:
 80         ShowCursor(FALSE);
 81         return 0;
 82 
 83     case WM_KEYDOWN:
 84         GetCursorPos(&point);
 85         ScreenToClient(hwnd, &point);
 86 
 87         x = max(0, min(DIVISIONS - 1, point.x / cxBlock));
 88         y = max(0, min(DIVISIONS - 1, point.y / cyBlock));
 89 
 90         switch (wParam)
 91         {
 92         case VK_UP:
 93             --y;
 94             break;
 95 
 96         case VK_DOWN:
 97             ++y;
 98             break;
 99 
100         case VK_LEFT:
101             --x;
102             break;
103 
104         case VK_RIGHT:
105             ++x;
106             break;
107 
108         case VK_HOME:
109             x = y = 0;
110             break;
111 
112         case VK_END:
113             x = y = DIVISIONS - 1;
114             break;
115 
116         case VK_RETURN:
117         case VK_SPACE:
118             SendMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(x * cxBlock, y * cyBlock));
119             break;
120         }
121 
122         x = (x + DIVISIONS) % DIVISIONS;
123         y = (y + DIVISIONS) % DIVISIONS;
124 
125         point.x = x * cxBlock + cxBlock / 2;
126         point.y = y * cyBlock + cyBlock / 2;
127 
128         ClientToScreen(hwnd, &point);
129         SetCursorPos(point.x, point.y);
130         return 0;
131 
132     case WM_LBUTTONDOWN:
133         x = LOWORD(lParam) / cxBlock;
134         y = HIWORD(lParam) / cyBlock;
135 
136         if (x < DIVISIONS && y < DIVISIONS)
137         {
138             fState[x][y] ^= 1;
139 
140             rect.left = x * cxBlock;
141             rect.top = y * cyBlock;
142             rect.right = (x + 1) * cxBlock;
143             rect.bottom = (y + 1) * cyBlock;
144 
145             InvalidateRect(hwnd, &rect, FALSE);
146         }
147         else
148             MessageBeep(0);
149         return 0;
150 
151     case WM_PAINT:
152         hdc = BeginPaint(hwnd, &ps);
153 
154         for (x = 0; x < DIVISIONS; ++x)
155             for (y = 0; y < DIVISIONS; ++y)
156             {
157                 Rectangle(hdc, x * cxBlock, y * cyBlock
158                     , (x + 1) * cxBlock, (y + 1) * cyBlock);
159                 
160                 if (fState[x][y])
161                 {
162                     MoveToEx(hdc, x * cxBlock, y * cyBlock, NULL);
163                     LineTo(hdc, (x + 1) * cxBlock, (y + 1) * cyBlock);
164                     MoveToEx(hdc, x * cxBlock, (y + 1) * cyBlock, NULL);
165                     LineTo(hdc, (x + 1) * cxBlock, y * cyBlock);
166                 }
167             }
168 
169         EndPaint(hwnd, &ps);
170         return 0;
171 
172     case WM_DESTROY:
173         PostQuitMessage(0);
174         return 0;
175     }
176 
177     return DefWindowProc(hwnd, message, wParam, lParam);
178 }

APR连接器的特点:

我们根据源码中的暗示来追踪
OPEN_PACKET 结构究竟在哪分配的,如前所述,调用链
NtCreateFile->IoCreateFile()->IopCreateFile() 的结尾,也就是在
IopCreateFile() 内部,实际负责 OPEN_PACKET
的初始化。下面贴出的代码片段以 NT 5.2 版内核源码为样例:

CHECKER2.C

  • 非阻塞I/O请求(请求之间保持)
  • 使用OpenSSL TLS / SSL功能(如果链接APR库支持)
  • FIPS 140-2支持TLS / SSL(如果与OpenSSL库支持)

 

在CHECKER2程序中,处理WM_KEYDOWN时利用GetCursorPos判断指针的位置,并利用ScreenToClient将屏幕坐标转换成客户区坐标,然后将坐标值除以矩形块的宽和高,得到x和y。这些x和y的值表示了矩形在5*5数组中的位置。当按下某个键时,鼠标指针可能在客户区也可能不在客户区内,因此x和y必须包含在min和max的宏处理中,保证它们的范围处于0和4之间。

具体参考:

图片 3

对于方向键,CHECKER2程序相应的增加或减少x和y的值。若按下回车键或空格键,CHECKER2程序调用SendMessage给自己发送一个WM_LBUTTONDOWN消息。最后,WM_KEYDOWN处理逻辑计算得到指向矩形中心的客户区坐标,并调用ClientToScreen将其转换成屏幕坐标,最后调用SetCursorPos设置指针的位置。

话不多说,直接上教程

也就是说,我们直接复制
IopCreateFile() 中的 OPEN_PACKET 结构初始化部分逻辑就行了?

//配置gcc依赖
yum install gcc

//安装openssl
wget https://www.openssl.org/source/openssl-1.1.0e.tar.gz
tar -zxvf openssl-1.1.0e.tar.gz
cd openssl-1.1.0e
./config --prefix=/usr/local/openssl
make && make install

//安装apr
cd
wget http://mirror.bit.edu.cn/apache//apr/apr-1.5.2.tar.gz
tar -zxvf apr-1.5.2.tar.gz
cd apr-1.5.2
./configure --prefix=/usr/local/apr
make && make install

//安装apr-util
cd
wget http://mirror.bit.edu.cn/apache//apr/apr-util-1.5.4.tar.gz
tar -zxvf apr-util-1.5.4.tar.gz
cd apr-util-1.5.4
./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr
make && make install

//安装tomcat-native
cd
wget https://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-connectors/native/1.2.12/source/tomcat-native-1.2.12-src.tar.gz
tar -zxvf tomcat-native-1.2.12-src.tar.gz
cd tomcat-native-1.2.12-src/native
./configure --with-apr=/usr/local/apr --with-ssl=/usr/local/openssl
make && make install

//配置环境变量
vi /etc/profile
//在末尾添加
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/apr/lib
source /etc/profile

//测试
cat /usr/local/tomcat/logs/catalina.out
//可以看到类似下面的消息即可
[main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-apr-18080"]
INFO: Loaded APR based Apache Tomcat Native library 1.1.33 using APR version 1.5.2.
org.apache.catalina.core.AprLifecycleListener.init Loaded APR based Apache Tomcat Native library 1.1.29 using APR version 1.5.0.

//另外server.xml有如下一项默认设置
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
//如果用不到SSL,则需要关闭,on改为off,否则启动时会报错

这里还有一个问题,负责分配该结构体内核内存的例程 IopAllocateOpenPacket()
是一个宏,Visual C++ 2015 中给出它是用 ExAllocatePoolWithTag()
定义的。这就好办了,在我们自己的驱动源码中,添加相应定义即可,如下图:

 

 

图片 4

 

————————————————————————————————————————————————————————————

因为
OPEN_PACKET 结构同样没有公开的文档来描述,所以要么在我们的驱动源码中用 
#include
包含定义它的头文件,要么直接复制定义的那一部分黏贴进来。很显然,后者比较轻松——OPEN_PACKET
在内核源码的 “iomgr.h
中定义,而该头文件又嵌套包含了一堆杂七杂八的内核头文件,要理清这些嵌套包含关系很麻烦,而且最重要的是,其中一些头文件定义的数据类型会与驱动开发中用的 “ntddk.h”
和“wdm.h”重复,引起编译器的抱怨。
所以直接在 “iomgr.h
中搜索字串 “typedef struct
_OPEN_PACKET”,把找到的定义块拷贝进来即可。

然而,OPEN_PACKET
结构中唯有一个字段不是 “原生” 定义的——这就是 “PDUMMY_FILE_OBJECT”
类型,需要包含其它头文件才不致使编译器报错。

我的解决方案是,直接把该字段的声明所在行注释掉,下图展示了该字段具体的位置(在
iomgr.h” 中的行号),方便各位快速查找:

 

图片 5

——————————————————————————————————————————————————————————————————

注意,NT
6.1 版内核在编译时刻的 OPEN_PACKET 结构显然是未经 “恶意
修改的,所以编译器为其 “sizeof(OPEN_PACKET)” 表达式计算 0x70
的值,而我们在自己的驱动中拿掉了 OPEN_PACKET
其中一个字段使得编译器为表达式 “sizeof(OPEN_PACKET)” 预计算 0x58
的值(后面的调试阶段会验证),这会造成 “Size” 字段不是
IopParseDevice() 内部逻辑预期的 0x70,从而导致返回
C0000024(STATUS_OBJECT_TYPE_MISMATCH)。

解决办法也很简单,我们的驱动中,不要依赖编译时刻的计算,直接把
Size” 字段的值硬编码为 0x70 不就好了?

如下图所示,你还会注意到,我把
“Type” 字段的常量 “IO_TYPE_OPEN_PACKET”
改成了对应的数值,以确保万一。

 

图片 6

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注