上一次看金山开源到如今已有一两个月了。期间看到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
解决方法请參考我的还有一篇文章:(里面有相同的出错的处理)
(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拷到图二中就可以
图一:
图二: