Attribute VB_Name = "modImportAnalysis"

Option Explicit

'Enhanced Import Analysis for PE Differ
'Shows exactly what changed when imphash differs
'David's Malware Analysis Toolkit

Public Function AnalyzeImportChanges(pe1 As CPEEditor, pe2 As CPEEditor) As CImportChangeReport
    'Detailed analysis of import table changes
    'On Error GoTo hell
    
    Dim report As New CImportChangeReport
    report.imphash1 = pe1.impHash
    report.imphash2 = pe2.impHash
    report.imphashMatch = (report.imphash1 = report.imphash2)
    
    'Get import tables
    Dim imp1 As CLoadImports, imp2 As CLoadImports
    'On Error Resume Next
    Set imp1 = pe1.Imports
    Set imp2 = pe2.Imports
    'On Error GoTo hell
    
    If imp1 Is Nothing And imp2 Is Nothing Then
        report.summary = "No imports in either file"
        Set AnalyzeImportChanges = report
        Exit Function
    End If
    
    If imp1 Is Nothing Then
        report.summary = "Imports added (none in original)"
        Dim i As Long
        For i = 1 To imp2.Modules.count
            Dim impMod As CImport
            Set impMod = imp2.Modules(i)
            report.dllsAdded.Add impMod.dllName
        Next
        report.totalChanges = imp2.Modules.count
        Set AnalyzeImportChanges = report
        Exit Function
    End If
    
    If imp2 Is Nothing Then
        report.summary = "All imports removed"
        For i = 1 To imp1.Modules.count
            Set impMod = imp1.Modules(i)
            report.dllsRemoved.Add impMod.dllName
        Next
        report.totalChanges = imp1.Modules.count
        Set AnalyzeImportChanges = report
        Exit Function
    End If
    
    'Build DLL lookup tables
    Dim dlls1 As Object, dlls2 As Object
    Set dlls1 = CreateObject("Scripting.Dictionary")
    Set dlls2 = CreateObject("Scripting.Dictionary")
    
    For i = 1 To imp1.Modules.count
        Set impMod = imp1.Modules(i)
        Set dlls1(LCase(impMod.dllName)) = impMod
    Next
    
    For i = 1 To imp2.Modules.count
        Set impMod = imp2.Modules(i)
        Set dlls2(LCase(impMod.dllName)) = impMod
    Next
    
    Dim fc As CImportFunctionChange
    
    'Find added DLLs
    Dim key
    For Each key In dlls2.Keys
        If Not dlls1.Exists(key) Then
            report.dllsAdded.Add dlls2(key).dllName
            report.totalChanges = report.totalChanges + 1
            
            'All functions in this DLL are "added"
            Dim j As Long
            For j = 1 To dlls2(key).functions.count
                Set fc = New CImportFunctionChange
                fc.dllName = dlls2(key).dllName
                fc.functionName = CStr(dlls2(key).functions(j))
                report.functionsAdded.Add fc
            Next
        End If
    Next
    
    'Find removed DLLs
    For Each key In dlls1.Keys
        If Not dlls2.Exists(key) Then
            report.dllsRemoved.Add dlls1(key).dllName
            report.totalChanges = report.totalChanges + 1
            
            'All functions in this DLL are "removed"
            For j = 1 To dlls1(key).functions.count
                Set fc = New CImportFunctionChange
                fc.dllName = dlls1(key).dllName
                fc.functionName = CStr(dlls1(key).functions(j))
                report.functionsRemoved.Add fc
            Next
        End If
    Next
    
    'Compare common DLLs for function changes
    For Each key In dlls1.Keys
        If dlls2.Exists(key) Then
            Dim imp1Dll As CImport, imp2Dll As CImport
            Set imp1Dll = dlls1(key)
            Set imp2Dll = dlls2(key)
            
            'Build function lookup tables
            Dim funcs1 As Object, funcs2 As Object
            Set funcs1 = CreateObject("Scripting.Dictionary")
            Set funcs2 = CreateObject("Scripting.Dictionary")
            
            For j = 1 To imp1Dll.functions.count
                Dim fname As String
                fname = CStr(imp1Dll.functions(j))
                funcs1(LCase(fname)) = fname
            Next
            
            For j = 1 To imp2Dll.functions.count
                fname = CStr(imp2Dll.functions(j))
                funcs2(LCase(fname)) = fname
            Next
            
            'Check for function changes
            Dim HasChanges As Boolean
            HasChanges = False
            
            'Functions added to this DLL
            Dim funcKey
            For Each funcKey In funcs2.Keys
                If Not funcs1.Exists(funcKey) Then
                    Set fc = New CImportFunctionChange
                    fc.dllName = imp2Dll.dllName
                    fc.functionName = funcs2(funcKey)
                    report.functionsAdded.Add fc
                    HasChanges = True
                    report.totalChanges = report.totalChanges + 1
                End If
            Next
            
            'Functions removed from this DLL
            For Each funcKey In funcs1.Keys
                If Not funcs2.Exists(funcKey) Then
                    Set fc = New CImportFunctionChange
                    fc.dllName = imp1Dll.dllName
                    fc.functionName = funcs1(funcKey)
                    report.functionsRemoved.Add fc
                    HasChanges = True
                    report.totalChanges = report.totalChanges + 1
                End If
            Next
            
            If HasChanges Then
                report.dllsModified.Add imp1Dll.dllName
            End If
        End If
    Next
    
    'Build summary
    report.summary = BuildImportChangeSummary(report)
    
    Set AnalyzeImportChanges = report
    Exit Function
    
