金山开源:金山卫士开源软件之旅(十) KSafeMain工程的分析 1

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

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

 

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

欢迎大家提出问题讨论。

 1、超链接的加入

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

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

    

 

eg:

求助这个按钮:

<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\r\n", 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 。

 

 它的类定义很简单:

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);// 创建修复漏洞页面的viewInitVulFix();

 

它主要是加载界面元素,并创建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  按钮处理函数的实现

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

在 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)首先编译BeikeUtils工程。

会出现以下报错:

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


解决方法请参考我的另一篇文章:(里面有同样的出错的处理)

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

(2、2、1、2) 其它的工程都顺利编译通过,只有两个工程ksafevul、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;}

ksafevul工程编译通过后就生成了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)// 创建扫描组件IVulfixm_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) \n"), hr, dwFlags);m_pVulScan->SetObserver(NULL);}// 通知扫描完成_RelayMessage(hWnd, WMH_SCAN_DONE, m_bVulScanCanceled, hr);}


 

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

我也被这个问题困扰着,从KSafeMain工程中我们只能知道

hr = m_pVulScan->Scan(dwFlags);

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

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

(2、2、3、1)Scan的实现在VulfixLIb工程中(在上面的(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 Filterm_pFilterOS = CreateOSFilter(sysEnv.m_WinVer, dwFlags);// 初始化OS FilterInitOSFilter( 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 );}elsem_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("d-d-d"), date.nYear, date.nMonth, date.nDay);}WriteVulConfig(_T("VulScan"), _T("LastSafePkgDate"), strVal);}}hr = KERR_NONE;} while (FALSE);return hr;}


 

(2、2、3、2) 只需要把数据库文件拷到KSafeMain工程目录下即可得到扫描结果。

图一中的整个文件夹data拷到图二中即可

图一:

 

图二:

相关推荐

相关文章