文章目录:
1. 引子:
2. 获取当前系统下所有进程:
3. 服务管理(安装,启动,停止,卸载):
4. 应用程序和内核程序通信:
5. 小结:
1. 引子:
关于这个 SSDT Hook 实现进程隐藏和进程保护呢,这是最后一篇博文了,在文章的结尾处你可以下载到整个项
目的实例程序以及代码,程序可以在 XP、Server、Win7 上运行的,当然我说的是32 位操作系统。
这一篇博文介绍的则是在 Ring3 下编写 MFC 应用程序,并且让应用程序与内核程序通信,即由应用程序
将需要隐藏的进程或者是需要保护的进程的 PID 传递给内核程序,然后在内核程序中就会将传递进来的这PID
进行隐藏或者保护 ~
在这里再给出这个应用程序的一张截图:
2. 获取当前系统下所有进程:
前面提到过,要想获取到系统下的所有进程,有三种方法,
第一种即是使用 ToolHelp 来获取;
第二种则是使用 PSAPI 来获取;
第三种则是使用 ntdll.dll 中的未文档化的 NtQuerySystemInformation 之类的 API 来获取(比较麻烦)。
而在这里我使用最简单的方式,即通过 PSAPI 中的 EnumProcesses 这个 API 来获取,EnumProcesses API 可以
获取到当前系统下所有进程的 PID,并且将 PID 存放在作为输出参数的数组当中,
其原型如下(可以看 MSDN):
1: BOOL WINAPI EnumProcesses(
2: __out DWORD* pProcessIds,
3: __in DWORD cb,
4: __out DWORD* pBytesReturned
5: );
6:
代码中使用(将获取到所有的 PID,然后将 PID 保存到 vector 容器中):
1: //遍历当前所有的进程,并且将进程 ID 填充到容器 vectorPID 中
2: void CSSDTProcessDlg::FillPIDVector()
3: {
4: DWORD dwPIDArray[MAX_PROCESS_COUNT];
5: DWORD dwNeededBytes;
6: DWORD dwProcCount;
7:
8: dwNeededBytes = 0;
9: dwProcCount = 0;
10: memset(dwPIDArray, 0, sizeof(DWORD) * MAX_PROCESS_COUNT);
11: if(NULL != EnumProcesses(dwPIDArray, sizeof(dwPIDArray), &dwNeededBytes))
12: {
13: dwProcCount = dwNeededBytes / sizeof(DWORD);
14: }
15:
16: BubbleSort(dwPIDArray, dwProcCount);
17:
18: ClearVector();
19: for(int i=0; i<dwProcCount; i++)
20: {
21: PROCESS_BIND procBind;
22: procBind.dwPID = dwPIDArray[i];
23: if(dwPIDArray[i] == 0)
24: {
25: procBind.state = ProcessStateUnknown;
26: }
27: else
28: {
29: procBind.state = ProcessStateGeneral;
30: }
31: this->m_vctAllProcess.push_back(procBind);
32: }
33: }
3. 服务管理(安装,启动,停止,卸载):
在 Windows 内核程序中,现在大体可以分为三类:
第一类是 NT 式驱动程序;
第二类是 WDM 驱动程序;
第三类是 WDF 驱动程序;
其中,对于 NT 式驱动程序,其安装方式是很简单的,因为你可以将 NT 式驱动程序看做一个服务,既然是
服务的话,自然在 Windows 中可以通过 SCM API 来完成其安装,启动,停止和卸载等功能 ~
而至于 WDM 和 WDF 的话,如果其中涉及到了设备的话,还必须使用 INF 文件来实现安装 ~ 而我们前面的
那个 SSDT 内核程序就是基于 NT 式的驱动程序,所以可以通过 SCM API 来实现上面的这些功能。
至于如何使用 SCM API 来完成服务的安装、启动、停止和卸载功能的话,可以参见笔者的另外一篇博文
《Windows 服务(附服务开发辅助工具)》,
博文地址为:http://www.cnblogs.com/BoyXiao/archive/2011/08/07/2130208.html
下面就只是将服务的安装 API、启动 API、停止 API 和卸载 API 贴出来了 ~
至于这些代码的细细道来的话,可以参考上面给出的那篇博文
1: //=====================================================================================//
2: //Name: bool InstallSvc() //
3: // //
4: //Descripion: 安装服务 //
5: // lpszSvcName 为服务名称, //
6: // lpszDisplay 为显示在服务控制管理器中的名称, //
7: // lpszSvcBinaryPath 为服务映像文件所在路径, //
8: // dwSvcType 为服务类型 //
9: // dwStartType 为服务启动类型 //
10: //=====================================================================================//
11: bool CSSDTProcessDlg::InstallSvc(LPTSTR lpszSvcName, LPTSTR lpszDisplayName,
12: LPTSTR lpszSvcBinaryPath, DWORD dwSvcType, DWORD dwStartType)
13: {
14: SC_HANDLE hSCM = NULL;
15: SC_HANDLE hSvc = NULL;
16:
17: AdjustProcessTokenPrivilege();
18:
19: hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
20: if(NULL == hSCM)
21: {
22: OutputErrorMessage(TEXT("InstallSvc - OpenSCManager Failed , Error Code Is %d , Error Message Is %s !"));
23:
24: return FALSE;
25: }
26:
27: for(int i = 0; i < 3 && (NULL == hSvc); i++)
28: {
29: //SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS
30: hSvc = CreateService(hSCM, lpszSvcName, lpszDisplayName, SERVICE_ALL_ACCESS,
31: dwSvcType, dwStartType, SERVICE_ERROR_NORMAL,
32: lpszSvcBinaryPath, NULL, NULL, NULL, NULL, NULL);
33: if(NULL != hSvc)
34: {
35: if(NULL != hSvc)
36: {
37: CloseServiceHandle(hSvc);
38: }
39: CloseServiceHandle(hSCM);
40: return TRUE;
41: }
42: }
43:
44: OutputErrorMessage(TEXT("InstallSvc - CreateService Failed , Error Code Is %d , Error Message Is %s !"));
45:
46: CloseServiceHandle(hSCM);
47:
48: return FALSE;
49: }
50:
51:
52: //=====================================================================================//
53: //Name: bool UnInstallSvc() //
54: // //
55: //Descripion: 实现卸载服务 //
56: //=====================================================================================//
57: bool CSSDTProcessDlg::UnInstallSvc(LPTSTR lpszSvcName)
58: {
59: SC_HANDLE hSCM = NULL;
60: SC_HANDLE hSvc = NULL;
61: bool rtResult = FALSE;
62:
63: AdjustProcessTokenPrivilege();
64:
65: hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
66: if(NULL == hSCM)
67: {
68: OutputErrorMessage(TEXT("UnInstallSvc - OpenSCManager Failed , Error Code Is %d , Error Message Is %s !"));
69:
70: return FALSE;
71: }
72:
73: hSvc = OpenService(hSCM, lpszSvcName, SERVICE_ALL_ACCESS);
74: if(NULL == hSvc)
75: {
76: OutputErrorMessage(TEXT("UnInstallSvc - OpenService Failed , Error Code Is %d , Error Message Is %s !"));
77:
78: CloseServiceHandle(hSCM);
79:
80: return FALSE;
81: }
82:
83: rtResult = DeleteService(hSvc);
84:
85: CloseServiceHandle(hSvc);
86: CloseServiceHandle(hSCM);
87:
88: return rtResult;
89: }
90:
91:
92: //=====================================================================================//
93: //Name: bool StartSvc() //
94: // //
95: //Descripion: 实现启动服务 //
96: //=====================================================================================//
97: bool CSSDTProcessDlg::StartSvc(LPTSTR lpszSvcName)
98: {
99: SC_HANDLE hSCM = NULL;
100: SC_HANDLE hSvc = NULL;
101: bool rtResult = FALSE;
102:
103: AdjustProcessTokenPrivilege();
104:
105: hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
106: if(NULL == hSCM)
107: {
108: OutputErrorMessage(TEXT("StartSvc - OpenSCManager Failed , Error Code Is %d , Error Message Is %s !"));
109:
110: return FALSE;
111: }
112:
113: hSvc = OpenService(hSCM, lpszSvcName, SERVICE_ALL_ACCESS);
114: if(NULL == hSvc)
115: {
116: OutputErrorMessage(TEXT("StartSvc - OpenService Failed , Error Code Is %d , Error Message Is %s !"));
117:
118: CloseServiceHandle(hSCM);
119:
120: return FALSE;
121: }
122:
123: rtResult = StartService(hSvc, NULL, NULL);
124:
125: CloseServiceHandle(hSvc);
126: CloseServiceHandle(hSCM);
127:
128: if(FALSE == rtResult)
129: {
130: if(ERROR_SERVICE_ALREADY_RUNNING == GetLastError())
131: {
132: return TRUE;
133: }
134: else
135: {
136: OutputErrorMessage(TEXT("StartSvc - StartService Failed , Error Code Is %d , Error Message Is %s !"));
137:
138: return FALSE;
139: }
140: }
141: else
142: {
143: return TRUE;
144: }
145: }
146:
147:
148: //=====================================================================================//
149: //Name: bool StopSvc() //
150: // //
151: //Descripion: 实现停止服务 //
152: //=====================================================================================//
153: bool CSSDTProcessDlg::StopSvc(LPTSTR lpszSvcName)
154: {
155: SC_HANDLE hSCM = NULL;
156: SC_HANDLE hSvc = NULL;
157: bool rtResult = FALSE;
158:
159: SERVICE_STATUS svcStatus;
160:
161: AdjustProcessTokenPrivilege();
162:
163: hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
164: if(NULL == hSCM)
165: {
166: OutputErrorMessage(TEXT("StopSvc - OpenSCManager Failed , Error Code Is %d , Error Message Is %s !"));
167:
168: return FALSE;
169: }
170:
171: hSvc = OpenService(hSCM, lpszSvcName, SERVICE_ALL_ACCESS);
172: if(NULL == hSvc)
173: {
174: OutputErrorMessage(TEXT("StopSvc - OpenService Failed , Error Code Is %d , Error Message Is %s !"));
175:
176: CloseServiceHandle(hSCM);
177:
178: return FALSE;
179: }
180:
181: rtResult = ControlService(hSvc, SERVICE_CONTROL_STOP, &svcStatus);
182: if(rtResult == FALSE)
183: {
184: OutputErrorMessage(TEXT("StopSvc - ControlService Failed , Error Code Is %d , Error Message Is %s !"));
185: }
186: CloseServiceHandle(hSvc);
187: CloseServiceHandle(hSCM);
188:
189: return rtResult;
190: }
那么服务的安装和启动放在那里比较合适,而服务的关闭和卸载又放在那里比较合适呢 ?
由于这个应用程序采用 MFC 开发,自然可以在 OnInitDialog()中安装和启动服务比较合适,而后可以
在对话框类的析构函数中关闭和卸载掉服务 ~
安装和启动服务:
1: wstring wStrSysPath = GetSysFilePath();
2: BOOL bResult = InstallSvc(((LPTSTR)(LPCTSTR)SSDT01_SERVICE_NAME),
3: ((LPTSTR)(LPCTSTR)SSDT01_SERVICE_NAME),
4: ((LPTSTR)(LPCTSTR)wStrSysPath.c_str()),
5: SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START);
6: if(FALSE == bResult)
7: {
8: MessageBox(_TEXT(" Install SSDT Service Failed , Application Auto Exit ! "),
9: _TEXT("Application Error"), MB_OK | MB_ICONSTOP);
10: CDialogEx::OnCancel();
11: return FALSE;
12: }
13: else
14: {
15: bResult = StartSvc(SSDT01_SERVICE_NAME);
16: if(FALSE == bResult)
17: {
18: MessageBox(_TEXT(" Start SSDT Service Failed , Application Auto Exit ! "),
19: _TEXT("Application Error"), MB_OK | MB_ICONSTOP);
20: CDialogEx::OnCancel();
21: return FALSE;
22: }
23: }
停止并且将服务卸载掉:
1: ~CSSDTProcessDlg()
2: {
3: //在析构函数中关闭 SSDT 设备句柄
4: if(this->m_hDevice)
5: {
6: CloseHandle(this->m_hDevice);
7: }
8:
9: //当发生析构函数时,停止服务并且卸载服务
10: StopSvc(SSDT01_SERVICE_NAME);
11: UnInstallSvc(SSDT01_SERVICE_NAME);
12: }
4. 应用程序和内核程序通信:
由前面的第二篇博文,可以知道,应用程序和内核程序的通信我是通过 DeviceIoControl 来完成的,开
发过内核程序的都清楚,应用程序和内核程序的通信最普遍的也就通过三个 API 来实现:
一个是 ReadFile;一个是WriteFile;一个是DeviceIoContrl。
当然其中属 DeviceIoControl 功能最为强大,完全可以用其替换掉 ReadFile 和 WriteFile。
DeviceIoControl 原型(详细信息可以参考 MSDN):
1: BOOL WINAPI DeviceIoControl(
2: __in HANDLE hDevice,
3: __in DWORD dwIoControlCode,
4: __in LPVOID lpInBuffer,
5: __in DWORD nInBufferSize,
6: __out LPVOID lpOutBuffer,
7: __in DWORD nOutBufferSize,
8: __out LPDWORD lpBytesReturned,
9: __in LPOVERLAPPED lpOverlapped
10: );
11:
至于如何实现应用程序和内核程序的通信的话,在我的 Demo 中是这样做处理的,首先在 OnInitDialog
事件中通过 CreateFile 打开我们所安装的服务中创建的设备,(在 NT 式驱动程序中我创建了一个设备,这个
设备用来实现应用程序和内核程序的通信),然后在对话框类中保存有一个全局变量,这个全局变量即代表所打开
的这个设备的句柄,
既然这个全局变量是保存的我们的设备的句柄,自然我们需要来获取到设备的句柄,并且将句柄赋值给该全
局变量,而这个呢,又是在 OnInitDialog 中完成的 ~
1: this->m_hDevice = CreateFile(SSDT01_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, 0,
2: NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3: if(INVALID_HANDLE_VALUE == this->m_hDevice)
4: {
5: MessageBox(_TEXT(" Open SSDT Device Failed , Application Auto Exit ! "),
6: _TEXT("Application Error"), MB_OK | MB_ICONSTOP);
7:
8: CDialogEx::OnCancel();
9: return FALSE;
10: }
有了这个设备句柄,我们就可以通过其来实现和内核程序的通信了,因为通过在应用程序中调用
DeviceIoControl 可以产生 IRP_MJ_DEVICE_CONTROL 的 IRP,然后该 IRP 可以被驱动程序中的
DeviceIoControl 分发函数所处理 ~
我们的应用程序只需要将我们所要隐藏或者是需要保护的进程的 PID 通过 DeviceIoControl 传递给内核程序即可 !!!
所以我们在应用程序中只需要调用 DeviceIoContrl 即可 ~
下面给出的代码比较凌乱(重点请看 DeviceIoControl 的调用)
1: //隐藏进程或者取消对进程的隐藏
2: void CSSDTProcessDlg::OnBnClickedBtnHideorunhide()
3: {
4: int nIndex;
5: DWORD dwPID;
6: CString cStrText;
7: CString cStrState;
8:
9: DWORD dwOutput;
10: BOOL bRet;
11: CHAR inBuffer[10];
12: CHAR outBuffer[10];
13: memset(inBuffer, 0, 10);
14: memset(outBuffer, 0, 10);
15:
16: dwPID = this->GetDlgItemInt(IDC_STATIC_SELECTED_PID);
17: this->GetDlgItemText(ID_BTN_HIDEORUNHIDE, cStrText);
18:
19: ultoa(dwPID, inBuffer, 10);
20:
21: nIndex = QueryItemIndexByPID(dwPID);
22: cStrState = this->m_ListCtrlProcess.GetItemText(nIndex, 4);
23:
24: if(cStrText.CompareNoCase(_TEXT("Hide")) == 0)
25: {
26: //隐藏 dwPID
27: bRet = DeviceIoControl(this->m_hDevice, IO_INSERT_HIDE_PROCESS, inBuffer, 10,
28: &outBuffer, 10, &dwOutput, NULL);
29: if(bRet)
30: {
31: this->SetDlgItemText(ID_BTN_HIDEORUNHIDE, _TEXT("UnHide"));
32: if(cStrState.CompareNoCase(_TEXT("Protect")) == 0)
33: {
34: this->m_ListCtrlProcess.SetItemText(nIndex, 4, _TEXT("HideAndProtect"));
35: }
36: else
37: {
38: this->m_ListCtrlProcess.SetItemText(nIndex, 4, _TEXT("Hide"));
39: }
40: MessageBox(_TEXT(" Hide Process Sucess ! "), _TEXT("Information"), MB_OK |
41: MB_ICONINFORMATION);
42: }
43: else
44: {
45: MessageBox(_TEXT(" Hide Process Failed ! "), _TEXT("Warning"), MB_OK | MB_ICONERROR);
46: }
47: }
48: else
49: {
50: //解除 dwPID 隐藏
51: bRet = DeviceIoControl(this->m_hDevice, IO_REMOVE_HIDE_PROCESS, inBuffer, 10,
52: &outBuffer, 10, &dwOutput, NULL);
53: if(bRet)
54: {
55: this->SetDlgItemText(ID_BTN_HIDEORUNHIDE, _TEXT("Hide"));
56: if(cStrState.CompareNoCase(_TEXT("Protect")) == 0 ||
57: cStrState.CompareNoCase(_TEXT("HideAndProtect"))== 0)
58: {
59: this->m_ListCtrlProcess.SetItemText(nIndex, 4, _TEXT("Protect"));
60: }
61: else
62: {
63: this->m_ListCtrlProcess.SetItemText(nIndex, 4, _TEXT("General"));
64: }
65: MessageBox(_TEXT(" UnHide Process Sucess ! "), _TEXT("Information"), MB_OK |
66: MB_ICONINFORMATION);
67: }
68: else
69: {
70: MessageBox(_TEXT(" UnHide Process Failed ! "), _TEXT("Warning"), MB_OK | MB_ICONERROR);
71: }
72: }
73: }
74:
75:
76: //保护进程或者取消对进程的保护操作
77: void CSSDTProcessDlg::OnBnClickedBtnProtectorunprotect()
78: {
79: int nIndex;
80: DWORD dwPID;
81: CString cStrText;
82: CString cStrState;
83:
84: DWORD dwOutput;
85: BOOL bRet;
86: CHAR inBuffer[10];
87: CHAR outBuffer[10];
88: memset(inBuffer, 0, 10);
89: memset(outBuffer, 0, 10);
90:
91: dwPID = this->GetDlgItemInt(IDC_STATIC_SELECTED_PID);
92: this->GetDlgItemText(ID_BTN_PROTECTORUNPROTECT, cStrText);
93:
94: ultoa(dwPID, inBuffer, 10);
95:
96: nIndex = QueryItemIndexByPID(dwPID);
97: cStrState = this->m_ListCtrlProcess.GetItemText(nIndex, 4);
98:
99: if(cStrText.CompareNoCase(_TEXT("Protect")) == 0)
100: {
101: //保护 dwPID 保护
102: bRet = DeviceIoControl(this->m_hDevice, IO_INSERT_PROTECT_PROCESS, inBuffer, 10,
103: &outBuffer, 10, &dwOutput, NULL);
104: if(bRet)
105: {
106: this->SetDlgItemText(ID_BTN_PROTECTORUNPROTECT, _TEXT("UnProtect"));
107: if(cStrState.CompareNoCase(_TEXT("Hide"))== 0)
108: {
109: this->m_ListCtrlProcess.SetItemText(nIndex, 4, _TEXT("HideAndProtect"));
110: }
111: else
112: {
113: this->m_ListCtrlProcess.SetItemText(nIndex, 4, _TEXT("Protect"));
114: }
115: MessageBox(_TEXT(" Protect Process Sucess ! "), _TEXT("Information"), MB_OK |
116: MB_ICONINFORMATION);
117: }
118: else
119: {
120: MessageBox(_TEXT(" Protect Process Failed ! "), _TEXT("Warning"), MB_OK | MB_ICONERROR);
121: }
122: }
123: else
124: {
125: //解除 dwPID 保护
126: bRet = DeviceIoControl(this->m_hDevice, IO_REMOVE_PROTECT_PROCESS, inBuffer, 10,
127: &outBuffer, 10, &dwOutput, NULL);
128: if(bRet)
129: {
130: this->SetDlgItemText(ID_BTN_PROTECTORUNPROTECT, _TEXT("Protect"));
131: if(cStrState.CompareNoCase(_TEXT("Hide")) == 0 ||
132: cStrState.CompareNoCase(_TEXT("HideAndProtect")) == 0)
133: {
134: this->m_ListCtrlProcess.SetItemText(nIndex, 4, _TEXT("Hide"));
135: }
136: else
137: {
138: this->m_ListCtrlProcess.SetItemText(nIndex, 4, _TEXT("General"));
139: }
140: MessageBox(_TEXT(" UnProtect Process Sucess ! "), _TEXT("Information"), MB_OK |
141: MB_ICONINFORMATION);
142: }
143: else
144: {
145: MessageBox(_TEXT(" UnProtect Process Failed ! "), _TEXT("Warning"), MB_OK | MB_ICONERROR);
146: }
147: }
148: }
5. 小结:
介绍这个应用程序呢,还真是不好写,因为感觉整个 Demo 里面却是没有什么好介绍的,无非就是获取到所
有的进程,然后通过一个 ListCtrl 来显示这些数据,然后用户选择一个进程,单击一下隐藏呢,我就在这个按
钮的消息处理函数中和内核程序通过 DeviceIoControl 通信一下,将这个进程的 PID 传递给内核程序,其他的
就都不需要理会了 ~ 所以转来转去的,也没什么好些的,干脆就写到这里得了。
等下将整个 Demo 打个包,直接提供下载,我这里说得口干舌燥也没什么用,感兴趣的自己下载了源码去慢
慢玩得了 ~
最后再总结一个 SSDT Hook 的优点,那就是 SSDT Hook 无论你是 Windows XP 还是 Server 或者 Vista 或
者 Win7,你都是可以很好的运行程序的,所以你下载的 Demo 你可以放心的在上面的这些操作系统上运行,当然
64 位的除外,64 位的操作系统虽然我没有做过测试,但是我估摸着会蓝屏的 ~ 有兴趣的可以去蓝一次 ~
下载 Demo Source Code