hell:
    If report Is Nothing Then Set report = New CImportChangeReport
    report.summary = "Error analyzing imports: " & Err.Description
    Set AnalyzeImportChanges = report
End Function

Private Function BuildImportChangeSummary(report As CImportChangeReport) As String
    Dim s As String
    
    s = "Import Hash: " & IIf(report.imphashMatch, "MATCH", "CHANGED") & vbCrLf
    s = s & "  Original: " & report.imphash1 & vbCrLf
    s = s & "  Modified: " & report.imphash2 & vbCrLf
    s = s & vbCrLf
    
    s = s & "DLL Changes:" & vbCrLf
    s = s & "  Added:    " & report.dllsAdded.count & vbCrLf
    s = s & "  Removed:  " & report.dllsRemoved.count & vbCrLf
    s = s & "  Modified: " & report.dllsModified.count & vbCrLf
    s = s & vbCrLf
    
    s = s & "Function Changes:" & vbCrLf
    s = s & "  Added:   " & report.functionsAdded.count & vbCrLf
    s = s & "  Removed: " & report.functionsRemoved.count & vbCrLf
    s = s & vbCrLf
    
    s = s & "Total Changes: " & report.totalChanges
    
    BuildImportChangeSummary = s
End Function

Public Function GetDetailedImportReport(pe1 As CPEEditor, pe2 As CPEEditor) As String
    'Generate comprehensive human-readable report
    Dim report As CImportChangeReport
    Set report = AnalyzeImportChanges(pe1, pe2)
    
    Dim s As String
    s = String(80, "=") & vbCrLf
    s = s & "IMPORT TABLE ANALYSIS" & vbCrLf
    s = s & String(80, "=") & vbCrLf
    s = s & vbCrLf
    
    s = s & report.summary & vbCrLf
    s = s & vbCrLf
    
    'DLLs Added
    If report.dllsAdded.count > 0 Then
        s = s & String(80, "-") & vbCrLf
        s = s & "DLLs ADDED (" & report.dllsAdded.count & "):" & vbCrLf
        s = s & String(80, "-") & vbCrLf
        
        Dim i As Long
        For i = 1 To report.dllsAdded.count
            s = s & "  [+] " & report.dllsAdded(i) & vbCrLf
        Next
        s = s & vbCrLf
    End If
    
    'DLLs Removed
    If report.dllsRemoved.count > 0 Then
        s = s & String(80, "-") & vbCrLf
        s = s & "DLLs REMOVED (" & report.dllsRemoved.count & "):" & vbCrLf
        s = s & String(80, "-") & vbCrLf
        
        For i = 1 To report.dllsRemoved.count
            s = s & "  [-] " & report.dllsRemoved(i) & vbCrLf
        Next
        s = s & vbCrLf
    End If
    
    'DLLs Modified
    If report.dllsModified.count > 0 Then
        s = s & String(80, "-") & vbCrLf
        s = s & "DLLs MODIFIED (" & report.dllsModified.count & "):" & vbCrLf
        s = s & String(80, "-") & vbCrLf
        
        For i = 1 To report.dllsModified.count
            s = s & "  [~] " & report.dllsModified(i) & vbCrLf
        Next
        s = s & vbCrLf
    End If
    
    'Functions Added
    If report.functionsAdded.count > 0 Then
        s = s & String(80, "-") & vbCrLf
        s = s & "FUNCTIONS ADDED (" & report.functionsAdded.count & "):" & vbCrLf
        s = s & String(80, "-") & vbCrLf
        
        'Group by DLL
        Dim byDll As Object
        Set byDll = CreateObject("Scripting.Dictionary")
        
        For i = 1 To report.functionsAdded.count
            Dim fc As CImportFunctionChange
            Set fc = report.functionsAdded(i)
            
            If Not byDll.Exists(LCase(fc.dllName)) Then
                Set byDll(LCase(fc.dllName)) = New Collection
            End If
            byDll(LCase(fc.dllName)).Add fc.functionName
        Next
        
        Dim key
        For Each key In byDll.Keys
            s = s & "  " & key & ":" & vbCrLf
            Dim j As Long
            For j = 1 To byDll(key).count
                s = s & "    [+] " & byDll(key)(j) & vbCrLf
            Next
        Next
        s = s & vbCrLf
    End If
    
    'Functions Removed
    If report.functionsRemoved.count > 0 Then
        s = s & String(80, "-") & vbCrLf
        s = s & "FUNCTIONS REMOVED (" & report.functionsRemoved.count & "):" & vbCrLf
        s = s & String(80, "-") & vbCrLf
        
        'Group by DLL
        Set byDll = CreateObject("Scripting.Dictionary")
        
        For i = 1 To report.functionsRemoved.count
            Set fc = report.functionsRemoved(i)
            
            If Not byDll.Exists(LCase(fc.dllName)) Then
                Set byDll(LCase(fc.dllName)) = New Collection
            End If
            byDll(LCase(fc.dllName)).Add fc.functionName
        Next
        
        For Each key In byDll.Keys
            s = s & "  " & key & ":" & vbCrLf
            For j = 1 To byDll(key).count
                s = s & "    [-] " & byDll(key)(j) & vbCrLf
            Next
        Next
        s = s & vbCrLf
    End If
    
    s = s & String(80, "=") & vbCrLf
    
    GetDetailedImportReport = s
