oletools_rs 0.1.0

Rust port of oletools — analysis tools for Microsoft Office files (VBA macros, DDE, OLE objects, RTF exploits)
Documentation
//! CLSID (Class Identifier) database for OLE objects.
//!
//! Maps well-known CLSIDs to human-readable descriptions.
//! Ported from oletools/common/clsid.py.

use std::collections::HashMap;
use std::sync::LazyLock;

use uuid::Uuid;

/// A CLSID entry with a human-readable description.
#[derive(Debug, Clone)]
pub struct ClsidEntry {
    pub clsid: Uuid,
    pub description: &'static str,
}

/// Static CLSID database, keyed by UUID.
pub static CLSID_DB: LazyLock<HashMap<Uuid, &'static str>> = LazyLock::new(|| {
    let entries: &[(&str, &str)] = &[
        // Microsoft Office applications
        ("00020906-0000-0000-C000-000000000046", "Microsoft Word 97-2003 Document (Word.Document.8)"),
        ("00020900-0000-0000-C000-000000000046", "Microsoft Word 6.0-7.0 Document (Word.Document.6)"),
        ("00020810-0000-0000-C000-000000000046", "Microsoft Excel 97-2003 Worksheet (Excel.Sheet.8)"),
        ("00020820-0000-0000-C000-000000000046", "Microsoft Excel 97-2003 Chart (Excel.Chart.8)"),
        ("00020811-0000-0000-C000-000000000046", "Microsoft Excel 5.0/95 Worksheet (Excel.Sheet.5)"),
        ("64818D10-4F9B-11CF-86EA-00AA00B929E8", "Microsoft PowerPoint 97-2003 Presentation"),
        ("64818D11-4F9B-11CF-86EA-00AA00B929E8", "Microsoft PowerPoint 97-2003 Slide"),
        ("EA7BAE70-FB3B-11CD-A903-00AA00510EA3", "Microsoft PowerPoint 95 Presentation"),

        // OLE embedded objects
        ("00000300-0000-0000-C000-000000000046", "StdOleLink"),
        ("00000303-0000-0000-C000-000000000046", "FileMoniker"),
        ("00000304-0000-0000-C000-000000000046", "ItemMoniker"),
        ("00000305-0000-0000-C000-000000000046", "CompositeMoniker"),
        ("00000306-0000-0000-C000-000000000046", "AntiMoniker"),
        ("00000309-0000-0000-C000-000000000046", "GenericComposite"),
        ("0000030B-0000-0000-C000-000000000046", "ClassMoniker"),
        ("0003000C-0000-0000-C000-000000000046", "OLE Package (may contain executable)"),
        ("0003000D-0000-0000-C000-000000000046", "Link Source"),
        ("0003000E-0000-0000-C000-000000000046", "OLE Linked Object (Link)"),

        // Equation Editor (CVE-2017-11882)
        ("0002CE02-0000-0000-C000-000000000046", "Microsoft Equation 3.0 (may trigger CVE-2017-11882)"),
        ("00021700-0000-0000-C000-000000000046", "Microsoft Equation (legacy)"),

        // Shell / ActiveX objects (potentially dangerous)
        ("D5DE8D20-5BB8-11D1-A1E3-00A0C90F2731", "ShellBrowserWindow"),
        ("C08AFD90-F2A1-11D1-8455-00A0C91F3880", "ShellBrowserWindow (2)"),
        ("9BA05972-F6A8-11CF-A442-00A0C90A8F39", "ShellWindows"),
        ("13709620-C279-11CE-A49E-444553540000", "Shell Automation Service (Shell.Application)"),
        ("72C24DD5-D70A-438B-8A42-98424B88AFB8", "Windows Script Host Shell (WScript.Shell)"),
        ("F935DC22-1CF0-11D0-ADB9-00C04FD58A0B", "Windows Script Host Shell (WScript.Shell.1)"),
        ("0D43FE01-F093-11CF-8940-00A0C9054228", "FileSystemObject (Scripting.FileSystemObject)"),
        ("06290BD2-48AA-11D2-8432-006008C3FBFC", "XMLHTTP (potentially suspicious)"),
        ("F6D90F16-9C73-11D3-B32E-00C04F990BB4", "XMLHTTP 2 (potentially suspicious)"),
        ("88D96A0A-F192-11D4-A65F-0040963251E5", "MSXML2.XMLHTTP.6.0"),
        ("AFBA6B42-5692-48EA-8141-DC517DCF0EF1", "MSXML2.ServerXMLHTTP.6.0"),
        ("88D96A0B-F192-11D4-A65F-0040963251E5", "MSXML2.DOMDocument.6.0"),
        ("2087C2F4-2CEF-4953-A8AB-66779B670495", "MSXML2.DOMDocument.5.0"),
        ("F5078F32-C551-11D3-89B9-0000F81FE221", "MSXML2.DOMDocument.3.0"),
        ("F6D90F11-9C73-11D3-B32E-00C04F990BB4", "MSXML2.DOMDocument"),
        ("ED8C108E-4349-11D2-91A4-00C04F7969E8", "ADODB.Stream (often used by malware)"),
        ("00000566-0000-0010-8000-00AA006D2EA4", "ADODB.Recordset"),
        ("0002E510-0000-0000-C000-000000000046", "Microsoft Outlook Application"),
        ("0002E520-0000-0000-C000-000000000046", "Microsoft Outlook MailItem"),
        ("46E31370-3F7A-11CE-BED6-00AA00611080", "Microsoft Forms 2.0 Form"),
        ("5512D110-5CC6-11CF-8D67-00AA00BDCE1D", "Microsoft Forms 2.0 HTML"),
        ("5512D112-5CC6-11CF-8D67-00AA00BDCE1D", "Microsoft Forms 2.0 HTML Submit"),
        ("5512D114-5CC6-11CF-8D67-00AA00BDCE1D", "Microsoft Forms 2.0 HTML Image"),
        ("5512D116-5CC6-11CF-8D67-00AA00BDCE1D", "Microsoft Forms 2.0 HTML Hidden"),
        ("5512D118-5CC6-11CF-8D67-00AA00BDCE1D", "Microsoft Forms 2.0 HTML Password"),
        ("5512D11A-5CC6-11CF-8D67-00AA00BDCE1D", "Microsoft Forms 2.0 HTML Select"),
        ("5512D11C-5CC6-11CF-8D67-00AA00BDCE1D", "Microsoft Forms 2.0 HTML TextArea"),
        ("D7053240-CE69-11CD-A777-00DD01143C57", "Microsoft Forms 2.0 CommandButton"),
        ("978C9E23-D4B0-11CE-BF2D-00AA003F40D0", "Microsoft Forms 2.0 Label"),
        ("8BD21D10-EC42-11CE-9E0D-00AA006002F3", "Microsoft Forms 2.0 TextBox"),
        ("8BD21D20-EC42-11CE-9E0D-00AA006002F3", "Microsoft Forms 2.0 ListBox"),
        ("8BD21D30-EC42-11CE-9E0D-00AA006002F3", "Microsoft Forms 2.0 ComboBox"),
        ("8BD21D40-EC42-11CE-9E0D-00AA006002F3", "Microsoft Forms 2.0 CheckBox"),
        ("8BD21D50-EC42-11CE-9E0D-00AA006002F3", "Microsoft Forms 2.0 OptionButton"),
        ("8BD21D60-EC42-11CE-9E0D-00AA006002F3", "Microsoft Forms 2.0 ToggleButton"),

        // Visio
        ("00021A20-0000-0000-C000-000000000046", "Microsoft Visio Drawing"),

        // Access
        ("73A4C9C1-D68D-11D0-98BF-00A0C90DC8D9", "Microsoft Access Database"),

        // Publisher
        ("0002123B-0000-0000-C000-000000000046", "Microsoft Publisher Document"),

        // MSI / Windows Installer
        ("000C1084-0000-0000-C000-000000000046", "Windows Installer Package (.msi)"),
        ("000C1086-0000-0000-C000-000000000046", "Windows Installer Patch (.msp)"),

        // Flash / potentially dangerous embedded objects
        ("D27CDB6E-AE6D-11CF-96B8-444553540000", "Shockwave Flash Object (potentially dangerous)"),

        // PDF
        ("B801CA65-A1FC-11D0-85AD-444553540000", "Adobe Acrobat PDF"),

        // OneNote
        ("0B734A0A-FEFA-4FE1-B239-4876A0694B74", "OneNote Section"),

        // Scripting
        ("0E59F1D5-1FBE-11D0-8FF2-00A0D10038BC", "Windows Script Component"),
        ("3F4DACA4-160D-11D2-A8E9-00104B365C9F", "VBScript"),
        ("CC5BBEC3-DB4A-4BED-828F-F3F079B4F820", "JScript.Encode"),
        ("F414C260-6AC0-11CF-B6D1-00AA00BBBB58", "JScript"),

        // OLE Automation / COM
        ("00020424-0000-0000-C000-000000000046", "OLE Automation (IDispatch)"),
        ("00020420-0000-0000-C000-000000000046", "PSDispatch"),
        ("00020421-0000-0000-C000-000000000046", "PSEnumVARIANT"),
        ("00020422-0000-0000-C000-000000000046", "PSTypeInfo"),
        ("00020423-0000-0000-C000-000000000046", "PSTypeLib"),
        ("00020425-0000-0000-C000-000000000046", "PSTypeComp"),
        ("B196B286-BAB4-101A-B69C-00AA00341D07", "IConnectionPoint"),

        // OLE controls
        ("BEF6E003-A874-101A-8BBA-00AA00300CAB", "OLE Font"),
        ("0BE35203-8F91-11CE-9DE3-00AA004BB851", "OLE StdPicture"),
        ("79EAC9D0-BAF9-11CE-8C82-00AA004BA90B", "URL Moniker"),
        ("79EAC9D1-BAF9-11CE-8C82-00AA004BA90B", "URL Moniker (HTTP)"),
        ("79EAC9E0-BAF9-11CE-8C82-00AA004BA90B", "URL Moniker (File)"),
        ("79EAC9E2-BAF9-11CE-8C82-00AA004BA90B", "URL Moniker (Mk)"),
        ("79EAC9E7-BAF9-11CE-8C82-00AA004BA90B", "URL Moniker (HTTPS)"),

        // Potentially dangerous OLE objects
        ("3050F4D8-98B5-11CF-BB82-00AA00BDCE0B", "HTML Application (HTA, potentially dangerous)"),
        ("06290BD3-48AA-11D2-8432-006008C3FBFC", "XMLHTTP 3.0"),
        ("F5078F35-C551-11D3-89B9-0000F81FE221", "MSXML2.XMLHTTP.3.0"),
        ("2933BF90-7B36-11D2-B20E-00C04F983E60", "MSXML2.DOMDocument (v2)"),
        ("F6D90F12-9C73-11D3-B32E-00C04F990BB4", "MSXML2.SAXXMLReader"),
        ("88D96A0C-F192-11D4-A65F-0040963251E5", "MSXML2.SAXXMLReader.6.0"),
        ("88D96A0E-F192-11D4-A65F-0040963251E5", "MSXML2.XSLTemplate.6.0"),

        // WMI
        ("76A64158-CB41-11D1-8B02-00600806D9B6", "WbemScripting.SWbemLocator"),
        ("4590F811-1D3A-11D0-891F-00AA004B2E24", "WbemScripting.SWbemLocator (alt)"),

        // Task Scheduler
        ("0F87369F-A4E5-4CFC-BD3E-73E6154572DD", "Schedule.Service"),

        // MHTML
        ("05300401-BCBC-11D0-85E3-00A0C91E6C5E", "MHTML Document"),

        // Internet Explorer
        ("25336920-03F9-11CF-8FD0-00AA00686F13", "HTMLDocument"),
        ("3050F1C5-98B5-11CF-BB82-00AA00BDCE0B", "HTMLDocument (2)"),
    ];

    let mut map = HashMap::with_capacity(entries.len());
    for &(uuid_str, desc) in entries {
        if let Ok(uuid) = Uuid::parse_str(uuid_str) {
            map.insert(uuid, desc);
        }
    }
    map
});

