首页 > 代码库 > 安全类工具制作第006篇:服务管理器

安全类工具制作第006篇:服务管理器

一、前言

        服务是一种在操作系统启动的时候就会启动的进程。在操作系统启动时会有两种程序随着系统启动,一种是普通的Win32程序,另一种则是驱动程序。正是基于服务的这种特性,恶意程序往往也会将自身伪装成正常的服务来实现自启动。因此在反病毒的过程中,还是很有必要对服务项进行查看并管理的。

        服务管理器的开发原理与之前所讨论的注册表管理器和进程管理器是类似的,主要也是枚举服务并将其显示在“List Control”控件中。而对于服务的管理,是通过服务相关的API函数来实现的。有了本系列之前几篇文章的铺垫,那么我在此就不会对MFC进行过细的讲解。大家可以参考之前的文章进行回顾。

 

二、界面设计

        利用MFC创建一个基于对话框的程序,这里需要一个“List Control”、两个“Radio Button”和三个“Button”控件:


图1 程序界面

        然后设置“List Control”的控件属性,在“Sytles”中的“View”中,选择“Report”,再选中“Single Selection”选项。然后为其添加一个名为“m_ServiceList”的变量,然后通过编程进行初始化:

void CServiceManageDlg::InitServiceList()
{
        //设置“List Control”控件的扩展风格
        m_ServiceList.SetExtendedStyle(
                m_ServiceList.GetExtendedStyle()
                | LVS_EX_GRIDLINES         //有网络格
                | LVS_EX_FULLROWSELECT );  //选中某行使整行高亮(只适用于report风格)
        //添加列目
        m_ServiceList.InsertColumn(0, "序号");
        m_ServiceList.InsertColumn(1, "服务名");
        m_ServiceList.InsertColumn(2, "显示名");
        m_ServiceList.InsertColumn(3, "状态");
        //设置列的宽度
        m_ServiceList.SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER);
        m_ServiceList.SetColumnWidth(1, 100);
        m_ServiceList.SetColumnWidth(2, 250);
        m_ServiceList.SetColumnWidth(3, LVSCW_AUTOSIZE_USEHEADER);
}

 

三、服务的枚举

        服务的枚举首先需要打开服务管理器,然后开始枚举服务,将枚举的服务显示在列表中,最后再关闭服务句柄:
void CServiceManageDlg::ShowServiceList(DWORD dwServiceType)
{
        m_ServiceList.DeleteAllItems();
        //打开服务管理器
        SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
        if ( NULL == hSCM )
        {
                AfxMessageBox("无法打开服务管理器!");
                return ;
        }

        DWORD dwBufSize = 512 * sizeof(ENUM_SERVICE_STATUS);
        DWORD dwByteNeeded, dwServicesReturned, lpResumeHandle = 0;
        ENUM_SERVICE_STATUS SerStatus[512] = { 0 };
        //服务项的枚举
        BOOL bRet = EnumServicesStatus(hSCM,
                                       dwServiceType,
                                       SERVICE_STATE_ALL,
                                       SerStatus,
                                       dwBufSize,
                                       &dwByteNeeded,
                                       &lpResumeHandle);
        if ( FALSE == bRet )
        {
                AfxMessageBox("服务项枚举失败!");
                CloseServiceHandle(hSCM);
                return ;
        }
        //在列表中显示枚举出来的服务项
        for ( DWORD i = 0; i < dwServicesReturned; i ++ )
        {
                CString str;
                str.Format("%d", i);
                m_ServiceList.InsertItem(i, str);
                m_ServiceList.SetItemText(i, 1, SerStatus[i].lpServiceName);
                m_ServiceList.SetItemText(i, 2, SerStatus[i].lpDisplayName);
                switch ( SerStatus[i].ServiceStatus.dwCurrentState )
                {
                case SERVICE_PAUSED:
                {
                        m_ServiceList.SetItemText(i, 3, "暂停");
                        break;
                }
                case SERVICE_STOPPED:
                {
                        m_ServiceList.SetItemText(i, 3, "停止");
                        break;
                }
                case SERVICE_RUNNING:
                {
                        m_ServiceList.SetItemText(i, 3, "运行");
                        break;
                }
                default:
                {
                        m_ServiceList.SetItemText(i, 3, "其他");
                }
                }
        }

        CloseServiceHandle(hSCM);
}
        这里要添加头文件“Winsvc.h”。需要特别说明的是,如果想在程序启动时就枚举出Win32服务应用程序,那么就需要在OnInitDialog()中添加:
