Analyzing Malware Persistence with Autoruns
Overview
Sysinternals Autoruns extracts data from hundreds of Auto-Start Extensibility Points (ASEPs) on Windows, scanning 18+ categories including Run/RunOnce keys, services, scheduled tasks, drivers, Winlogon entries, LSA providers, print monitors, WMI subscriptions, and AppInit DLLs. Digital signature verification filters Microsoft-signed entries. The compare function identifies newly added persistence via baseline diffing. VirusTotal integration checks hash reputation. Offline analysis via -z flag enables forensic disk image examination.
When to Use
- When investigating security incidents that require analyzing malware persistence with autoruns
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
Prerequisites
- Sysinternals Autoruns (GUI) and Autorunsc (CLI)
- Administrative privileges on target system
- Python 3.9+ for automated analysis
- VirusTotal API key for reputation checks
- Clean baseline export for comparison
Workflow
Step 1: Automated Persistence Scanning
#!/usr/bin/env python3
"""Automate Autoruns-based persistence analysis."""
import subprocess
import csv
import json
import sys
def scan_and_analyze(autorunsc_path="autorunsc64.exe", csv_path="scan.csv"):
cmd = [autorunsc_path, "-a", "*", "-c", "-h", "-s", "-nobanner", "*"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=600)
with open(csv_path, 'w') as f:
f.write(result.stdout)
return parse_and_flag(csv_path)
def parse_and_flag(csv_path):
suspicious = []
with open(csv_path, 'r', errors='replace') as f:
for row in csv.DictReader(f):
reasons = []
signer = row.get("Signer", "")
if not signer or signer == "(Not verified)":
reasons.append("Unsigned binary")
if not row.get("Description") and not row.get("Company"):
reasons.append("Missing metadata")
path = row.get("Image Path", "").lower()
for sp in ["\temp\\", "\appdata\local\temp", "\users\public\\"]:
if sp in path:
reasons.append(f"Suspicious path")
launch = row.get("Launch String", "").lower()
for kw in ["powershell", "cmd /c", "wscript", "mshta", "regsvr32"]:
if kw in launch:
reasons.append(f"LOLBin: {kw}")
if reasons:
row["reasons"] = reasons
suspicious.append(row)
return suspicious
if __name__ == "__main__":
if len(sys.argv) > 1:
results = parse_and_flag(sys.argv[1])
print(f"[!] {len(results)} suspicious entries")
for r in results:
print(f" {r.get('Entry','')} - {r.get('Image Path','')}")
for reason in r.get('reasons', []):
print(f" - {reason}")
Validation Criteria
- All ASEP categories scanned and cataloged
- Unsigned entries flagged for investigation
- Suspicious paths and LOLBin launch strings highlighted
- Baseline comparison identifies new persistence mechanisms
References
1---
2name: analyzing-malware-persistence-with-autoruns
3description: Use Sysinternals Autoruns to systematically identify and analyze malware persistence mechanisms across registry
4 keys, scheduled tasks, services, drivers, and startup locations on Windows systems.
5domain: cybersecurity
6subdomain: malware-analysis
7tags:
8- autoruns
9- persistence
10- malware-analysis
11- sysinternals
12- windows
13- registry
14- startup
15- incident-response
16mitre_attack:
17- T1547
18- T1053
19- T1543
20- T1546
21version: '1.0'
22author: mahipal
23license: Apache-2.0
24d3fend_techniques:
25- Executable Denylisting
26- Execution Isolation
27- File Metadata Consistency Validation
28- Content Format Conversion
29- File Content Analysis
30nist_csf:
31- DE.AE-02
32- RS.AN-03
33- ID.RA-01
34- DE.CM-01
35---
36
37# Analyzing Malware Persistence with Autoruns
38
39## Overview
40
41Sysinternals Autoruns extracts data from hundreds of Auto-Start Extensibility Points (ASEPs) on Windows, scanning 18+ categories including Run/RunOnce keys, services, scheduled tasks, drivers, Winlogon entries, LSA providers, print monitors, WMI subscriptions, and AppInit DLLs. Digital signature verification filters Microsoft-signed entries. The compare function identifies newly added persistence via baseline diffing. VirusTotal integration checks hash reputation. Offline analysis via -z flag enables forensic disk image examination.
42
43
44## When to Use
45
46- When investigating security incidents that require analyzing malware persistence with autoruns
47- When building detection rules or threat hunting queries for this domain
48- When SOC analysts need structured procedures for this analysis type
49- When validating security monitoring coverage for related attack techniques
50
51## Prerequisites
52
53- Sysinternals Autoruns (GUI) and Autorunsc (CLI)
54- Administrative privileges on target system
55- Python 3.9+ for automated analysis
56- VirusTotal API key for reputation checks
57- Clean baseline export for comparison
58
59## Workflow
60
61### Step 1: Automated Persistence Scanning
62
63```python
64#!/usr/bin/env python3
65"""Automate Autoruns-based persistence analysis."""
66import subprocess
67import csv
68import json
69import sys
70
71
72def scan_and_analyze(autorunsc_path="autorunsc64.exe", csv_path="scan.csv"):
73 cmd = [autorunsc_path, "-a", "*", "-c", "-h", "-s", "-nobanner", "*"]
74 result = subprocess.run(cmd, capture_output=True, text=True, timeout=600)
75 with open(csv_path, 'w') as f:
76 f.write(result.stdout)
77 return parse_and_flag(csv_path)
78
79
80def parse_and_flag(csv_path):
81 suspicious = []
82 with open(csv_path, 'r', errors='replace') as f:
83 for row in csv.DictReader(f):
84 reasons = []
85 signer = row.get("Signer", "")
86 if not signer or signer == "(Not verified)":
87 reasons.append("Unsigned binary")
88 if not row.get("Description") and not row.get("Company"):
89 reasons.append("Missing metadata")
90 path = row.get("Image Path", "").lower()
91 for sp in ["\temp\\", "\appdata\local\temp", "\users\public\\"]:
92 if sp in path:
93 reasons.append(f"Suspicious path")
94 launch = row.get("Launch String", "").lower()
95 for kw in ["powershell", "cmd /c", "wscript", "mshta", "regsvr32"]:
96 if kw in launch:
97 reasons.append(f"LOLBin: {kw}")
98 if reasons:
99 row["reasons"] = reasons
100 suspicious.append(row)
101 return suspicious
102
103
104if __name__ == "__main__":
105 if len(sys.argv) > 1:
106 results = parse_and_flag(sys.argv[1])
107 print(f"[!] {len(results)} suspicious entries")
108 for r in results:
109 print(f" {r.get('Entry','')} - {r.get('Image Path','')}")
110 for reason in r.get('reasons', []):
111 print(f" - {reason}")
112```
113
114## Validation Criteria
115
116- All ASEP categories scanned and cataloged
117- Unsigned entries flagged for investigation
118- Suspicious paths and LOLBin launch strings highlighted
119- Baseline comparison identifies new persistence mechanisms
120
121## References
122
123- [Sysinternals Autoruns](https://learn.microsoft.com/en-us/sysinternals/downloads/autoruns)
124- [SANS - Offline Autoruns Revisited](https://www.sans.org/blog/offline-autoruns-revisited-auditing-malware-persistence/)
125- [Hunting Malware with Autoruns](https://nasbench.medium.com/hunting-malware-with-windows-sysinternals-autoruns-19cbfe4103c2)
126- [MITRE ATT&CK T1547 - Boot or Logon Autostart](https://attack.mitre.org/techniques/T1547/)