安全类工具制作第004篇:进程管理器(上)

一、前言

进程是计算机中执行的程序,是向操作系统申请资源的基本单位。我们执行一个程序。那么就会对应地创建一个甚至多个进程,关闭程序时。进程也就结束了。查看进程最经常使用的手段是按下Ctrl+Shift+Delete打开Windows自带的任务管理器,或者使用老牌强力软件“冰刃”。又或者是使用由微软推出的更为强大的Process Monitor,都能基本得到同样的效果。不同的是。强大的进程查看软件能够查看到系统的隐藏进程,而一般的仅仅能查看应用层的进程。而我在这两篇文章中所讨论的就是怎样实现一个简易的进程管理器,通过它能够管理当前的进程,也能够管理进程所载入的DLL。这篇文章主要讨论的就是进程管理方面的编程,下一篇再讨论DLL管理方面的程序编写。

二、界面设计

本程序须要设计两个界面。这篇文章仅仅讨论第一个界面的制作。这里须要一个“List Control”和三个“Button”控件:

图1 主界面的设计

然后设置“List Control”的控件属性。在“Sytles”中的“View”中。选择“Report”,再选中“Single Selection”选项。

然后为其加入一个名为“m_ProcessList”的变量,然后通过编程进行初始化:

void CProcessManageDlg::InitProcessList()
{
        //设置“List Control”控件的扩展风格
        m_ProcessList.SetExtendedStyle(
                m_ProcessList.GetExtendedStyle()
                | LVS_EX_GRIDLINES        //有网络格
                | LVS_EX_FULLROWSELECT);  //选中某行使整行高亮(仅仅适用于report风格)

        //加入列目
        m_ProcessList.InsertColumn(0, _T("序号"));
        m_ProcessList.InsertColumn(1, _T("进程名称          "));
        m_ProcessList.InsertColumn(2, _T("PID值"));
        m_ProcessList.InsertColumn(3, _T("线程数"));
        m_ProcessList.InsertColumn(4, _T("父进程ID"));
        m_ProcessList.InsertColumn(5, _T("线程优先级"));
        //设置列的宽度
        m_ProcessList.SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER);
        m_ProcessList.SetColumnWidth(1, LVSCW_AUTOSIZE_USEHEADER);
        m_ProcessList.SetColumnWidth(2, LVSCW_AUTOSIZE_USEHEADER);
        m_ProcessList.SetColumnWidth(3, LVSCW_AUTOSIZE_USEHEADER);
        m_ProcessList.SetColumnWidth(4, LVSCW_AUTOSIZE_USEHEADER);
        m_ProcessList.SetColumnWidth(5, LVSCW_AUTOSIZE_USEHEADER);
}  

之后在CProcessManageDlg::OnInitDialog()中加入:

InitProcessList();

以实现初始化,再在头文件里声明:

void InitProcessList();

三、进程的枚举

进程的枚举就是把全部的进程显示出来,而有一些特意隐藏的进程是无法通过常规的枚举方式枚举到的。

这里所解说的是应用层的进程枚举。

为实现此功能。这里使用的是CreateToolhelp32Snapshot()。它的作用是对当前系统中的进程进行一个快照。在创建成功后对进程逐个枚举。

枚举进程须要用到Process32First()以及Process32Next()这两个函数。使用这几个函数须要先包括Tlhelp32.h头文件。代码例如以下:

