zoukankan      html  css  js  c++  java
  • 安全类工具先创建007片:开发活动监控工具

    一个、前言

            今天的反病毒软件是具有“行为监控”功能。该功能能够在可疑进程被创建时,或者注冊表敏感位置被写入时等情况下。给予用户以提示。让用户来选择是否对对应的可疑操作进行拦截,从而达到主动防御的目的。

    这样就能够避免传统杀软依靠特征码查杀病毒的滞后性。行为监控工具能够在恶意程序还未正式产生危害时,就将其扼杀。

            在制作病毒专杀工具的时候,往往也会使用行为监控工具。比方由微软推出的大名鼎鼎的Process Monitor就是这类工具的典范。

    通过监控在虚拟机中执行的病毒的种种行为,来採取对应的对策,从而编写出专杀工具(基于真实病毒的专杀工具制作的整套流程,我会在以后的文章中具体讲述)。而我这次所编写的就是可以实现类似于Process Monitor的监控程序。

    当然。我这里更基本的是程序原理的论述。文章中实际编写出来的程序自然无法与Process Monitor相提并论(由于Process Monitor一方面应该是钩取了一些我们并不常见的函数,还有一方面它应该是运用了内核级的一些技术,这些会在我未来的文章中进行讨论)。当然我相信读者会对其不断完好,从而私人订制出一套自己的安全工具。

     

    二、行为监控的原理

            不论什么程序功能的实现,必定须要调用对应的API函数。因此。想要监測程序的行为。就须要对其调用的API函数进行钩取并分析。

    我之前的文章中主要讨论过两类HOOK技术。一个是Inline HOOK(详见《反病毒攻防研究第012篇:利用Inline HOOK实现主动防御》),还有一个是IAT HOOK技术(详见《逆向project第004篇:令计算器程序显示汉字(下)》)。通过这两种HOOK技术,就行对程序中的API函数实现拦截的操作。

    行为监控的原理就是对敏感API函数进行钩取,之后可以由用户选择是否进行拦截,这样就行预防恶意程序损害我们的系统。

            详细到本程序,为了讨论的简单起见。我这里只钩取用于进程创建的CreateProcess()这个API函数(大家能够根据本章所讲述的原理自行丰富程序的功能)。因为使用了HOOK,那么就必定要涉及DLL的编写。而为了能在全部基于消息的进程中注入我们的DLL,就必须使用Windows钩子。

            须要说明的是。我在《反病毒攻防研究第012篇:利用InlineHOOK实现主动防御》中所讲述的方法只针对于一个程序进行防御,可是这次我打算针对系统中的全部CreateProcess()函数进行钩取,这就须要使用Windows下全局钩取的方法。Windows提供的钩子许多,当中有一种类型的钩子很有用。那就是WH_GETMESSAGE这个类型的钩子。它能够很方便地将DLL文件注入到全部基于消息机制的程序中,从而实现DLL所编写的功能。

            经过上述分析就已经明白了。本程序的实现,须要编写一个DLL程序用于注入,再编写一个EXE程序用于前台的控制。

     

    三、DLL程序的编写

            这里须要创建一个简单的Win32Dynamic Link Library项目。并把之前所编写的“CInlineHOOK.h”和“CInlineHOOK.cpp”加入该项目中(详见《反病毒攻防研究第012篇:利用Inline HOOK实现主动防御》)。然后加入例如以下代码:

    // EasyPM.cpp : Defines the entry point for the DLL application.
    //
    
    #include "stdafx.h"
    #include "InlineHOOK.h"
    #include <stdio.h>
    
    #pragma data_seg(".shared")
    HHOOK g_hHook = NULL;
    HWND  g_ExeHwnd = NULL;
    #pragma data_seg()
    
    #pragma comment (linker, ".shared, RWS")
    
    extern "C" __declspec(dllexport) void SetHookOn(HWND hWnd);
    extern "C" __declspec(dllexport) void SetHookOff();
    
    CInlineHOOK CreateProcessWHook;
    
    HINSTANCE g_hInst = NULL;
    //定义一些常量用来标识类型。可根据程序的完好而添加这部分
    #define PM_CREATEPROCESS  0x00000001L
    //定义一个结构体,将该结构体的信息发送给用于载入DLL的EXE文件。并让EXE给出提示
    typedef struct _PM_INFO
    {
        WCHAR wProcessName[0x200];
        DWORD dwPMClass;
    }PM_INFO, *PPM_INFO;
    
    BOOL
    WINAPI
    MyCreateProcessW(
                   __in_opt    LPCWSTR lpApplicationName,
                   __inout_opt LPWSTR lpCommandLine,
                   __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes,
                   __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes,
                   __in        BOOL bInheritHandles,
                   __in        DWORD dwCreationFlags,
                   __in_opt    LPVOID lpEnvironment,
                   __in_opt    LPCWSTR lpCurrentDirectory,
                   __in        LPSTARTUPINFOW lpStartupInfo,
                   __out       LPPROCESS_INFORMATION lpProcessInformation
        )
    {
        PM_INFO sz = { 0 };
        if ( wcslen(lpCommandLine) != 0 )
        {
            wcscpy(sz.wProcessName, lpCommandLine);
        }
        else
        {
            wcscpy(sz.wProcessName, lpApplicationName);
        }
    
        sz.dwPMClass = PM_CREATEPROCESS;
    
        COPYDATASTRUCT cds = { NULL, sizeof(PM_INFO), (void *)&sz };
        BOOL bRet = FALSE;
    	// 注意FindWindow的第二个參数应填敲代码主窗体的"Caption"
    	// 这里的SendMessage()函数用来发送一个WM_COPYDATA消息,将结构体
    	// 传给了载入DLL的EXE程序,使EXE程序把对应的信息显示给用户。
        if ( SendMessage(FindWindow(NULL, "EasyPM"), WM_COPYDATA, GetCurrentProcessId(), (LPARAM)&cds) != -1 )
        {
            CreateProcessWHook.UnHOOK();
            bRet = CreateProcessW(lpApplicationName, lpCommandLine,
                        lpProcessAttributes, lpThreadAttributes,
                        bInheritHandles, dwCreationFlags,
                        lpEnvironment, lpCurrentDirectory, 
                        lpStartupInfo, lpProcessInformation);
            CreateProcessWHook.ReHOOK();
        }
        
        return bRet;
    }
    
    BOOL APIENTRY DllMain( HANDLE hModule, 
                           DWORD  ul_reason_for_call, 
                           LPVOID lpReserved
    					 )
    {
        switch ( ul_reason_for_call )
        {
        case DLL_PROCESS_ATTACH:
            {
                g_hInst = (HINSTANCE)hModule;
                CreateProcessWHook.HOOK("kernel32.dll", "CreateProcessW", (PROC)MyCreateProcessW);
                break;
            }
        case DLL_PROCESS_DETACH:
            {
                CreateProcessWHook.UnHOOK();
                if ( g_hHook != NULL )
                {
                    SetHookOff();
                }
                break;
            }
        }
    
        return TRUE;
    }
    
    // 钩子函数
    LRESULT CALLBACK GetMsgProc(
                                int code,       // hook code
                                WPARAM wParam,  // removal option
                                LPARAM lParam   // message
                                )
    {
        return CallNextHookEx(g_hHook, code, wParam, lParam);
    }
    
    void SetHookOn(HWND hWnd)
    {
        g_ExeHwnd = hWnd;
        // 安装WH_GETMESSAGE钩子用于监视被投递到消息队列中的消息
    	SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, g_hInst, 0);
    }
    
    void SetHookOff()
    {
        // 卸载钩子
    	UnhookWindowsHookEx(g_hHook);
        g_hHook = NULL;
    }
            以上就是所有DLL程序的代码,并不复杂。我已经加入了对应的凝视。大家能够在此基础上加入其他API函数的代码,以便更加全面地监控我们的系统。


     

    四、程序界面的制作

            本程序须要一个“List Control”和三个“Button”控件:


    图1 程序界面的制作

            然后为“List Control”控件加入一个名为“m_PMReports”的变量。为“启动”和“停止”button分别加入名为“m_BtnOn”和“m_BtnOff”的变量。并加入例如以下初始化代码:

    typedef void (*SETHOOKON)(HWND);
    typedef void (*SETHOOKOFF)();
    
    void CEasyPMDlg::InitPMReports()
    {
        m_PMReports.SetExtendedStyle(m_PMReports.GetExtendedStyle()
                                | LVS_EX_GRIDLINES);
    
        m_PMReports.InsertColumn(0, "序号");
        m_PMReports.InsertColumn(1, "时间");
        m_PMReports.InsertColumn(2, "进程");
        m_PMReports.InsertColumn(3, "类型");
    
        m_PMReports.SetColumnWidth(0, 40);
        m_PMReports.SetColumnWidth(1, 160);
        m_PMReports.SetColumnWidth(2, 200);
        m_PMReports.SetColumnWidth(3, 200);
    }
    
    void CEasyPMDlg::OnBtnOn() 
    {
        // TODO: Add your control notification handler code here
        m_hInst = LoadLibrary("EasyPM.dll");
        SETHOOKON SetHookOn = (SETHOOKON)GetProcAddress(m_hInst, "SetHookOn");
        
        SetHookOn(GetSafeHwnd());
        FreeLibrary(m_hInst);
        m_BtnOn.EnableWindow(FALSE);
        m_BtnOff.EnableWindow(TRUE);
    }
    
    void CEasyPMDlg::OnBtnOff() 
    {
        // TODO: Add your control notification handler code here
        m_hInst = GetModuleHandle("EasyPM.dll");
        SETHOOKOFF SetHookOff = (SETHOOKOFF)GetProcAddress(m_hInst, "SetHookOff");
        SetHookOff();
        CloseHandle(m_hInst);
        FreeLibrary(m_hInst);
        m_BtnOn.EnableWindow(TRUE);
        m_BtnOff.EnableWindow(FALSE);
    }
    
    void CEasyPMDlg::OnBtnClear() 
    {
        // TODO: Add your control notification handler code here
        m_PMReports.DeleteAllItems();
    }

            最后须要在对应的位置进行声明,这里不再赘述。


    五、主程序的编写

            主程序事实上就是主要用于接收DLL的消息。代码例如以下:

    #define PM_CREATEPROCESS  0x00000001L
    
    typedef struct _PM_INFO
    {
        WCHAR wProcessName[0x200];
        DWORD dwPMClass;
    }PM_INFO, *PPM_INFO;
    
    BOOL CEasyPMDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) 
    {
        // TODO: Add your message handler code here and/or call default
        WCHAR sz[2048];
        PPM_INFO pPMInfo = (PPM_INFO)pCopyDataStruct->lpData;
        wcscpy(sz,pPMInfo->wProcessName);
        
        int nNum = m_PMReports.GetItemCount();
        CString Str;
        //显示序号
        Str.Format("%d", nNum);
        m_PMReports.InsertItem(nNum, Str);
        //获取系统时间
        SYSTEMTIME StTime;
        GetLocalTime(&StTime);
        Str.Format("%04d/%02d/%02d %02d:%02d:%02d",
                StTime.wYear,
                StTime.wMonth,
                StTime.wDay,
                StTime.wHour,
                StTime.wMonth,
                StTime.wSecond);
        //显示时间
        m_PMReports.SetItemText(nNum, 1, Str);
        //显示进程名称。注意由于这里是宽字符,所以要用大写的S
        Str.Format("%S", sz);
        m_PMReports.SetItemText(nNum, 2, Str);
        //显示类型,能够根据钩取函数的添加而完好case语句
        switch ( pPMInfo->dwPMClass )
        {
        case PM_CREATEPROCESS:
            {
                Str = "进程创建(CreateProcess)";
                break;
            }
        }
        m_PMReports.SetItemText(nNum, 3, Str);
    
        return CDialog::OnCopyData(pWnd, pCopyDataStruct);
    }
            这部分代码就是对WM_COPYDATA消息的一个响应。这些代码基本就是对界面进行了操作。

    由于使用的消息映射。所以还需在对应的位置进行声明,首先是在BEGIN_MESSAGE_MAP(CEasyPMDlg, CDialog)下加入:

    ON_WM_COPYDATA()
            最后在头文件“EasyPMDlg.h”中的“//{{AFX_MSG(CEasyPMDlg)”下加入:
    afx_msg BOOL OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct);

            以上就是所有代码。完毕后就能够编译链接了。执行时不要忘了将之前编写的“EasyPM.dll”放在和本EXE程序同一文件夹下。

     

    六、程序的測试

            这里我先执行本程序。单击界面中的“启动”button,然后依次打开“记事本”、“绘图”和“计算器”程序,例如以下图所看到的:


    图2 监控启动的程序
            可见,我们的程序已经成功监控了全部打开的程序。

    这里须要说明的是。第4个程序是我用于截图的QQ截图工具。

    七、小结

            我们的代码并不能监控到全部的进程,并且我们的程序也过于简单,非常easy被恶意程序所突破。不过这个程序不过一个雏形,我在此希望能够起到抛砖引玉的作用。此过程还可以增加拦截的过程的功能。感兴趣的读者可以自行完好。

    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    Redis五种数据类型操作命令
    MySQL单表数据量过千万,采坑优化记录,完美解决方案
    并行的执行效率一定高于串行吗?(多线程的执行效率一定高于单线程吗?)
    Swagger2安装及使用
    MySQL单表多次查询和多表联合查询,哪个效率高?
    Java集合时间复杂度
    JAVA中常见集合的扩容
    ant design vue 之 rowKey浏览器报警告
    ant design vue中表格自带分页如何使用
    ant design vue 中表格的使用中,表格选中之后没有状态
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/4630115.html
Copyright © 2011-2022 走看看