End Function

Public Sub PrintImportAnalysis(pe1 As CPEEditor, pe2 As CPEEditor)
    'Quick debug output
    Debug.Print GetDetailedImportReport(pe1, pe2)
End Sub

Public Function QuickImportCheck(pe1 As CPEEditor, pe2 As CPEEditor) As String
    'One-liner summary for quick checks
    Dim report As CImportChangeReport
    Set report = AnalyzeImportChanges(pe1, pe2)
    
    If report.imphashMatch Then
        QuickImportCheck = "Imphash MATCH - imports identical"
    Else
        QuickImportCheck = "Imphash CHANGED - " & _
                          report.dllsAdded.count & " DLLs added, " & _
                          report.dllsRemoved.count & " DLLs removed, " & _
                          report.dllsModified.count & " DLLs modified, " & _
                          report.functionsAdded.count & " functions added, " & _
                          report.functionsRemoved.count & " functions removed"
    End If
End Function

'============================================================================
' USAGE EXAMPLES
'============================================================================

'Quick check:
'  Debug.Print QuickImportCheck(pe1, pe2)
'
'Detailed analysis:
'  Call PrintImportAnalysis(pe1, pe2)
'
'Programmatic access:
'  Dim report As CImportChangeReport
'  Set report = AnalyzeImportChanges(pe1, pe2)
'  If Not report.imphashMatch Then
'      Debug.Print "DLLs added: " & report.dllsAdded.Count
'      Dim i As Long
'      For i = 1 To report.functionsAdded.Count
'          Dim fc As CImportFunctionChange
'          Set fc = report.functionsAdded(i)
'          Debug.Print fc.dllName & "!" & fc.functionName
'      Next
'  End If


