一个VB.NET应用程序,用于修复Visual Basic 6 OCX安全问题
一个多线程应用程序,用于识别系统中的VB6 OCX文件是否存在漏洞,并生成一个批处理文件来注册更新后的OCX控件。
- 下载VB 2010源代码,修订于2011年11月2日 - 3.47 MB
- 下载Visual Basic 6 OCX问题文档 - 273 KB
- 下载Why_this_software_was_developed.pdf - 73.7 KB
- 下载有关两个VB6 OCX更新的详细信息 - 86.2 KB
引言
我开发了一个多线程的Visual Basic 2010应用程序,用于验证Microsoft的安全问题(MS08-070:Visual Basic 6.0 Runtime Extended Files(ActiveX控件)中的漏洞可能允许远程代码执行)是否存在于计算机上。
该应用程序会同时检查已注册的ActiveX控件和存在于文件系统中(但未注册)的ActiveX控件。Microsoft建议您联系软件开发商(安装了这些易受攻击的ActiveX控件的开发商),并请求一个更新的软件包(将安装更新的ActiveX控件)。您如何知道是哪个软件安装了ActiveX控件?为什么不能只更新单个文件?
我的软件提供了一种简便的方法来检查您的系统并修复安全问题,而无需进行所有这些研究和重大的软件升级。
- 此应用程序显示了如何通过读取系统注册表来确定您的(32/64位操作系统)计算机上已注册了哪些ActiveX(OCX)文件。
- 提供了一个实用程序,用于解决许多计算机上存在的潜在安全问题。
- 演示了如何使用多线程同时读取注册表项并(通过
System.Management
)检查文件。 - 演示了如何让线程更新主窗体上的进度条和
DataGridView
。 - 演示了如何根据数据录入,在添加
DataGridView
条目时应用样式以重新格式化(行颜色)。 - 演示了如何将文件嵌入到编译后的应用程序中,并在需要时提取文件。
这个解决方案解决了什么问题?
这个Visual Basic(2010)实用程序允许系统管理员检查他们的系统是否存在易受攻击的VB6 ActiveX控件,并生成一个修复操作(一个批处理文件,用于注销易受攻击的OCX文件,重命名它,复制一个更新的{Microsoft签名的} OCX文件{该文件已从本实用程序中提取},并注册新的OCX文件)。无需猜测哪个应用程序安装了过时的OCX文件或升级现有软件。
代码是如何工作的?
该应用程序启动两个线程。第一个线程扫描注册表中已注册的OCX文件。
' Read registry thread
Private Sub Read_Reg()
' Give a name to identify the thread that creates the User Interface
Thread.CurrentThread.Name = "Read_Registry"
Dim x As Integer = 1 'starting count
Dim myAL As New ArrayList() ' holds initial raw registry data
myAL.Clear() 'clear initial raw registry data
Dim strProgID As String = String.Empty
Dim strInprocServer32 As String = String.Empty
Dim strVersion As String = String.Empty
Dim defaultValue As Array
If My.Computer.FileSystem.DirectoryExists("C:\Windows\SysWOW64") Then
'this is a 64 bit OS
'Get all key names
defaultValue = Registry.ClassesRoot.OpenSubKey("Wow6432Node\CLSID").GetSubKeyNames()
Else
'this is a 32 bit OS
'Get all key names
defaultValue = Registry.ClassesRoot.OpenSubKey("CLSID").GetSubKeyNames()
End If
Dim EntryCount As Integer = defaultValue.Length ' number of items to loop thru
添加了委托,以根据注册表计数初始化主窗体进度条,并在读取条目时对其进行更新。
' Delegate to initialize registry process bar (sets maximum)
Private Delegate Sub DelInitializePB(ByVal pMin As Integer, _
ByVal pMax As Integer, ByVal pValue As Integer)
' Delegate to advance registry process bar
Private Delegate Sub MethodInvoker(ByVal pVal As Integer)
' Initialize Progressbar (for Registry)
Private Sub InitializePB(ByVal pMin As Integer, _
ByVal pMax As Integer, ByVal pValue As Integer)
progressBar1.Minimum = pMin
progressBar1.Maximum = pMax
progressBar1.Value = pValue
End Sub
' Increment Progressbar (for Registry)
Private Sub IncrementPB(ByVal PVal As Integer)
If Me.progressBar1.InvokeRequired Then
Me.progressBar1.Invoke(New MethodInvoker(AddressOf IncrementPB), _
New Object() {PVal})
Else
progressBar1.Value = PVal
End If
End Sub
第二个线程扫描所有硬盘驱动器上的OCX文件。
' Read files thread
Private Sub Check_for_OCX_on_HD()
' Give a name to identify the thread that creates the User Interface
Thread.CurrentThread.Name = "Check_Drives_for_OCX"
'find local drive letters
Dim t2 As New System.Management.SelectQuery(_
"Select DeviceID from Win32_LogicalDisk Where drivetype = '3' ")
Dim r2 As New System.Management.ManagementObjectSearcher(t2)
Dim Drv_Name As System.Management.ManagementObject
Dim Drv_Ltrs As System.Management.ManagementObjectCollection = r2.Get()
Dim Drv_Ltrs_Count As Integer = Drv_Ltrs.Count
Dim DrvLtrArray As New ArrayList
For Each Drv_Name In Drv_Ltrs
DrvLtrArray.Add("Drive='" & _
Drv_Name("DeviceID").ToString & "'").ToString()
Next Drv_Name
' Display querying files
Count_File_Entry("(Querying Files)")
'create multiple drive letter str for next WMI query (if multiple drive letters)
Dim myArr4 As String() = CType(DrvLtrArray.ToArray(GetType(String)), String())
Dim DrvSearch As String = String.Join(" Or ", myArr4)
Dim q As New System.Management.SelectQuery("Select * from " & _
"CIM_DataFile Where Extension = 'ocx' and (" & DrvSearch & ")")
Dim s As New System.Management.ManagementObjectSearcher(q)
Dim OCX_Lst As System.Management.ManagementObjectCollection = s.Get()
Dim OCX_Count As Integer = OCX_Lst.Count
' display file count
Count_File_Entry("(Processing " & OCX_Count & " Files)")
添加了委托,以允许线程将行添加到主窗体上的DataGridView
中。
' Add row to Reg_DataGridView (for Reg)
Private Sub AddRow_2_Reg_DataGridView(ByVal This_Key As String, _
ByVal OCX_Ver As String, ByRef OCXPath As String)
If Me.Reg_DataGridView.InvokeRequired Then
Me.Reg_DataGridView.Invoke(New add_2_Reg_DataGridView(AddressOf _
AddRow_2_Reg_DataGridView), New Object() {This_Key, OCX_Ver, OCXPath})
Else
Reg_index = Reg_DataGridView.Rows.Add(This_Key, OCX_Ver, OCXPath)
'Scroll to the last row.
Me.Reg_DataGridView.FirstDisplayedScrollingRowIndex = Me.Reg_DataGridView.RowCount - 1
Me.Reg_DataGridView.Update()
End If
End Sub
本次修订的更改
2010年11月2日
修改了Read_Reg
子程序(旧行316-341)。
我现在检查注册表项,并在尝试读取注册表值之前测试是否存在空条目。旧代码中曾抛出许多空指针异常。我还将在读取注册表项后将其关闭。
旧代码
For Each subKeyName As String In defaultValue 'regKey.GetSubKeyNames()
strProgID = String.Empty
Try
If My.Computer.FileSystem.DirectoryExists("C:\Windows\SysWOW64") Then
'this is a 64 bit OS
strProgID = Registry.ClassesRoot.OpenSubKey("Wow6432Node\CLSID\" & _
subKeyName & "\ProgID").GetValue("").ToString()
Else
'this is a 32 bit OS
strProgID = Registry.ClassesRoot.OpenSubKey("CLSID\" & _
subKeyName & "\ProgID").GetValue("").ToString()
End If
Catch ex As Exception
End Try
strInprocServer32 = String.Empty
Dim InprocServer32_Path As String = String.Empty
Try
If My.Computer.FileSystem.DirectoryExists("C:\Windows\SysWOW64") Then
'this is a 64 bit OS
InprocServer32_Path = Registry.ClassesRoot.OpenSubKey("Wow6432Node\CLSID\" & _
subKeyName & "\InprocServer32").GetValue("").ToString()
Else
'this is a 32 bit OS
InprocServer32_Path = Registry.ClassesRoot.OpenSubKey("CLSID\" & _
subKeyName & "\InprocServer32").GetValue("").ToString()
End If
strInprocServer32 = System.IO.Path.GetFullPath(InprocServer32_Path)
'Expand any short names
Catch ex As Exception
End Try
新代码
For Each subKeyName As String In defaultValue
strProgID = String.Empty
Try
If My.Computer.FileSystem.DirectoryExists("C:\Windows\SysWOW64") Then
'this is a 64 bit OS
' Check the registry entry before trying to read the value (entry could be a null)
Using key As RegistryKey = _
Registry.ClassesRoot.OpenSubKey("Wow6432Node\CLSID\" & _
subKeyName & "\ProgID")
' if null returned, don't try to get the value
If key IsNot Nothing Then
' get registry value and close the registry entry
strProgID = key.GetValue("").ToString()
key.Close()
End If
End Using
Else
'this is a 32 bit OS
' Check the registry entry before trying to read the value (entry could be a null)
Using key As RegistryKey = Registry.ClassesRoot.OpenSubKey("CLSID\" & subKeyName & "\ProgID")
' if null returned, don't try to get the value
If key IsNot Nothing Then
' get registry value and close the registry entry
strProgID = key.GetValue("").ToString()
key.Close()
End If
End Using
End If
Catch ex As Exception
End Try
关注点
我在开发此应用程序时学到了很多东西,并且始终欢迎改进代码的意见。这是我的第一个多线程应用程序。也是我第一个嵌入资源(新的OCX文件)并在需要时提取它们的应用程序。
首次应用样式来格式化DataGridView
行(根据非VB6 OCX、易受攻击的OCX、当前OCX来着色行)。
我使用此实用程序检查了至少80台计算机,其中大部分都有一些需要更新的VB6 OCX文件。请阅读本文开头处的PDF文档,了解该软件的使用方法。编译后的实用程序只有大约8MB,尽管它嵌入了26个VB6 OCX文件作为资源。由于发布文件大小限制,编译后的实用程序未包含在源代码中。
历史
- 版本1发布于2011年10月23日。
- 版本2发布于2011年11月2日。