Malicious Office (OLE) — malware analysis report

Static analysis result for SHA-256 d252a7865009a563…

MALICIOUS

Office (OLE)

285.2 KB Created: 2003-06-26 01:30:00 Authoring application: Microsoft Office Word First seen: 2020-09-24
MD5: f948c79de272835d2e98ccfe5c6955fe SHA-1: 589e2b564d9bcc6f806474df1c9e6980c18afa8e SHA-256: d252a7865009a56346547150ac134b82dafd755034a733db94d062372e68ebc2
190 Risk Score

Malware Insights

MITRE ATT&CK
T1059.005 Visual Basic T1059 Command and Scripting Interpreter T1203 Exploitation for Client Execution

The sample is a malicious Office document containing VBA macros. The critical OLE_VBA_SHELL heuristic indicates the presence of a Shell() call within the VBA code, which is commonly used to execute arbitrary commands or download and run secondary payloads. The presence of heap spray and CreateObject heuristics further suggests exploitation or malicious code execution. No specific family could be identified.

Heuristics 7

  • VBA macros detected medium 3 related findings OLE_VBA_MACROS
    Document contains VBA macro code
  • Potential Shell call in VBA critical OLE_VBA_SHELL
    Potential Shell call in VBA
    Matched line in script
    ' registry paths to User Shell Folders and Conversion Wizard settings
    Global Const strREG_PERFORM_BATCH = "Software\Microsoft\Office\8.0\Word\Wizards\Conversion Wizard"
  • CreateObject call high OLE_VBA_CREATEOBJ
    CreateObject call
    Matched line in script
        Set docWizard = ActiveDocument
        Set oWord = CreateObject("word.application")
        oWord.Visible = False
  • AutoOpen macro low OLE_VBA_AUTOOPEN
    AutoOpen macro
    Matched line in script
    Attribute VB_Name = "AutoOpen"
    Sub Main()
  • Heap-spray pattern detected high SC_HEAP_SPRAY
    Repeated 0x06 bytes found
    Disassembly
    Attempted x86 opcode disassembly
    00038062  06                push es
    00038063  06                push es
    00038064  06                push es
    00038065  06                push es
    00038066  06                push es
    00038067  06                push es
    00038068  06                push es
    00038069  06                push es
    0003806A  06                push es
    0003806B  06                push es
    0003806C  06                push es
    0003806D  06                push es
    0003806E  06                push es
    0003806F  06                push es
    00038070  06                push es
    00038071  06                push es
    00038072  06                push es
    00038073  06                push es
    00038074  06                push es
    00038075  06                push es
    00038076  06                push es
    00038077  06                push es
    00038078  06                push es
    00038079  06                push es
    0003807A  06                push es
    0003807B  06                push es
    0003807C  06                push es
    0003807D  06                push es
    0003807E  06                push es
    0003807F  06                push es
    00038080  06                push es
    00038081  06                push es
    00038082  06                push es
    00038083  06                push es
    00038084  06                push es
    00038085  06                push es
    00038086  06                push es
    00038087  06                push es
    00038088  06                push es
    00038089  06                push es
    0003808A  06                push es
    0003808B  06                push es
    0003808C  06                push es
    0003808D  06                push es
    0003808E  06                push es
    0003808F  06                push es
    00038090  06                push es
    00038091  06                push es
    00038092  06                push es
    00038093  06                push es
    00038094  06                push es
    00038095  06                push es
    00038096  06                push es
    00038097  06                push es
    00038098  06                push es
    00038099  06                push es
    0003809A  06                push es
    0003809B  06                push es
    0003809C  06                push es
    0003809D  06                push es
    0003809E  06                push es
    0003809F  06                push es
    000380A0  06                push es
    000380A1  06                push es
    000380A2  06                push es
    000380A3  06                push es
    000380A4  06                push es
    000380A5  06                push es
    000380A6  06                push es
    000380A7  06                push es
    000380A8  06                push es
    000380A9  06                push es
    000380AA  06                push es
    000380AB  06                push es
    000380AC  06                push es
    000380AD  06                push es
    000380AE  06                push es
    000380AF  06                push es
    000380B0  06                push es
    000380B1  06                push es
    000380B2  06                push es
    000380B3  06                push es
    000380B4  06                push es
    000380B5  06                push es
    000380B6  06                push es
    000380B7  06                push es
    000380B8  06                push es
    000380B9  06                push es
    000380BA  06                push es
    000380BB  06                push es
    000380BC  06                push es
    000380BD  06                push es
    000380BE  06                push es
    000380BF  06                push es
    000380C0  06                push es
    000380C1  06                push es
  • Legacy WordBasic auto-exec macro marker medium OLE_LEGACY_WORDBASIC_AUTOEXEC
    OLE Word document contains a legacy WordBasic auto-execution marker such as AutoOpen, but no modern VBA project was recovered and no stronger macro-virus family marker was present. This is analyst-facing evidence for old Word macro execution surface, not a downloader or parser-CVE attribution by itself.
  • Embedded URL info EMBEDDED_URL
    One or more URLs were extracted from the document. The URL itself is not a detection — see the per-URL labels for which channel (macro, JS, link annotation, document body, ...) reached each URL.
    URL http://www.microsoft.com0 In document text (OLE body)
    • http://crl.microsoft.com/pki/crl/products/CodeSignPCA.crl0In document text (OLE body)
    • https://www.verisign.com/rpaIn document text (OLE body)
    • http://ocsp.verisign.com/ocsp/status0In document text (OLE body)
    • https://www.verisign.com/rpa0In document text (OLE body)