/// Look up a CLSID and return its description, if known.
pub fn lookup_clsid(clsid: &Uuid) -> Option<&'static str> {
    CLSID_DB.get(clsid).copied()
}

/// Parse 16 raw bytes (mixed-endian GUID as stored in OLE) into a `Uuid`.
pub fn clsid_from_bytes(bytes: &[u8; 16]) -> Uuid {
    // OLE CLSIDs are stored in mixed-endian format:
    //   Data1 (4 bytes LE), Data2 (2 bytes LE), Data3 (2 bytes LE), Data4 (8 bytes BE)
    Uuid::from_fields(
        u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
        u16::from_le_bytes([bytes[4], bytes[5]]),
        u16::from_le_bytes([bytes[6], bytes[7]]),
        &bytes[8..16].try_into().unwrap(),
    )
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_lookup_known_clsid() {
        let word_clsid = Uuid::parse_str("00020906-0000-0000-C000-000000000046").unwrap();
        let desc = lookup_clsid(&word_clsid);
        assert!(desc.is_some());
        assert!(desc.unwrap().contains("Word"));
    }

    #[test]
    fn test_lookup_unknown_clsid() {
        let unknown = Uuid::nil();
        assert!(lookup_clsid(&unknown).is_none());
    }

    #[test]
    fn test_clsid_from_bytes() {
        // Word 97-2003: 00020906-0000-0000-C000-000000000046
        let bytes: [u8; 16] = [
            0x06, 0x09, 0x02, 0x00, // Data1 LE
            0x00, 0x00, // Data2 LE
            0x00, 0x00, // Data3 LE
            0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, // Data4 BE
        ];
        let uuid = clsid_from_bytes(&bytes);
        assert_eq!(
            uuid.to_string(),
            "00020906-0000-0000-c000-000000000046"
        );
    }

    #[test]
    fn test_equation_editor_clsid() {
        let eq_clsid = Uuid::parse_str("0002CE02-0000-0000-C000-000000000046").unwrap();
        let desc = lookup_clsid(&eq_clsid).unwrap();
        assert!(desc.contains("Equation"));
        assert!(desc.contains("CVE-2017-11882"));
    }

    #[test]
    fn test_db_not_empty() {
        assert!(CLSID_DB.len() >= 80);
    }
}