65.9K
CodeProject 正在变化。 阅读更多。
Home

一个VB.NET应用程序,用于修复Visual Basic 6 OCX安全问题

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (7投票s)

2011年10月27日

CPOL

3分钟阅读

viewsIcon

34818

downloadIcon

757

一个多线程应用程序,用于识别系统中的VB6 OCX文件是否存在漏洞,并生成一个批处理文件来注册更新后的OCX控件。

引言

我开发了一个多线程的Visual Basic 2010应用程序,用于验证Microsoft的安全问题(MS08-070:Visual Basic 6.0 Runtime Extended Files(ActiveX控件)中的漏洞可能允许远程代码执行)是否存在于计算机上。

该应用程序会同时检查已注册的ActiveX控件和存在于文件系统中(但未注册)的ActiveX控件。Microsoft建议您联系软件开发商(安装了这些易受攻击的ActiveX控件的开发商),并请求一个更新的软件包(将安装更新的ActiveX控件)。您如何知道是哪个软件安装了ActiveX控件?为什么不能只更新单个文件?

我的软件提供了一种简便的方法来检查您的系统并修复安全问题,而无需进行所有这些研究和重大的软件升级。

Verify_VB6_OCX.jpg

  1. 此应用程序显示了如何通过读取系统注册表来确定您的(32/64位操作系统)计算机上已注册了哪些ActiveX(OCX)文件。
  2. 提供了一个实用程序,用于解决许多计算机上存在的潜在安全问题。
  3. 演示了如何使用多线程同时读取注册表项并(通过System.Management)检查文件。
  4. 演示了如何让线程更新主窗体上的进度条和DataGridView
  5. 演示了如何根据数据录入,在添加DataGridView条目时应用样式以重新格式化(行颜色)。
  6. 演示了如何将文件嵌入到编译后的应用程序中,并在需要时提取文件。

这个解决方案解决了什么问题?

这个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日。
© . All rights reserved.