Extracted artifacts 1

Files carved from inside the sample during analysis.

FilenameKindSourceSize
macros.bas vba-macro oletools.olevba.extract_macros (decoded VBA source) 79057 bytes
SHA-256: 330957448c6b8b32e0cdca2348e9665ab9f7d0a5b1a4b18d1dd92107f241a7ae
Preview script
First 1,000 lines of the extracted script
Attribute VB_Name = "ThisDocument"
Attribute VB_Base = "0{00020906-0000-0000-C000-000000000046}"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Attribute VB_TemplateDerived = False
Attribute VB_Customizable = True
Option Explicit



Attribute VB_Name = "formCnvCompleteDlg"
Attribute VB_Base = "0{CFB2DE44-EB19-462F-B8A2-928F2942DC2E}{08340965-3C38-4800-83DF-ABC8089971E1}"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Attribute VB_TemplateDerived = False
Attribute VB_Customizable = False



Private Sub cmdNo_Click()

    fAnotherConversion = False
    Unload Me

End Sub


Private Sub cmdYes_Click()

    fAnotherConversion = True
    Unload Me

End Sub


Private Sub UserForm_Initialize()

    If fHaltConversion Then
        lblCnvComplete = strCONVERSION_INTERRUPTED
    Else
        lblCnvComplete = strCONVERSION_COMPLETE
    End If

End Sub



Attribute VB_Name = "formProgress"
Attribute VB_Base = "0{EFCC7F6B-6E03-4D4C-B4E3-18EE8470B624}{40648256-7CB7-459B-B99D-69DAB3E0D82F}"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Attribute VB_TemplateDerived = False
Attribute VB_Customizable = False




Private Sub cmdCancel_Click()
'fCnvInterrupted = True
    fHaltConversion = True
    formProgress.Hide
End Sub

Private Sub UserForm_Activate()
    fHaltConversion = False
    gConverter.DoConversion
    Set gConverter = Nothing
    
    formProgress.Hide
End Sub



Attribute VB_Name = "formWizDlg"
Attribute VB_Base = "0{971FC1EE-D6F5-402B-9B3D-F1608CE7BF2C}{E135A9DE-82EB-4E45-962D-D8B7C4AD42DE}"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Attribute VB_TemplateDerived = False
Attribute VB_Customizable = False



' Conversion Wizard Form
Option Explicit

Private bClearToConvertListBox As Boolean

' Enable or disable the Finish button depending
' on the contents of the Convert list box
'
Private Sub SetFinishButton()

    If lbConvert.ListCount = 0 Then
        cmdFinish.Enabled = False
    Else
        cmdFinish.Enabled = True
    End If

End Sub

Private Sub cbFromWord_Change()

    ' Set the converter to use
    gConverter.SetFromWordConverter

End Sub


Private Sub cbToWord_Change()

    ' Set the converter to use
    gConverter.SetToWordConverter

End Sub

Private Sub cbType_Change()

    gConverter.SetPage3 False

End Sub

Private Sub cmdBrowseDest_Click()
    Dim strPath As String

    strPath = fnBrowseForFolder
    If Len(strPath) > 0 Then labDest.Caption = strPath
End Sub

