• 金山卫士开源软件之旅(十) KSafeMainproject的分析 1


     上一次看金山开源到如今已有一两个月了。期间看到QQ群里大家对它非常是热情。

    近期有时间想看看金山的主界面projectKSafeMain,自己水平有限,总结的东西浅显。但还是愿意拿来与大家分享。希望对大家有帮助。

    转载请标明是引用于 http://blog.csdn.net/chenyujing1234

    欢迎大家提出问题讨论。

     1、超链接的增加

    上图中红色标注的地方就是超链接的地方。

    它的实现是在dlgfile_header.xml文件里。

        

    eg:

    求助这个button:

    <link class="linktext5" pos="-238,6" href="http://www.ijinshan.com/safe/help.html?fr=client" crtext="FFFFFF">求助</link>

    标红色的部分表此控制的类型为 linktext5,它是定义在def_style.xml文件里.

    通过cursor节点的属性实现放上去有手的开关的功能。

    那么是哪里调用了此文件里呢?

    在bkwinres.rc2中有

    即,我们把此文件定义为509了。

    而在dlg_main.xml中对调用了ID为509的XML文件

    2、修复漏洞的实现

    2、1  界面创建方法

    首先绑定dlg_main.xml里的 <tabctrl id="136"

    在bkwinres.h中有

    #define IDC_TAB_MAIN                            136

    在beikesafemaindlg.h中有

        BK_NOTIFY_MAP(IDC_RICHVIEW_WIN)
            //BK_NOTIFY_ID_COMMAND(IDCANCEL, OnBkBtnClose)
            BK_NOTIFY_ID_COMMAND(IDC_BTN_SYS_CLOSE, OnBkBtnClose)
            BK_NOTIFY_ID_COMMAND(IDC_BTN_SYS_MAX, OnBkBtnMax)
            BK_NOTIFY_ID_COMMAND(IDC_BTN_SYS_MIN, OnBkBtnMin)
            BK_NOTIFY_TAB_SELCHANGE(IDC_TAB_MAIN, OnBkTabMainSelChange)
        BK_NOTIFY_MAP_END()

    BOOL CBeikeSafeMainDlg::OnBkTabMainSelChange(int nTabItemIDOld, int nTabItemIDNew)
    {
    
    	DEBUG_TRACE(L"Tab Change %d, %d
    ", nTabItemIDOld, nTabItemIDNew);
    
    	BOOL bRet = FALSE;
    
    	if (m_bFirstPageChange)
    	{
    		if (0 != nTabItemIDNew)
    		{
    			PostMessage(MSG_APP_DELAY_EXAM, FALSE);
    		}
    
    		m_bFirstPageChange = FALSE;
    	}
    
    
    
    	bRet = TRUE;
    	switch (nTabItemIDNew)
    	{
    	case 0:
    		if (m_bPage0NeverShowed)
    		{
    			PostMessage(MSG_APP_DELAY_NAVIGATE_IE);
    			PostMessage(MSG_APP_DELAY_EXAM, TRUE);
    
    			m_bPage0NeverShowed = FALSE;
    		}
    
    		break;
    
    	case 1:
    		break;
    
    	case 2:		
    		break;
    	case 3:    // 修复漏洞
    		m_viewVulfix.ShowWindow(SW_SHOW);
    		if(!m_bVulfixInited || m_bVulfixRescanRequired)
    		{
    			BOOL toRescan = TRUE;
    			if(m_bVulfixRescanRequired && theEngine && theEngine->m_isRepairing)
    			{
    				toRescan = FALSE;
    			}			
    			m_bVulfixInited = TRUE;
    			m_bVulfixRescanRequired = FALSE;
    			if(toRescan)
    				m_viewVulfix.m_viewSoftVul.InitEnv();
    		}
    		break;
    	case  4://系统优化
    	case  5://清理
    	case  6://网盾
    	case  8:// 打开软件管理
    	default:
    		break;
    	}
    
    	return TRUE;
    }
    
    
    
    
    
    
    


     能够得知近好改动漏洞后进入的case是:

     case 3:

    处理的第一条是 m_viewVulfix.ShowWindow(SW_SHOW);

    m_viewVulfix是CBeikeSafeMainDlg中的成员:

    // 修复漏洞页面里的view
     CEmbeddedView m_viewVulfix; 

    CEmbeddedView也CBeikeSafeMainDlg一样都是继承自CBkDialogViewImpl。

    每一个CBkDialogViewImpl的实例中都有三个成员,各自是m_bkHeader、m_bkBody和m_bkFooter,它们分别代表窗体的头部、中间和底部,

    它们各自界面元素的载入是在 CBkDialogViewImpl::Load 。

     它的类定义非常easy:

    class CEmbeddedView 
    	: public CBkDialogViewImpl<CEmbeddedView>
    	, public CIconAnimate<CEmbeddedView>
    {
    public:
    	//  做漏洞扫描动作的类
    	CBeikeVulfixHandler m_viewSoftVul;


    那么m_viewVulfix是在哪里创建的呢?

    (1) CBeikeSafeMainDlg::OnInitDialog 的一開始就初始化了这个变量
    BOOL CBeikeSafeMainDlg::OnInitDialog(CWindow /*wndFocus*/, LPARAM /*lInitParam*/)
    {
    
    	SetIcon(::LoadIcon((HMODULE)&__ImageBase, MAKEINTRESOURCE(IDI_BEIKESAFE)));
    	SetIcon(::LoadIcon((HMODULE)&__ImageBase, MAKEINTRESOURCE(IDI_SMALL)), FALSE);
    
    	_Module.SetActiveWindow(m_hWnd);
    	// 创建修复漏洞页面的view
    	InitVulFix();

    它主要是载入界面元素,并创建list控件.

    void CBeikeSafeMainDlg::InitVulFix()
    {
    	// 创建 m_viewVulfix 窗体
    	m_viewVulfix.Create(GetViewHWND(), NULL, WS_CHILD|WS_CLIPCHILDREN, 0, 3000);
    	// 从 dlg_vul_main.xml 文件里载入控件
    	ATLVERIFY( m_viewVulfix.Load( IDR_BK_VULDLG_MAIN ) );
    	// 设置修复漏洞处理逻辑类m_viewSoftVul的父窗体
    	m_viewVulfix.m_viewSoftVul.SetMainDlg( this );
    	// 创建列名为:严重程序、补丁名称、补丁描写叙述、发面日期、状态的列表控件
    	m_viewVulfix.Init(m_hWnd);
    }

    (2) dlg_vul_main.xml文件分析

    主要分为两大部分:

    扫描或修复状态扫描结果.

    从XML文件里能够看到 扫描中与repairing是同一块,临时把repairing隐藏起来。

     

    repairing有五个部分:

    2、2  button处理函数的实现

    扫描结果显示的效果图是:

    在 case 3:的处理中显示完界面后主要就是调用扫描漏洞的工作:

    if(toRescan)
        m_viewVulfix.m_viewSoftVul.InitEnv();

    它主要完毕 :

    初始化扫描引擎;

     载入ksafevul.dll中的API函数, 创建CVulEngine中的IVulEnvironment 接口;

    解发開始扫描的消息。

    void CBeikeVulfixHandler::InitEnv()
    {
    	if(!theEngine)
    	{
    		// 初始化扫描引擎
    		theEngine = new CVulEngine;	
    		// 载入ksafevul.dll中的API函数, 创建CVulEngine中的IVulEnvironment 接口
    		theEngine->_InitFunctions();
    
    		m_WinInfo.Init();
    		//m_WinInfo64 = IsWin64();
    	}
    	// 解发開始扫描的消息
    	PostMessage( WMH_SCAN_START, 0, 0);
    }
    (2、2、1)非常多人反映ksafevul.dll 载入不到。此dll的得到金山是提供源代码的。

    大家能够用VS2005打开 beikesafevul.sln

    (2、2、1、1)首先编译BeikeUtilsproject。

    会出现下面报错:

    1>d:自己的经验总结自己的经验总结金山开源osspcmanagersrcpublishcommon/registrywow.h(18) : error C2146: 语法错误 : 缺少“;”(在标识符“OpenKeyEx”的前面)
    1>d:自己的经验总结自己的经验总结金山开源osspcmanagersrcpublishcommon/registrywow.h(18) : error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int
    1>d:自己的经验总结自己的经验总结金山开源osspcmanagersrcpublishcommon/registrywow.h(19) : error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int
    


    解决方法请參考我的还有一篇文章:(里面有相同的出错的处理)

    金山卫士开源软件之旅(一) VS 2005环境下编译

    (2、2、1、2) 其他的project都顺利编译通过,仅仅有两个projectksafevul、VulfixLib出现报错:

    envutils.h(428) : error C3861: “IsWin64”: 找不到标识符

        它是用来推断系统是不是64位用的。

    既然源代码没有提供此函数,那么我们自己来实现吧:

    考虑到调用到此函数的cpp文件都包括了BeikeUtils.h文件,我决定在BeikeUtils 中加入此函数体

    BeikeUtils.h中加入

    // 推断是不是64位的系统
    // 返回值: TRUE 是64位系统;FALSE 不是64位系统
    BOOL IsWin64();
    


    BeikeUtils.cpp里加入

    BOOL IsWin64()
    {
    	#define IS_64BIT_OS (sizeof(void *) == 8)
    	return IS_64BIT_OS;
    }
    

    ksafevulproject编译通过后就生成了ksafevul.dll.这样大家就能够调试扫描漏洞与修复漏洞的过程了。

    (2、2、2) WMH_SCAN_START消息的回调函数例如以下:
    void CBeikeVulfixHandler::OnBkBtnScan()
    {
    	if(m_firstInited)
    	{
    		// Clean downloaded files 
    		BOOL bSave = BKSafeConfig::Get_Vulfix_SaveDownFile();
    		if( !bSave )
    			theEngine->m_fixLog.CleanFiles(FALSE, NULL);
    		m_firstInited = FALSE;
    		SetItemVisible(1015, !theEngine->IsSystemSupported());
    	}
    	// 把扫描结果列表清空
    	ResetListCtrl(m_wndListCtrlVul);
    	// 调用引擎起一线程開始扫描
    	if( theEngine->ScanVul( m_RefWin.m_hWnd ) )
    	{
    		// 界面处理
    		m_dwScanBeginTime = GetTickCount();
    		m_bScanStarted = FALSE;
    
    		m_nScanState = 0;
    		m_nTotalItem = 0;
    		m_nCurrentItem = 0;
    		_SetDisplayState(SCANSTATE_SCANNING);
    		_SetScanProgress( 0 );
    		m_RefWin.SetTimer(0, 200, NULL);
    		m_wndListCtrlVul.SetEmptyString(BkString::Get(IDS_VULFIX_5027));
    		m_RefWin.StartIconAnimate( IDC_IMG_VULFIX_SCAN_ANIMATION, IDC_PROGRESS_VULFIX_SCANNING, 300);
    		SetItemDWordAttribute(IDC_PROGRESS_VULFIX_SCANNING, "showpercent", 0);
    	}
    }


    以上基本的工作是调用ScanVul创建一线程完毕扫描

    bool CVulEngine::ScanVul(HWND hWnd)
    {
    	if(m_hThreadVulScan)
    		_SafeTerminateThread( m_hThreadVulScan, FALSE );
    
    	m_bVulScanCanceled = FALSE;
    	m_hThreadVulScan = CreateThread(NULL, 0, ThreadFunc_Scan, (void*)hWnd, 0, NULL);
    	return m_hThreadVulScan!=NULL;
    }


     

    DWORD WINAPI CVulEngine::ThreadFunc_Scan( LPVOID lpParam )
    {
    	HWND hWnd = (HWND)lpParam;
    	theEngine->_ScanVul(hWnd);	
    	return 0;
    }


     

    void CVulEngine::_ScanVul(HWND hWnd)
    {
    	DWORD dwFlags = _GetScanFlags();
    	CWindowVulfixObserver observer( hWnd);
    	if(!m_pVulScan)
    		// 创建扫描组件IVulfix
    		m_pVulScan = CreateVulFix();
    	
    	HRESULT hr = E_POINTER;
    	if(m_pVulScan)
    	{
    		// 设计扫描组件的观察者对象
    		m_pVulScan->SetObserver(&observer);
    		// 运行扫描(要持续一段时间)
    		hr = m_pVulScan->Scan(dwFlags);
    		DEBUG_TRACE(_T("CVulEngine::_ScanVul ScanVul %x(%x) 
    "), hr, dwFlags);
    		m_pVulScan->SetObserver(NULL);
    	}
    	// 通知扫描完毕
    	_RelayMessage(hWnd, WMH_SCAN_DONE, m_bVulScanCanceled, hr);
    }
    


     

    (2、2、3)  DLL也载入到了,为什么修复漏洞不是没有扫描的结果呢。

    我也被这个问题困扰着,从KSafeMainproject中我们仅仅能知道

    hr = m_pVulScan->Scan(dwFlags);

    返回了失败.所以没有扫描结果。

    但原因是什么呢?我决定对此打破砂锅。

    (2、2、3、1)Scan的实如今VulfixLIbproject中(在上面的(2、2、1)中讲到)

    说是扫描,事实上是 从数据库文件 office64.dat、office.dat、soft.dat、system64.dat、system.dat中读取漏洞列表

    看到这里更坚定了我对对金山的开源的失望是对的。

    //  从数据库文件 office64.dat、office.dat、soft.dat、system64.dat、system.dat中读取漏洞列表
    HRESULT CImplVulfix::Scan(DWORD dwFlags)
    {
    	TIME_CHECK( _T("CImplVulfix::Scan ") );
    	m_Canceled = FALSE;
    	T_ComInit __init__com__;
    	HRESULT hr ; 	
    	do
    	{
    		// 把数据库和补丁列表清除
    		Reset();
    		GetLangID();
    		
    		CSysEnv& sysEnv = singleton<CSysEnv>::Instance();
    		sysEnv.Init();
    		if( FAILED( hr=sysEnv.IsSupported(FALSE) ) )
    			break;
    		
    		Init();
    		m_objIgnore.LoadIgnoreDB();
    
    		CString filenameSystem, filenameOffice, filenameSoft;
    		GetXmlDBFileName(VTYPE_WINDOWS, filenameSystem, IsWin64());
    		GetXmlDBFileName(VTYPE_OFFICE, filenameOffice, FALSE);
    		GetXmlDBFileName(VTYPE_SOFTLEAK, filenameSoft, FALSE);
    		if( !PathFileExists(filenameSystem) && !PathFileExists(filenameOffice) && !PathFileExists(filenameSoft) )
    		{
    			hr = KERR_LOAD_FILE;
    			break;
    		}
    		// 创建OS Filter
    		m_pFilterOS = CreateOSFilter(sysEnv.m_WinVer, dwFlags);
    		// 初始化OS Filter
    		InitOSFilter( m_pFilterOS, sysEnv.m_WinVer, dwFlags);
    		if( m_pFilterOS->WaitComplete() )
    		{
    			// 设计数据库对象的观察者
    			m_dbOS.SetObserver( m_Observer );
    			m_dbOffice.SetObserver( m_Observer );
    			m_dbSoft.SetObserver( m_Observer );
    			m_pFilterOS->SetIIgnore( &m_objIgnore );
    			
    			CString filename;
    			try
    			{
    				FixLocale();
    
    				//BOOL bWin64 = IsWin64();
    				//PVOID OldValue = NULL;
    				//if(bWin64)
    				//	Wow64DisableWow64FsRedirection(&OldValue);
    				
    				// 从data目录里的文件加载数据库数据
    				!m_Canceled && m_dbOffice.Load( filenameOffice, m_pFilterOS, dwFlags );
    				!m_Canceled && sysEnv.IsLangSupported() && sysEnv.IsOsSupported() && m_dbOS.Load( filenameSystem, m_pFilterOS, dwFlags );
    				!m_Canceled && m_dbSoft.Load( filenameSoft, NULL, dwFlags);
    
    				//if(bWin64)
    				//	Wow64RevertWow64FsRedirection(OldValue);
    			}
    			catch (...)
    			{
    				hr = KERR_LOAD_FILE;
    			}
    			
    			CSimpleArray<LPTUpdateItem> arrLeaks;
    			CSimpleArray<TReplacedUpdate*> arrReplaced;		
    			// 从数据库中获得列表 
    			m_dbOS.GetUnfixedLeakList( arrLeaks, m_arrFixedVuls, m_arrInvalid, arrReplaced );
    			m_dbOffice.GetUnfixedLeakList( arrLeaks, m_arrFixedVuls, m_arrInvalid, arrReplaced );
    
    			const CSimpleArray<int> &arrExpired = m_dbOS.GetExpiredIds();
    			CSimpleArray<int> arrReplacedId;
    			for(int i=0; i<arrReplaced.GetSize(); ++i)
    			{
    				arrReplacedId.Add( arrReplaced[i]->nKBID );
    			}
    			
    			// select soft ignored vuls 
    			CSimpleArray<LPTVulSoft> arrSoftLeaks;
    			m_dbSoft.GetUnfixedLeakList( arrSoftLeaks );
    			for(int i=0; i<arrSoftLeaks.GetSize(); ++i)
    			{
    				LPTVulSoft ps = arrSoftLeaks[i];
    				ps->isIgnored = m_objIgnore.IsIgnored( ps->nID );
    				if( ps->isIgnored )
    				{
    					LPTUpdateItem pu = new TUpdateItem;
    					pu->m_nType = VTYPE_SOFTLEAK;
    					pu->nID = ps->nID;
    					pu->strName = ps->matchedItem.strName;
    					pu->strDescription = ps->strDescription;
    					pu->strWebpage = ps->matchedItem.strWebpage;
    					pu->nWarnLevel = ps->nLevel;
    					pu->strPubdate = ps->strPubdate;
    
    					m_arrIgnoredVuls.Add( pu );
    					m_arrIgnoredVulsFromSoft.Add( pu );
    				}
    				else
    					m_arrSoftLeaks.Add( ps );
    			}
    			
    			// select installable, ignored , expired 
    			for(int i=0; i<arrLeaks.GetSize(); ++i )
    			{
    				LPTUpdateItem &pi = arrLeaks[i];
    				pi->isExpired = arrExpired.Find( pi->nID )!=-1;
    
    				if(pi->isExpired)
    					m_arrInvalid.Add( pi );
    				else if(pi->isIgnored)
    					m_arrIgnoredVuls.Add( pi );
    				else
    				{
    					bool bReplaced = arrReplacedId.Find( pi->nID )!=-1;
    					if(!bReplaced)
    						m_arrLeaks.Add( pi );
    				}
    			}
    			
    			// find correct replace relationship 
    			for(int i=0; i<arrReplaced.GetSize(); ++i)
    			{
    				TReplacedUpdate* pu = arrReplaced[i];
    				BOOL bInstalled = FindArrayIndex( m_arrFixedVuls, pu->nKBID )!=-1;
    				if( !bInstalled )
    				{
    					if( FindArrayIndex(m_arrFixedVuls, pu->nKBID2)!=-1 
    						|| FindArrayIndex(m_arrLeaks, pu->nKBID2)!=-1
    						|| FindArrayIndex(m_arrIgnoredVuls, pu->nKBID2)!=-1 )
    						m_arrReplacedUpdates.Add( pu );
    				}
    			}
    
    			// - 保存最后无漏洞时间, 使得下次不再提示有风险 
    			// -- 非高速扫描的结果才有效果 
    			if( RequireUsingInterface() && !(dwFlags & VULSCAN_EXPRESS_SCAN) )
    			{
    				BOOL hasMustLeak = FALSE;
    				const CSimpleArray<LPTUpdateItem> &arrLeaks = GetResults();
    				for(int i=0; i<arrLeaks.GetSize(); ++i)
    				{
    					if(arrLeaks[i]->nWarnLevel>0)
    					{
    						hasMustLeak = TRUE;
    						break;
    					}
    				}
    				CString strVal;
    				if(!hasMustLeak)
    				{
    					T_Date date;
    					GetLatestPackgeDate(date.nYear, date.nMonth, date.nDay);
    					strVal.Format(_T("%04d-%02d-%02d"), date.nYear, date.nMonth, date.nDay);
    				}
    				WriteVulConfig(_T("VulScan"), _T("LastSafePkgDate"), strVal);
    			}			
    		}
    		
    		hr = KERR_NONE;
    	} while (FALSE);
    	return hr;
    }
    


     

    (2、2、3、2) 仅仅须要把数据库文件拷到KSafeMainproject文件夹下就可以得到扫描结果。

    图一中的整个目录data拷到图二中就可以

    图一:

    图二:

  • 相关阅读:
    React 事件机制
    EggJs学习 (一)
    css 选择器及样式属性
    css盒子模型
    ES5 继承方式
    正则表达式
    Flex布局
    npm
    深拷贝、浅拷贝
    Webpack实战(入门、进阶与调优)
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4093432.html
Copyright © 2020-2023  润新知