void CProcessManageDlg::ShowProcess()
{
        //清空列表
        m_ProcessList.DeleteAllItems();
        //给系统内全部的进程拍个快照
        HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if ( hSnap == INVALID_HANDLE_VALUE )
        {
                AfxMessageBox("进程快照创建失败!");
                return ;
        }

        PROCESSENTRY32 Pe32 = { 0 };
        //在使用这个结构前。先设置它的大小
        Pe32.dwSize = sizeof(PROCESSENTRY32);
        //遍历进程快照,轮流显示每一个进程的信息
        BOOL bRet = Process32First(hSnap, &Pe32);
        int i = 0;
        CString str;

        while ( bRet )
        {
                str.Format("%d", i);
                m_ProcessList.InsertItem(i, str);
                //进程名
                m_ProcessList.SetItemText(i, 1, Pe32.szExeFile);
                //进程ID
                str.Format("%d", Pe32.th32ProcessID);
                m_ProcessList.SetItemText(i, 2, str);
                //此进程开启的线程计数
                str.Format("%d", Pe32.cntThreads);
                m_ProcessList.SetItemText(i, 3, str);
                //父进程ID
                str.Format("%d", Pe32.th32ParentProcessID);
                m_ProcessList.SetItemText(i, 4, str);
                //线程优先权
                str.Format("%d", Pe32.pcPriClassBase);
                m_ProcessList.SetItemText(i, 5, str);

                i ++;
                bRet = Process32Next(hSnap, &Pe32);
        }
        CloseHandle(hSnap);
}

由于我希望刚打开程序,就行把系统的进程显示出来,因此要在OnInitDialog()中加入:

ShowProcess();

最后在头文件里加上:

void ShowProcess();

四、结束进程

通常情况下。进程正常结束时,会调用ExitProcess()函数来使自身退出。而假设想要结束指定的进程,则须要使用TerminateProcess()函数。可是对于进程的操作,往往都须要使用其PID值,为了方便起见。这里编写一个获取进程PID值的程序。以方便接下来对于进程的一系列操作。

它的原理就是在进程被枚举出来,显示在列表框中以后,返回所选取进程的“PID值”的内容:

int CProcessManageDlg::GetSelectPid()
{
        pid = -1;
        //获取列表框中所选中的位置
        POSITION Pos = m_ProcessList.GetFirstSelectedItemPosition();
        int nSelect = -1;
        while ( Pos )
        {
                nSelect = m_ProcessList.GetNextSelectedItem(Pos);
        }
        //假设在列表框中没有进行选择。则报错
        if ( -1 == nSelect )
        {
                AfxMessageBox("请选择进程!");
                return -1;
        }
        //获取列表框中显示的PID值
        char  szPid[10] = { 0 };
        m_ProcessList.GetItemText(nSelect, 2, szPid, 10);
        pid = atoi(szPid);

        return pid;
}

这个函数须要在头文件里声明:

int GetSelectPid();

然后为“结束进程”button加入代码:

void CProcessManageDlg::OnButtonTerminate()
{
        // TODO: Add your control notification handler code here
        int nPid = GetSelectPid();

        HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, nPid);

        TerminateProcess(hProcess, 0);

        CloseHandle(hProcess);

        ShowProcess();
}

上述代码的原理是先获取进程的权限,然后再进行结束。

五、暂停与恢复进程

有些时候,恶意程序为了保护自身,可能会创建两个或者多个进程。令其“荣辱与共”。

当当中一个进程发现还有一个进程被结束了,那么它就会把那个被结束的进程又一次执行起来。这几个进程相互帮助。所以就非常难把恶意程序的进程彻底结束掉。也就不能删除恶意程序本身。

遇到这样的情况。能够将这几个进程暂停,然后就能够结束掉恶意进程了。

暂停进程通常使用的是SuspendThread()函数,它须要使用线程的句柄。线程的句柄能够通过OpenThread()函数获得,然后利用Thread32First()以及Thread32Next()这两个函数进行枚举。

为“暂停进程”button加入代码:

void CProcessManageDlg::OnBtnStop()
{
        // TODO: Add your control notification handler code here
        int nPid = -1;
        nPid = GetSelectPid();
        //创建线程快照
        HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, nPid);
        if ( hSnap == INVALID_HANDLE_VALUE )
        {
                AfxMessageBox("暂停进程失败!

");
                return ;
        }

        THREADENTRY32 Te32 = { 0 };
        Te32.dwSize = sizeof(THREADENTRY32);
        BOOL bRet = Thread32First(hSnap, &Te32);

        while ( bRet )
        {
                //推断线程所属
                if ( Te32.th32OwnerProcessID == nPid )
                {
                        HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, Te32.th32ThreadID);

                        SuspendThread(hThread);

                        CloseHandle(hThread);
                }

                bRet = Thread32Next(hSnap, &Te32);
        }
}