Private Sub cmdBrowseSource_Click()
    Dim strPath As String

    strPath = fnBrowseForFolder
    If Len(strPath) > 0 Then
        labSource.Caption = strPath
        bClearToConvertListBox = True
    End If
End Sub

Private Sub cmdRemove_Click()

    ' cycle all of the available entries and put them in the convert listbox
    While formWizard.lbConvert.ListCount > 0
        formWizard.lbAvailable.AddItem formWizard.lbConvert.List(0)
        formWizard.lbConvert.RemoveItem 0
    Wend
    SetFinishButton

End Sub

Private Sub cmdSelect_Click()

    ' cycle all of the available entries and put them in the convert listbox
    While formWizard.lbAvailable.ListCount > 0
        formWizard.lbConvert.AddItem formWizard.lbAvailable.List(0)
        formWizard.lbAvailable.RemoveItem 0
    Wend
    SetFinishButton

End Sub

Private Sub lbAvailable_DblClick(ByVal Cancel As MSForms.ReturnBoolean)

    Dim str As String

    ' add the selected item to the other listbox
    str = formWizard.lbAvailable.Text
    formWizard.lbConvert.AddItem str
    ' if this is the first file to be copied over
    ' then enable Finish button
    SetFinishButton

    ' remove the selected item from this listbox
    If formWizard.lbAvailable.ListIndex >= 0 Then
        formWizard.lbAvailable.RemoveItem formWizard.lbAvailable.ListIndex
    End If

End Sub


Private Sub lbConvert_DblClick(ByVal Cancel As MSForms.ReturnBoolean)

    Dim str As String

    ' add the selected item to the other listbox
    str = formWizard.lbConvert.Text
    formWizard.lbAvailable.AddItem str

    ' remove the selected item from this listbox
    If formWizard.lbConvert.ListIndex >= 0 Then
        formWizard.lbConvert.RemoveItem formWizard.lbConvert.ListIndex
    End If

    SetFinishButton

End Sub


' Flowchart Controls
    
Private Sub lblMap0_Click()

    JumpToPanel 0

End Sub

Private Sub lblMap1_Click()

    JumpToPanel 1

End Sub

Private Sub lblMap2_Click()

    JumpToPanel 2

End Sub

Private Sub lblMap3_Click()

    JumpToPanel 3

End Sub

Private Sub lblMap4_Click()

    JumpToPanel 4

End Sub

Private Sub obFromWord_Change()

    If formWizard.obFromWord.Value Then iCurrentDirection = iDIRECTION_FROM

    ' check the state, and set the corresponding combo box's active state accordingly
    formWizard.cbFromWord.Enabled = formWizard.obFromWord.Value

    ' set the converter to use
    gConverter.SetFromWordConverter

End Sub


Private Sub obToWord_Change()

    If formWizard.obToWord.Value Then iCurrentDirection = iDIRECTION_TO

    ' check the state, and set the corresponding combo box's active state accordingly
    formWizard.cbToWord.Enabled = formWizard.obToWord.Value

    ' set the converter to use
    gConverter.SetToWordConverter

End Sub

Private Sub shpMap0_Click()

    JumpToPanel 0

End Sub

Private Sub shpMap1_Click()

    JumpToPanel 1

End Sub

Private Sub shpMap2_Click()

    JumpToPanel 2

End Sub

Private Sub shpMap3_Click()

    JumpToPanel 3

End Sub

Private Sub shpMap4_Click()

    JumpToPanel 4

End Sub


Private Sub cmdBack_Click()

    Dim i As Integer

    i = iCurrentPanel - 1
    While (i > 0 And rgfSkipPanel(i))
        i = i - 1
    Wend

    JumpToPanel i

End Sub

Private Sub cmdNext_Click()

    Dim i As Integer

    i = iCurrentPanel + 1
    While (rgfSkipPanel(i) And i < iMAX_PANEL)
        i = i + 1
    Wend

    JumpToPanel i

End Sub

Private Sub cmdCancel_Click()

    On Error GoTo FatalError

    If fBalloonVisible Then
        objAssistantBalloon.Close
        ' to avoid ReportError from closing balloon again
        fBalloonVisible = False
    End If

    gConverter.SaveDialogValues (True)
    Set gConverter = Nothing

    Unload formWizard
    ' no need to bring up the "Another Conversion?" dialog
    fSkipCnvComplete = True

    If lAssistantId Then Assistant.EndWizard lAssistantId, True
    Exit Sub

FatalError:
    ReportError Err
    Err.Clear