// TODO: Add extra initialization here
InitServiceList();
ShowServiceList(SERVICE_WIN32);

        同理,如果想默认显示驱动程序,则将ShowServiceList()函数的参数改写为SERVICE_DRIVER,若什么都不想显示,则在初始化语句中删除这个函数。

 

四、服务的切换

        对于两种服务切换的实现,就是对“Radio Button”控件添加代码:
void CServiceManageDlg::OnRadioWin32() 
{
        // TODO: Add your control notification handler code here
        ShowServiceList(SERVICE_WIN32);
}

void CServiceManageDlg::OnRadioDriver() 
{
        // TODO: Add your control notification handler code here
        ShowServiceList(SERVICE_DRIVER);
}

        根据不同的参数,就能够枚举相应的服务。

 

五、服务的启动与停止

        启动服务与停止服务的代码如下,比较简单,这里不再赘述:
</pre><p><span style="font-size:14px;"></span><pre name="code" class="cpp">void CManageServiceDlg::OnBtnStart() 
{
        // TODO: Add your control notification handler code here
        // 选中服务的的索引
        POSITION Pos = m_ServiceList.GetFirstSelectedItemPosition();
        int nSelect = -1;

        while ( Pos )
        {
                nSelect = m_ServiceList.GetNextSelectedItem(Pos);
        }

        if ( -1 == nSelect )
        {
                AfxMessageBox("请选择要启动的服务");
                return ;
        }
        // 获取选中服务的服务名
        char szServiceName[MAXBYTE] = { 0 };
        m_ServiceList.GetItemText(nSelect, 1, szServiceName, MAXBYTE);

        SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
        if ( NULL == hSCM )
        {
                AfxMessageBox("OpenSCManager Error");
                return ;
        }

        SC_HANDLE hSCService = OpenService(hSCM, szServiceName, SERVICE_ALL_ACCESS);
    
        // 启动服务
        BOOL bRet = StartService(hSCService, 0, NULL);
        if ( bRet == TRUE )
        {
                m_ServiceList.SetItemText(nSelect, 3, "运行");
        }
        else
        {
                int n = GetLastError();
        }

        CloseServiceHandle(hSCService);
        CloseServiceHandle(hSCM);
}

void CManageServiceDlg::OnBtnStop() 
{
        // TODO: Add your control notification handler code here
        // 选中服务的的索引
        POSITION Pos = m_ServiceList.GetFirstSelectedItemPosition();
        int nSelect = -1;
    
        while ( Pos )
        {
                nSelect = m_ServiceList.GetNextSelectedItem(Pos);
        }
    
        if ( -1 == nSelect )
        {
                AfxMessageBox("请选择要停止的服务");
                return ;
        }
    
        // 获取选中服务的服务名
        char szServiceName[MAXBYTE] = { 0 };
        m_ServiceList.GetItemText(nSelect, 1, szServiceName, MAXBYTE);
    
        SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
        if ( NULL == hSCM )
        {
                AfxMessageBox("OpenSCManager Error");
                return ;
        }
    
        SC_HANDLE hSCService = OpenService(hSCM, szServiceName, SERVICE_ALL_ACCESS);
        SERVICE_STATUS ServiceStatus;
        // 停止服务
        BOOL bRet = ControlService(hSCService, SERVICE_CONTROL_STOP, &ServiceStatus);
        if ( bRet == TRUE )
        {
                m_ServiceList.SetItemText(nSelect, 3, "停止");
        }
        else
        {
                int n = GetLastError();
        }
    
        CloseServiceHandle(hSCService);
        CloseServiceHandle(hSCM);
}

 

六、程序测试

        上述程序编译链接成功后,运行,测试一下:


图2 运行程序

        程序启动时就已经列出了本机所有的Win32服务应用程序,通过单选按钮就可以切换到驱动程序的显示,这里也可以用专业软件SREng对比一下:


图3 使用SREng显示服务

        二者是一致的,说明我们的程序没有问题。

 

七、小结

        至此,三大“静态”查毒利器的主体框架已经编写完毕,利用这三个工具就能够令应用层的恶意程序无处藏身。通过这三个工具的制作,可以发现API函数的强大,这种“拿来主义”为我们的编程提供了非常大的便利。接下来可以考虑将这三个程序合并在一起,令查毒工作更加方便,一目了然。有兴趣的读者不妨尝试一下。

安全类工具制作第006篇:服务管理器