金山卫士开源软件之旅(十) 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
CEmbeddedViewm_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拷到圖二中就可以
圖一:
圖二:
總結
以上是生活随笔為你收集整理的金山卫士开源软件之旅(十) KSafeMainproject的分析 1的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RequireBusyDialog
- 下一篇: why my filter by tit