End Sub

Private Sub cmdFinish_Click()

    If fBalloonVisible Then
        objAssistantBalloon.Close
        ' to avoid ReportError from closing balloon again
        fBalloonVisible = False
    End If

    gConverter.SaveDialogValues (True)

    formWizard.Hide

    formProgress.Show

    Unload formProgress

    Unload formWizard

    If lAssistantId Then Assistant.EndWizard lAssistantId, True

End Sub

' Page 6
Private Sub JumpToPanel(iNewPanel As Integer)

    Dim objFormCtrls As Object

    If ((iCurrentPanel = iNewPanel) Or (rgfSkipPanel(iNewPanel))) Then Exit Sub

    Set objFormCtrls = formWizard.Controls

    If FPageLostFocus Then
        ' deselect current flow chart marker
        objFormCtrls(strSHP_MAP & iCurrentPanel).BackColor = COLOR_DARKGREY
        objFormCtrls(strLBL_MAP & iCurrentPanel).FONTBOLD = False
        iCurrentPanel = iNewPanel

        ' select new flow chart marker
        objFormCtrls(strSHP_MAP & iCurrentPanel).BackColor = COLOR_GREEN
        objFormCtrls(strLBL_MAP & iCurrentPanel).FONTBOLD = True

        ' change to new active page
        formWizard.mpgWizardPage.Value = iCurrentPanel
        If fBalloonVisible Then
            objAssistantBalloon.Close
            objAssistantBalloon.Text = rgstrAssistantMsg(iNewPanel)
            objAssistantBalloon.Show
        End If
        PageSetFocus
    End If

End Sub

Private Function FPageLostFocus() As Boolean

    Select Case iCurrentPanel
        Case iPANEL_START
            formWizard.cmdBack.Enabled = True
        Case iPANEL_FINISH
            formWizard.cmdNext.Enabled = True
    End Select

    ' Conversion Wizard always returns true
    FPageLostFocus = True

End Function

Private Sub PageSetFocus()

    Select Case iCurrentPanel
        Case iPANEL_START
            cmdNext.SetFocus
            cmdBack.Enabled = False
        Case iPANEL_FROMTO
            Select Case iCurrentDirection
                Case iDIRECTION_TO
                    formWizard.obToWord.SetFocus
                Case iDIRECTION_FROM
                    formWizard.obFromWord.SetFocus
                Case Else
                    iCurrentDirection = iDIRECTION_TO
                    formWizard.obToWord.SetFocus
            End Select
        Case iPANEL_FILES
            gConverter.SetPage3 bClearToConvertListBox
            If bClearToConvertListBox Then bClearToConvertListBox = False
        Case iPANEL_FINISH
            If cmdFinish.Enabled Then cmdFinish.SetFocus
            cmdNext.Enabled = False
    End Select

End Sub


' End Conversion Wizard Form Code
Private Sub UserForm_Initialize()

    bClearToConvertListBox = False

    labSource.Caption = strC_DIR
    labDest.Caption = strC_DIR

    cmdFinish.Enabled = False
    JumpToPanel 0

End Sub


Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)

    On Error GoTo FatalError

    If (CloseMode = vbFormControlMenu) Then
        If fBalloonVisible Then
            objAssistantBalloon.Close
            ' to avoid ReportError from closing balloon again
            fBalloonVisible = False
        End If
    
        gConverter.SaveDialogValues (True)
        Set gConverter = Nothing
    
        Unload formWizard
        ' no need to bring up the "Another Conversion?" dialog
        fSkipCnvComplete = True
    
        If lAssistantId Then Assistant.EndWizard lAssistantId, True
    End If
    Exit Sub
    
FatalError:
    ReportError Err
    Err.Clear
End Sub


Attribute VB_Name = "AutoNew"
' Wizard dialog form
Sub Main()
    StartConversionWizard
End Sub


Attribute VB_Name = "AutoOpen"
Sub Main()
'    StartConversionWizard
End Sub


Attribute VB_Name = "BrowseFolder"
Option Explicit

'---------------------------------------------------
' WinAPI Declarations
'---------------------------------------------------
Private Declare Sub CoTaskMemFree Lib "ole32.dll" (ByVal hMem As Long)
Private Declare Function SHBrowseForFolder Lib "shell32" (lpbi As BrowseInfo) As Long
Private Declare Function SHGetPathFromIDList Lib "shell32" (ByVal pidList As Long, ByVal lpBuffer As String) As Long
Private Declare Function GetActiveWindow Lib "user32" () As Long

