spytrap-adb 0.3.5

Test a phone for stalkerware using adb and usb debugging to scan for suspicious apps and configuration
Documentation
use crate::dumpsys;
use crate::errors::*;
use crate::ioc::{Suspicion, SuspicionLevel};
use crate::parsers::accessibility::Accessibility;
use forensic_adb::Device;

pub async fn dump(device: &Device) -> Result<Accessibility> {
    info!("Reading accessibility settings");
    let out = dumpsys::dump_service(device, "accessibility").await?;
    out.parse::<Accessibility>()
        .context("Failed to parse accessibility service output")
}

impl Accessibility {
    pub fn audit(&self) -> Vec<Suspicion> {
        let mut sus = Vec::new();
        if let Some(services) = &self.bound_services {
            warn!("Found bound accessibility services: {:?}", services);
            sus.push(Suspicion {
                level: SuspicionLevel::High,
                description: "An accessibility service is bound".to_string(),
            });
        }
        if let Some(services) = &self.enabled_services {
            warn!("Found enabled accessibility services: {:?}", services);
            sus.push(Suspicion {
                level: SuspicionLevel::High,
                description: format!("An accessibility service is enabled: {:?}", services),
            });
        }
        sus
    }
}

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

    #[test]
    fn test_audit_accessibility_plain() {
        let data = include_str!("../test_data/dumpsys/accessibility/plain.txt");
        let a = data.parse::<Accessibility>().unwrap();
        let sus = a.audit();
        assert_eq!(&sus, &[]);
    }

    #[test]
    fn test_audit_accessibility_plain2() {
        let data = include_str!("../test_data/dumpsys/accessibility/plain2.txt");
        let a = data.parse::<Accessibility>().unwrap();
        let sus = a.audit();
        assert_eq!(&sus, &[]);
    }

    #[test]
    fn test_audit_accessibility_spylive360() {
        let data = include_str!("../test_data/dumpsys/accessibility/spylive360.txt");
        let a = data.parse::<Accessibility>().unwrap();
        let sus = a.audit();
        assert_eq!(&sus, &[
            Suspicion {
                level: SuspicionLevel::High,
                description: "An accessibility service is bound".to_string(),
            },
            Suspicion {
                level: SuspicionLevel::High,
                description: "An accessibility service is enabled: \"{com.wifi0/com.wifi0.AccessibilityReceiver4}\"".to_string(),
            },
        ]);
    }
}