进程隐藏与进程保护(SSDT Hook 实现)(三)

时间:2024-06-02 13:33:49

文章目录:

1. 引子:

2. 获取当前系统下所有进程:

3. 服务管理(安装,启动,停止,卸载):

4. 应用程序和内核程序通信:

5. 小结:

1. 引子:

关于这个 SSDT Hook 实现进程隐藏和进程保护呢,这是最后一篇博文了,在文章的结尾处你可以下载到整个项

目的实例程序以及代码,程序可以在 XPServerWin7 上运行的,当然我说的是32 位操作系统。

这一篇博文介绍的则是在 Ring3 下编写 MFC 应用程序,并且让应用程序与内核程序通信,即由应用程序

将需要隐藏的进程或者是需要保护的进程的 PID 传递给内核程序,然后在内核程序中就会将传递进来的这PID

进行隐藏或者保护 ~

在这里再给出这个应用程序的一张截图:

进程隐藏与进程保护(SSDT Hook 实现)(三)

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 式驱动程序中我创建了一个设备,这个

设备用来实现应用程序和内核程序的通信),然后在对话框类中保存有一个全局变量,这个全局变量即代表所打开

的这个设备的句柄,

进程隐藏与进程保护(SSDT Hook 实现)(三)

既然这个全局变量是保存的我们的设备的句柄,自然我们需要来获取到设备的句柄,并且将句柄赋值给该全

局变量,而这个呢,又是在 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