'-------------------------------------------------
' User-Defined Types
'-------------------------------------------------
Private Type BrowseInfo
    hwndOwner As Long
    pIDLRoot As Long
    pszDisplayName As String
    lpszTitle As String
    ulFlags As Long
    lpfnCallback As Long
    lParam As Long
    iImage As Long
End Type

Public Type FileDialog
    sTitle As String
    sFilter As String
    sDefaultExt As String
    sInitDir As String
End Type

'-------------------------------------------------
' Module-level Constants
'-------------------------------------------------
'used for SHBrowseForFolder APIs
Const BIF_RETURNONLYFSDIRS = 1
Const MAX_PATH = 260

Public Function fnBrowseForFolder() As String
    Dim iNull As Integer
    Dim lpIDList As Long
    Dim lResult As Long
    Dim sPath As String
    Dim udtBI As BrowseInfo
    
    With udtBI
        .hwndOwner = GetActiveWindow&
        .ulFlags = BIF_RETURNONLYFSDIRS
    End With
    
    lpIDList = SHBrowseForFolder(udtBI)
    If lpIDList Then
        sPath = String$(MAX_PATH, 0)
        lResult = SHGetPathFromIDList(lpIDList, sPath)
        Call CoTaskMemFree(lpIDList)
        iNull = InStr(sPath, vbNullChar)
        If iNull Then sPath = Left$(sPath, iNull - 1)
    End If
    fnBrowseForFolder = sPath
End Function



Attribute VB_Name = "CnvCommon"
' ---------------------------------------------------------------------
' WORD 2003 WIZARD
' Batch File Conversion Wizard Specific Code
' ---------------------------------------------------------------------
'
' Modifications:
'
Option Explicit

' ---------------------------------------------------------------------
' CONSTANT DECLARATIONS

' Conversion Wizard
Public Const strWIZ_NAME = "转换向导"
Public Const strWIZ_LONG_NAME = strWIZ_NAME
Public Const strWIZ_FILE_NAME = "Convert9.wiz"
Public Const strWIZ_SHORT_NAME = "Conversion"
Public Const strWIZ_WORD_FILES = "*.doc"
Public Const strWIZ_WORD_EXT = "doc"
Public Const strWIZ_ALL_FILES = "*.*"
Public Const strWIZ_BLANK = "*.*"
Public Const strWIZ_SEP = "."
Public Const strWIZ_BACKSLASH = "\"
Public Const strWIZ_ALL_WORD_DOCS = "所有 Word 文档"
Public Const strWIZ_WORD_FOR_MAC = "Word 4.0 - 5.1 for Macintosh"

' Word VBA built-in converters (not listed by the FileConverters object)
Public Const strWIZ_TEXT = "纯文本"
Public Const strWIZ_TEMPLATE = "模板 "
Public Const strWIZ_UNICODE_TEXT = "编码文本"
Public Const strWIZ_RTF = "RTF 格式"
Public Const strWIZ_TEXT_WLB = "带换行符的纯文本"
Public Const strWIZ_MSDOS_TEXT = "MS DOS 文本"
Public Const strWIZ_MSDOS_WLB = "带换行符的 MS DOS 文本"
Public Const strWIZ_HTML = "HTML 文档"
Public Const strWIZ_XML = "XML 文档"

Public Const strTEXT_FILES = "*.txt"
Public Const strTEMPLATE_FILES = ".dot"
Public Const strUNICODE_TEXT_FILES = ".txt"
Public Const strRTF_FILES = ".rtf"
Public Const strHTML_FILES = ".htm"
Public Const strXML_FILES = ".xml"

Public Const strTEXT_FILE_EXT = "txt"
Public Const strTEMPLATE_FILE_EXT = "dot"
Public Const strUNICODE_TEXT_FILE_EXT = "txt"
Public Const strRTF_FILE_EXT = "rtf"
Public Const strTEXT_WLB_EXT = "txt"
Public Const strMSDOS_TEXT_EXT = "txt"
Public Const strMSDOS_TEXT_WLB_EXT = "txt"
Public Const strHTML_EXT = "htm"
Public Const strXML_EXT = "xml"

' Conversion result constants
Public Const strCONVERSION_COMPLETE = "转换已经完成。"
Public Const strCONVERSION_INTERRUPTED = "转换尚未完成。"

' Wizard Document and Form Control Related Constants
Public Const iPANEL_START As Integer = 0
Public Const iPANEL_FROMTO As Integer = 1
Public Const iPANEL_SOURCEDEST As Integer = 2
Public Const iPANEL_FILES As Integer = 3
Public Const iPANEL_FINISH As Integer = 4

' Conversion direction
Public Const iDIRECTION_TO = 0
Public Const iDIRECTION_FROM = 1

' form and callback balloon constants
Public Const iMAX_PANEL As Integer = 6 'panel # of the last panel in
                             'the dialog (starts from 0)
Public rgstrAssistantMsg(iMAX_PANEL + 1) As String ' as many as there are states
'Public Const iCALL_BACK_COUNT = 3 ' Number of items in CallBackBalloon (First=1)
'Public rgstrCallBackMsg(iCALL_BACK_COUNT) As String
'Public Const strCALL_BACK_HEADING = "Do more with the resume?"

'keeps track of which panel to be skipped.
'if we are enabling a panel, then we need to restore the shape's
'color to as it was before. rgiColorShape stores that color
Public rgfSkipPanel(iMAX_PANEL) As Boolean 'if rgfSkipPanel(i) is True,
                                            'then skip the ith panel
Public rgiColorShape(iMAX_PANEL) As Long
Public Const COLOR_LIGHT_GREY As Long = &HC0C0C0    'initial color of most shapes



Attribute VB_Name = "Common"
' ---------------------------------------------------------------------
' WORD 2003 WIZARD
' Common VBA Module
' ---------------------------------------------------------------------
'
Option Explicit

' ---------------------------------------------------------------------
' CONSTANT DECLARATIONS

' Note use of trailing spaces and punctuation...

' Banter strings
Public Const strSTARTING        As String = "开始 "
Public Const strSTARTING2       As String = "..."
Public Const strAPPLYING        As String = "正在应用样式表..."
Public Const strCREATING_DOC    As String = "正在创建文档..."
Public Const strSAVE_SETTINGS   As String = "正在保存设置..."
Public Const strRST_SETTINGS    As String = "正在恢复设置..."
Public Const strUPDATING_STYLE  As String = "正在更新样式..."

' Error messages
Public Const strERR_BAD_DOC         As String = "向导无法转换活动的文档。要运行向导,从“文件”菜单选择“打开”,然后选择“"
Public Const strERR_BAD_DOC2        As String = "”。"
Public Const strERR_INTERNAL        As String = "向导无法继续,由于下列错误 "
Public Const strERR_WIZ_NOT_FOUND   As String = "在用户指定的模板路径找不到向导。"
Public Const strERR_STYLE_NOT_FOUND As String = "向导找不到样式模板“"
Public Const strERR_STYLE_NOT_FOUND2 As String = "”。"
Public Const strERR_ASSISTANT_MSG   As String = "Assistant Error"  ' error msg for assistant
Public Const strERR_INIT_FORM       As String = "初始化表格出错。"
Public Const strERR_INIT_CALL_BACK  As String = "Error in initializing callback balloon."
Public Const strERR_CONVERSION_INCOMPLETE As String = "Word 无法转换文件 - "
Public Const strERR_CONVERSION_INCOMPLETE2 As String = "是否继续转换文件?"

' Misc strings
Public Const strWIZ As String = ".wiz"  'common extension to a wizard file
Public Const strDOT As String = ".dot"  'extension to a template file

' Progress bar static text strings
Public Const strSTATIC_1 As String = " 个文件已转换,共 "
Public Const strSTATIC_2 As String = " 个文件。"

' Help Assistant messages
Public Const strASSISTANT_MSG_0 = "未使用的"
Public Const strASSISTANT_MSG_1 = "未使用的"
Public Const strASSISTANT_MSG_2 = "未使用的"
Public Const strASSISTANT_MSG_3 = "未使用的"
Public Const strASSISTANT_MSG_4 = "未使用的"

' ---------------------------------------------------------------------
' **********     DO NOT LOCALIZE ANY CODE BEYOND THIS POINT  **********
' ---------------------------------------------------------------------

' registry key under which to store individual wizard preference settings
Public Const strREG_SETTINGS_BASE_KEY As String = "HKEY_CURRENT_USER\Software\Microsoft\Office\11.0\Word\Wizards\"

Public Const strSPACE       As String = " "
Public Const strCOMMA       As String = ","
Public Const strSHP_MAP     As String = "shpMap"  'prefix to the names of the shapes in the navigation chart/map
Public Const strLBL_MAP     As String = "lblMap"  'prefix to the names of the labels in the navigation chart/map
Public Const strREG_ASSISTANT_HELP As String = "Assistant Help" 'registry entry to store local state of Assistant
                                                                'for this wizard
Public Const strREG_ASSISTANT_TIME_STAMP As String = "Time Stamp" 'registry to store the time stamp when the
                                                                  'local state of the wizard changed.

' COLOUR constants used
Public Const COLOR_DISABLED As Long = &H404040  'used for disabled panel's label and shape
Public Const COLOR_DARKGREY As Long = &H808080  'used for visited panel's label and shape
Public Const COLOR_LIGHTGREY As Long = &HC0C0C0 'used for unvisited panel's label and shape
Public Const COLOR_RED      As Long = &HFF&
Public Const COLOR_GREEN    As Long = &HFF00&
Public Const COLOR_WHITE    As Long = &HFFFFFF

' ---------------------------------------------------------------------
' VARIABLE DECLARATIONS

' Wizard Names And FileNames
Public strWizName As String
Public strWizLongName As String
Public strWizShortName As String
Public strWizFileName As String

' Application Environment
Public objActiveRange   As Range     'current range
Public objWizTemplate   As Template  'doc's template i.e the wizard
Public objFps           As PageSetup 'FilePageSetup object
Public sMaxPageHeight   As Single    'PageHeight
Public iAlertsLevel     As Integer   'stores the initial alerts level

' Variables to store some environment values
Public strPathSeparator As String    'Directory separator in a path

' current panel of the multipage control in the dialog
Public iCurrentPanel As Integer

' Currently selected direction of conversion
Public iCurrentDirection As Integer

' Registry location key
Public strRegSettingsKey As String

' Assistant
Public objAssistantBalloon  As Balloon  'help balloon displayed for each panel
Public fBalloonVisible      As Boolean  'true if the above balloon is visible
Public fLocalState          As Boolean  'Local State of Assistant for passing to Office
Public lAssistantId         As Long     'assistant id obtained from StartConversionWizard call
Public fExitTglEvent        As Boolean  'this is set to True, if we don't want the
                                        'click event for the toggle button to be executed
                                        'when we change its value

Public fWizardCallBack      As Boolean  'we set it to True in FReenterWizardPanel
                                        'since it is used only in JumpToPanel
                                        'to disable jumping to other panels, by clicking
                                        'on the shapes
Public fInitialAssistantState As Boolean  'to go back to after exiting wizard

' Wizard
' Flags
Public fAnotherConversion As Boolean    'when set to true start another conversion
Public fSkipCnvComplete As Boolean      'when true don't bring up the last dlg
Public fCnvInterrupted As Boolean       'true when conversion interrupted
Public fEditInitSuccess As Boolean      'true when Edit Conv Options dlg initialized
Public fHaltConversion As Boolean       'true until conversion interrrupted
' Forms
Public formWizard As formWizDlg         'Wizard dialog form
Public formComplete As formCnvCompleteDlg 'conversion complete form
' Other
Public gConverter As CConverter         'global CConverter object
Public clsCnvTable As CConverterTable   'converter/filter table object
Public hWordHandle As Long              'Word's handle for Browse/Progres bar dlg

Public docWizard As Document
Public oWord As Object                  'Extra instance of Word to do conversions



' GetActiveWindow()
Private Declare Function GetActiveWindow Lib "user32" () As Long

' ----------------------------------------------------------------------
' General Purpose Utilities for Starting, Saving, and Restoring Wizards
' ----------------------------------------------------------------------
'
Public Sub StartConversionWizard()

    'qq Dim activeDoc As Document

    On Error GoTo FatalError

    fAnotherConversion = False
    fSkipCnvComplete = False
    fCnvInterrupted = False
    fHaltConversion = False

    Set docWizard = ActiveDocument
    Set oWord = CreateObject("word.application")
    oWord.Visible = False

    'qq Set activeDoc = oWord.Documents.Add
    
    Do
        ' Create a new instance of the coverter object
        Set gConverter = New CConverter
        If gConverter Is Nothing Then GoTo FatalError
    
        ' Init Global Var
        fWizardCallBack = False
        fExitTglEvent = False
        lAssistantId = 0
    
        ' Identify Wizard
        gConverter.InitWizardName (True)
    
        ' We're busy now
        StatusBar = strSTARTING & strWizName & strSTARTING2
    
        SetWizardEnvironment
    
        ' Locate the wizard template
        InitDocTemplate
    
        ' Initialize the new document
        InitDoc

        ' Initialize form
        gConverter.InitWizard (True)
    
        ' remove any text which might written for indicating progress
        StatusBar = ""
    
        ' Connect to the Assistant
        InitWizardAssistant
    
        ' Bring up dialog
        System.Cursor = wdCursorNormal
        formWizard.Show
    
        ResetWizardEnvironment

        ' if conversion successful ask user if she wants more
        If fSkipCnvComplete = False Then
            ' create and show the closing dialog
            Set formComplete = New formCnvCompleteDlg
            If formComplete Is Nothing Then GoTo FatalError
            formComplete.Show
        Else
            Exit Do
        End If
    Loop While (fAnotherConversion = True)
    
    ' Stop the extra instance of Word
    oWord.Quit
    
    ' Close the Wiz document
    docWizard.Close
    Exit Sub

FatalError:
    ReportError Err

End Sub  ' Main / StartConversionWizard

Private Sub InitDocTemplate()
    
    ' Did user create a New Document or a New Template?
    On Error GoTo CreatingNewTemplate

    ' New Document
    Set objWizTemplate = ActiveDocument.AttachedTemplate
    Exit Sub

CreatingNewTemplate:
    ' New Template
    Set objWizTemplate = ActiveDocument

End Sub  ' InitDocTemplate

' Sets the wizard environment
'
Private Sub SetWizardEnvironment()

    System.Cursor = wdCursorWait
    ' set alert level to none, so that Word/VBA dont display display any
    ' error messages by themselves
    iAlertsLevel = Application.DisplayAlerts
    Application.DisplayAlerts = wdAlertsNone
    ' Disable Cancel key, to prevent ESC key from interrupting the macro.
    ' it will still dismiss the Form though
    Application.EnableCancelKey = wdCancelDisabled

End Sub

' Resets the environment to what it was before the wizard was executed
'
Private Sub ResetWizardEnvironment()

    System.Cursor = wdCursorNormal
    ' remove any text which might written for indicating progress
    StatusBar = ""
    Application.ScreenUpdating = True
    Application.DisplayAlerts = iAlertsLevel
    Application.EnableCancelKey = wdCancelInterrupt

End Sub

' Returns the value stored in registry key strId
'
Public Function StrFetchPref(strId As String) As String

    On Error GoTo LReturnNull

    StrFetchPref = System.PrivateProfileString("", strRegSettingsKey, strId)
    Exit Function

LReturnNull:
    StrFetchPref = ""

End Function


' Stores strValue in registry key strId
'
Public Sub StorePref(strId As String, strValue As String)

    Dim strTemp As String

    ' If string is empty, store "~" as placeholder
    If (Len(strValue) = 0) Then
        strTemp = "~"
    Else
        strTemp = strValue
    End If

    System.PrivateProfileString("", strRegSettingsKey, strId) = strTemp

End Sub


' Returns the string stored in strId. If empty, returns strDefault
'
Public Function StrRestorePref(strId As String, strDefault As String) As String

    Dim strTemp As String

    strTemp = StrFetchPref(strId)
    ' If length is 0, it wasn't in regsistry, so use default value
    If Len(strTemp) = 0 Then
        strTemp = strDefault
    ' "~" is a placeholder to allow returning empty strings
    ElseIf strTemp = "~" Then
        strTemp = ""
    End If

    StrRestorePref = strTemp

End Function


' Stores iVal in registry key strId as a string
'
Public Sub StoreValPref(strId As String, iVal As Integer)

       StorePref strId, LTrim$(str$(iVal))

End Sub


' Returns the value stored in the key strId
' if invalid, returns iDefault.
'
Public Function FRestorePref(strId As String, fDefault As Boolean) As Boolean

    Dim strVal As String

    strVal = StrFetchPref(strId)
    If Len(strVal) = 0 Then
        FRestorePref = fDefault
    Else
        FRestorePref = Val(strVal)
    End If

End Function


' Returns the value stored in the key strId
' if invalid, returns iDefault
'
Public Function IRestorePref(strId As String, iDefault As Integer) As Integer

    Dim strVal As String

    strVal = StrFetchPref(strId)
    If Len(strVal) = 0 Then
…