Widnows补丁检测最基本的方法还是通过微软自己提供的相关接口来实现比较好。这里用到得也就是Windows Update Agent API了,Windows Update Agent API其实属于COM接口,不过可以通过VB,VC,.net等来调用,这里我选择用C调用。当然是用VB比较简单微软也给出了范例,也就几十行代码就搞定的事情。不过c++实现的范例国内的资料基本没有, 以下只是我参考MSDN的一些学习笔记,当然对于这个你们也可以自己参考MSDN的得到,不足之处还请指出。并附上一段简单的调用代码。
1 WUA API中各类直接的关系。
WUA API中存在以下接口:
要使用IUpdateSearcher、IUpdateDownloader、IUpdateInstaller、WebProxy等类必须先建立
IUpdateSession对象。这里所有类的属性基本上都有Get操作,部分是Put操作。
而IUpdateSession则必须通过com来产生一个实例。
2 要想获得补丁的信息先得通过IUpdateSearcher接口进行查询。
2.1 IUpdateSearcher接口的使用方法。
主要调用IUpdateSearcher.Search方法,进行同步查询。
HRESULT Search(
[in] BSTR criteria,
[out] ISearchResult **retval
);
其中BSTR criteria是我们的查询条件字符串,其格式和SQL语句的条件类似,
支持And或Or等逻辑运算,以及=、!=等运算。
通常我们关心的criteria查询条件有:Type、IsInstalled、IsHidden等,其他的条件可以参考:
http://msdn.microsoft.com/en-us/library/aa386526(VS.85).aspx。
Type 是String类型,指查询更新的类型,如"'Driver'"和"'Software'"。
IsInstalled 是int类型,指查询更新的补丁是否已经安装。
criteria = "Type = 'Software' and IsInstalled = 0";
查询的返回结果是ISearchResult类型,下面我们再来看ISearchResult接口。
2.2 ISearchResult接口的使用方法。
ISearchResult接口有四个属性,ResultCode、RootCategories、Updates、Warnings,这里我们关心的是
Updates这个属性。
Updates属性包含了我们查询更新后的结果的接口集。
ISearchResult::Updates
Updates有get_Updates这个方法,来进一步返回数据。
HRESULT get_Updates(
[out] IUpdateCollection **retval
);
ISearchResult::Updates.get_Updates();
这其中使用到了IUpdateCollection类来存放结果,下面我们在来看IUpdateCollection接口的使用。
2.3 IUpdateCollection接口的使用方法。
IUpdateCollection有5个方法,Add,Clear,Copy,Insert,RemoveAt。不过这些方法不是我们现在关心的。
我们关心的是它的另外四个属性,_NewEnum、Count、Item、ReadOnly。
其中Count指的是返回的满足我们的跟新查询条件的结果的记录个数。
Item则是进一步的存放了我们需要的信息。
Item属性有有两个对应的操作,put和get,可以用来修改或取得信息。
HRESULT put_Item(
[in] long index,
[in] IUpdate *value
);
HRESULT get_Item(
[in] long index,
[out] IUpdate **retval
);
IUpdateCollection::Item.get_Item();方法可以取出查询结果记录中第i条记录的值,当然了这里的值又是
以IUpdate类的形式存放的,下面我们在继续看IUpdate类的使用方法。
2.4 IUpdate接口的使用方法。
到了 IUpdate我们的追寻才算终止, IUpdate类里面包括了我们需要的关于系统补丁的各种信息:补丁号、补丁描述
补丁安全等级、补丁下载地址以及该补丁的相关信息等信息。这里我们只关心上面这些数据,至于其他的你可以参考http://msdn.microsoft.com/en-us/library/aa386099(VS.85).aspx。
SecurityBulletinIDs 安全公告ID
SupportUrl 漏洞相关信息
HRESULT get_SupportUrl(
[out] BSTR *retval
);
IUpdate::SupportUrl.get_SupportUrl()
MsrcSeverity 漏洞等级
HRESULT get_MsrcSeverity(
[out] BSTR *retval
);
IUpdate::MsrcSeverity.get_MsrcSeverity()
DownloadContents 下载内容(注:在BundledUpdates包含IUpdateCollection对象的情况下无法使用DownloadContents获得下载地址)
HRESULT get_DownloadContents(
[out] IUpdateDownloadContentCollection **retval
);
IUpdate::DownloadContents.get_DownloadContents(),
其中补丁下载地址的数据保存在IUpdateDownloadContentCollection类的对象中。
下面我们来看IUpdateDownloadContentCollection类的使用。其他的属性操作请自己参考
http://msdn.microsoft.com/en-us/library/aa386099(VS.85).aspx
2.5 IUpdateDownloadContentCollection类的使用
同样IUpdateDownloadContentCollection类也有_NewEnum、Count、Item三个属性,
Item是我们关心的内容。
IUpdateDownloadContentCollection::Item.get_Item()
HRESULT get_Item(
[in] long index,
[out] IUpdateDownloadContent **retval
);
我们需要的补丁下载地址又进一步放在了IUpdateDownloadContent类的对象当中。
这里面又涉及到了一个新的类IUpdateDownloadContent。
2.6 IUpdateDownloadContent类的使用
到了这里应该是我们获取补丁下载地址的一个终结了,使用IUpdateDownloadContent类的
DownloadUrl属性即可获得下载URL了。
HRESULT get_DownloadUrl(
[out] BSTR *retval
);
IUpdateDownloadContent::DownloadUrl.get_DownloadUrl()
3 创建IUpdateSearcher类的对象。
3.1 使用IUpdateSession::CreateUpdateSearcher方法创建。
HRESULT CreateUpdateSearcher(
[out] IUpdateSearcher **retval
);
3.2关于IUpdateSession类的使用
IUpdateSession类有CreateUpdateDownloader、CreateUpdateInstaller、CreateUpdateSearcher三个方法。
参考代码:
CODE:
//
//(2) 获取操作系统补丁信息(部分代码已经舍去)
// 使用Windows Update Agent API实现
// 使用离线检测的形式
BOOL GetSystemDefects(struct defects *system_defects)
{
int res = NO_ERROR;
HRESULT ret;
int flag = 1;
struct defects *p;
try
{
IUpdateSession *Session = NULL;
ret = CoInitialize(NULL);
if (FAILED(ret))
{
Log("GetSystemDefects():Initializes the COM Failed.");
throw -1;
}
ret = CoCreateInstance(CLSID_UpdateSession, NULL, CLSCTX_INPROC_SERVER,
IID_IUpdateSession , (LPVOID*)&Session);
if ((Session == NULL) || FAILED(ret))
{
//return -1;
throw -2;
}
IUpdateSearcher *Searcher = NULL;
ret = Session->CreateUpdateSearcher(&Searcher);
if (FAILED(ret) || (Searcher == NULL))
{
Session->Release();
//return -1;
throw -3;
}
Searcher->put_Online(VARIANT_FALSE); //离线查询
// Searcher->put_Online(VARIANT_TRUE); //在线查询
ISearchResult *SearchResult = NULL;
ret = Searcher->Search(_bstr_t("IsInstalled = 0 and Type = 'Software'"), &SearchResult);
if (FAILED(ret))
{
Searcher->Release();
Session->Release();
//return -1;
throw -4;
}
IUpdateCollection *Collection;
ret = SearchResult->get_Updates(&Collection);
if (FAILED(ret) || Collection == NULL)
{
Log("//");
Log("GetSystemDefects():failed to call ISearchResult::Updates!");
Log("//");
//return 0;
throw -5;
}
long Colnum;
long i = 0;
long j = 0;
Collection->get_Count(&Colnum);
if (Colnum < 0)
{
//system_defects = NULL;
//printf("There are no appliable update./n");
}
else
{
//printf("Total update count:%d/n", Colnum);
}
for (i = 0; i < Colnum; i++)
{
IUpdate *Update;
ret = Collection->get_Item(i, &Update);
if (FAILED(ret) || Update == NULL)
{
Log("Collection->get_Item(i, &Update)");
throw -6;
}
BSTR Title = NULL;
ret = Update->get_Title(&Title);
//安全等级
//Critical Important Moderate Low
BSTR SecLevel = NULL;
ret = Update->get_MsrcSeverity(&SecLevel);
//Download Url
//
IUpdateDownloadContentCollection *DownloadUrlCol = NULL;
//获取安全公告号
IStringCollection *SBID = NULL;//安全公告号
ret = Update->get_SecurityBulletinIDs(&SBID);
BSTR SB = NULL;
if (SUCCEEDED(ret) && SBID != NULL)
{
long SBCount;
ret = SBID->get_Count(&SBCount);
SBID->get_Item(0, &SB);
}
//获取补丁号
IStringCollection *KBArticles = NULL;
ret = Update->get_KBArticleIDs(&KBArticles);
BSTR KB;
if (SUCCEEDED(ret) && KBArticles != NULL)
{
long KbCount;
ret = KBArticles->get_Count(&KbCount);
KBArticles->get_Item(0, &KB);
}
//Description
//
BSTR Description = NULL;
ret = Update->get_Description(&Description);
//
//ReleaseNote
BSTR ReleaseNote = NULL;
ret = Update->get_ReleaseNotes(&ReleaseNote);
//
//More information
IStringCollection *MoreInfo;
ret = Update->get_MoreInfoUrls(&MoreInfo);
BSTR MoreInfoUrl;
if (SUCCEEDED(ret) && MoreInfo != NULL)
{
long MICount;
ret = MoreInfo->get_Count(&MICount);
MoreInfo->get_Item(0, &MoreInfoUrl);
}
// 有安全公告号,才显示
if (SB != NULL)
{
wchar_t buffer[max_size];
memset(buffer, '/0', max_size);
//first record
if (flag)
{
//Title
char *Ttemp = _bstr_t(Title);
//sprintf(buffer, "%s", temp);
memcpy(system_defects->defects_name, Ttemp, strlen(Ttemp));
//Security Bulletin
memset(buffer, '/0', max_size);
swprintf(buffer, L"%s", SB);
// wprintf(L"%s/n", buffer);
memcpy(system_defects->defects_id, buffer, avg_size);
//Security Level
memset(buffer, '/0', max_size);
swprintf(buffer, L"%s", SecLevel);
// wprintf(L"%s/n", buffer);
memcpy(system_defects->defects_level, buffer, avg_size);
//Description
char *Dtemp = _bstr_t(Description);
memcpy(system_defects->defects_desc, Dtemp, strlen(Dtemp));
//KB
memset(buffer, '/0', max_size);
swprintf(buffer, L"KB%s", KB);
//wprintf(L"%s/n", buffer);
memcpy(system_defects->patch_name, buffer, avg_size);
//MoreInforUrl
memset(buffer, '/0', max_size);
swprintf(buffer, L"%s", MoreInfoUrl);
//wprintf(L"%s/n", buffer);
memcpy(system_defects->MoreInfoUrl, buffer, avg_size);
system_defects->next = NULL;
flag = 0;
}
else
{
//...
//...
}
}
}
Session->Release();
Searcher->Release();
SearchResult->Release();
CoUninitialize();
}catch(int err)
{
res = err;
printf("Error:%d, ret = %x/n", res, ret);
}
Log("Get system defects successed.");
return 1;
}
注:对BSTR的转换成char*的方法,网上的不太实用,没有成功,这里我使用_bstr_t类转换成功。