因为CreateToolhelp32Snapshot()仅仅能创建系统的线程快照。不能创建指定进程中的线程的快照。所以假设想要暂停线程。必须对枚举到的线程进行推断。看其是否为指定进程中的线程。在THREADENTRY32这个结构体中的th32ThreadID标识了当前枚举到的线程的线程ID,而th32OwnerProcessID标识了该线程归属的进程的ID。所以在上述代码中须要进行推断。以找到对应的线程。

接下来为“恢复进程”button加入代码:

void CProcessManageDlg::OnButtonResume()
{
        // TODO: Add your control notification handler code here
        int nPid = -1;
        nPid = GetSelectPid();

        HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, nPid);
        if ( hSnap == INVALID_HANDLE_VALUE )
        {
                AfxMessageBox("进程恢复失败!

");
                return ;
        }

        THREADENTRY32 Te32 = { 0 };
        Te32.dwSize = sizeof(THREADENTRY32);
        BOOL bRet = Thread32First(hSnap, &Te32);

        while ( bRet )
        {
                if ( Te32.th32OwnerProcessID == nPid )
                {
                        HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, Te32.th32ThreadID);

                        ResumeThread(hThread);

                        CloseHandle(hThread);
                }

                bRet = Thread32Next(hSnap, &Te32);
        }
}

由于它与暂停进程原理同样,不再赘述。

六、程序效果

上述程序编译成功后,就行对进程实现结束、暂停与恢复的效果。



watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaW9pb19qeQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

图2 查看记事本进程

比方对一个“记事本”程序做实验。

打开记事本。执行本软件。找到记事本的进程,单击“暂停进程”button,可见尽管记事本程序仍可见,可是已无法对其操作。

直至单击“恢复进程”后,记事本才又恢复原样。然后单击“结束进程”,则记事本就被关闭,它已经从列表框中消失了。说明我们的程序是有效的。

 

七、小结

这次实现了一个简单的进程管理器程序,这类程序往往在手动查杀病毒方面有非常大的用处。也希望读者可以举一反三。在这个基础上开发出功能更加全面的程序出来。

时间: 2024-10-13 22:20:36

安全类工具制作第004篇:进程管理器(上)的相关文章

安全类工具制作第005篇:进程管理器(下)

一.前言 这次的程序是为了完好上一次所编写的进程管理器.使得当我们选中某一个进程的时候.能够查看其DLL文件,而且能够对可疑的模块进行卸载操作.这样就能够有效对抗DLL的恶意注入. 二.界面制作 这个界面是要依托于上一篇文章中制作的界面,须要单击上次界面中的"查看DLL"button来启动. 在上次的工作区中,找到VC6中菜单条的"Insert"选项.在其下拉菜单中选择"Resource-".在弹出的界面中选择"Dialog"

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

一.前言 服务是一种在操作系统启动的时候就会启动的进程.在操作系统启动时会有两种程序随着系统启动,一种是普通的Win32程序,另一种则是驱动程序.正是基于服务的这种特性,恶意程序往往也会将自身伪装成正常的服务来实现自启动.因此在反病毒的过程中,还是很有必要对服务项进行查看并管理的. 服务管理器的开发原理与之前所讨论的注册表管理器和进程管理器是类似的,主要也是枚举服务并将其显示在"List Control"控件中.而对于服务的管理,是通过服务相关的API函数来实现的.有了本系列之前几篇文

安全类工具制作第007篇:行为监控工具的开发

一.前言 现今的杀毒软件都会带有"行为监控"的功能.该功能可以在可疑进程被创建时,或者注册表敏感位置被写入时等情况下,给予用户以提示,让用户来选择是否对相应的可疑操作进行拦截,从而达到主动防御的目的.这样就可以避免传统杀软依靠特征码查杀病毒的滞后性.行为监控工具可以在恶意程序还未正式产生危害时,就将其扼杀. 在制作病毒专杀工具的时候,往往也会使用行为监控工具.比如由微软推出的大名鼎鼎的Process Monitor就是这类工具的典范.通过监控在虚拟机中运行的病毒的种种行为,来采取相应的

安全类工具制作第001篇:制作AutoRun.inf免疫程序

一.前言 我曾经在<反病毒攻防研究第006篇:利用WinRAR与AutoRun.inf实现自启动>那篇文章中讨论过AutoRun.inf的原理与应对方法,作为对这个问题的收尾,我打算在此讨论一下如何利用MFC开发一个简单的免疫程序.尽管如今我们应该已经不会再受到AutoRun.inf的肆虐,但是这其中包含的很多思想依旧值得探讨.需要强调的是,这篇文章的重点在于预防,也就是在还没有受到AutoRun.inf的威胁时该如何给自己的计算机打预防针.如果计算机中了AutoRun.inf的破坏,可参考反

安全类工具制作第002篇:U盘防火墙的制作

一.前言 我在上一篇文章中讨论了如何制作AutoRun.inf免疫程序,虽然这个免疫程序可以对所有的盘符有效,但是其实主要还是针对于U盘来进行防护的.由于目前新版的操作系统已经基本不支持AutoRun.inf,因此一般来说我们无需特别地关注这个问题.作为对U盘防御研究的收尾,这次我所讨论的是制作一个U盘防火墙.通过这个防火墙,当检测到有U盘插入时,则会产生提示,并且自动检查U盘中是否有AutoRun.inf文件,进行解析再进行删除操作,通过这个防火墙就可以安全地打开U盘. 其实现在很多杀毒软件都

FastCGI 进程管理器(FPM)

FPM(FastCGI 进程管理器)用于替换 PHP FastCGI 的大部分附加功能,对于高负载网站是非常有用的. 它的功能包括: 支持平滑停止/启动的高级进程管理功能: 可以工作于不同的 uid/gid/chroot 环境下,并监听不同的端口和使用不同的 php.ini 配置文件(可取代 safe_mode 的设置): stdout 和 stderr 日志记录; 在发生意外情况的时候能够重新启动并缓存被破坏的 opcode; 文件上传优化支持; "慢日志" - 记录脚本(不仅记录文

3 FastCGI 进程管理器(FPM)

1 FPM(FastCGI 进程管理器)用于替换 PHP FastCGI 的大部分附加功能,对于高负载网站是非常有用的. 它的功能包括: ● 支持平滑停止/启动的高级进程管理功能: ● 可以工作于不同的 uid/gid/chroot 环境下,并监听不同的端口和使用不同的 php.ini 配置文件(可取代 safe_mode 的设置): ● stdout 和 stderr 日志记录; ● 在发生意外情况的时候能够重新启动并缓存被破坏的 opcode; ● 文件上传优化支持; ● "慢日志"

JAVA版进程管理器

ProcessViewer.java 类,负责界面实现 import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import javax.swing.JButton; import javax.swing.JFrame; import j

PHPFastCGI进程管理器PHP-FPM详解

PHP-FPM是一个PHPFastCGI进程管理器,是只用于PHP的.      PHP-FPM其实是PHP源代码的一个补丁,旨在将FastCGI进程管理整合进PHP包中.必须将它patch到你的PHP源代码中,在编译安装PHP后才可以使用.      现在我们可以在最新的PHP 5.3.2的源码树里下载得到直接整合了PHP-FPM的分支,据说下个版本会融合进PHP的主分支去.相对Spawn-FCGI,PHP-FPM在CPU和内存方面的控制都更胜一筹,而且前者很容易崩溃,必须用crontab进行