WireLurker Detector is a short Python script that scans a Mac OS X system for files and applications infected by the WireLurker malware family, a 2014 OS X / iOS threat discovered by Palo Alto Networks. It also ships a small companion script that can decrypt the command-and-control (C&C) traffic used by the Windows-capable variant of WireLurker.
Important
This tool is a historical artifact. It was written in 2014 against Python 2, targets the specific on-disk signatures of the 2014 WireLurker campaign, and has not been updated to detect newer malware. Use it for historical forensics, research, or incident-response work on legacy systems — not as a general-purpose antivirus.
1. Quick Start
The detector is a single file. You download it, run it with Python 2, and read its output.
macOS
curl -O https://raw.githubusercontent.com/PaloAltoNetworks/WireLurkerDetector/master/WireLurkerDetectorOSX.py
python2 WireLurkerDetectorOSX.py
Clone the repo
git clone https://github.com/PaloAltoNetworks/WireLurkerDetector.git
cd WireLurkerDetector
python2 WireLurkerDetectorOSX.py
Expected output on a clean system:
WireLurker Detector (version 1.2.0)
Copyright (c) 2014, Palo Alto Networks, Inc.
[+] Scanning for known malicious files ...
[-] Nothing is found.
[+] Scanning for known suspicious files ...
[-] Nothing is found.
[+] Scanning for infected applications ... (may take minutes)
[-] Nothing is found.
[+] Your OS X system isn't infected by the WireLurker. Thank you!
Note
The application scan walks every
.appbundle in/Applicationsand~/Applications. On systems with many installed apps it can take several minutes. This is expected.
2. Requirements
| Requirement | Value | Notes |
|---|---|---|
| Operating system | macOS (Darwin) | The detector refuses to run on anything else and exits with code -1. |
| Python interpreter | Python 2 (tested with 2.7) | The source uses Python-2 print statement syntax. Python 3 raises SyntaxError at parse time. |
| Privileges | Unprivileged user is enough to read /Applications, /Library, /System/Library, /usr/bin, and /usr/local/. sudo is not required by the script itself. |
|
| Network | None for the OS X detector. curl only needs the internet when you first download the script. |
|
| External library (decryptor only) | pyDes |
Pure-Python DES implementation. Only needed if you run decryptor.py. |
Warning
Modern macOS ships Python 3 as
python3, and thepythoncommand may be absent or aliased topython3. Run the detector explicitly withpython2and confirm the version first:python2 --versionPython 2.7.18
3. Installation
There is no packaging, no setup.py, and no PyPI release. "Installation" is just obtaining the script.
3.1 Option A — Download a single file
curl -O https://raw.githubusercontent.com/PaloAltoNetworks/WireLurkerDetector/master/WireLurkerDetectorOSX.py
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 5143 100 5143 0 0 22000 0 --:--:-- --:--:-- --:--:-- 22000
The file is ~5 KB. Place it anywhere you can execute it from.
3.2 Option B — Clone the repository
git clone https://github.com/PaloAltoNetworks/WireLurkerDetector.git
cd WireLurkerDetector
ls
HOWTO-Windows.md
LICENSE
README.md
WireLurkerDetectorOSX.py
decryptor.py
3.3 Installing pyDes (only if you need the decryptor)
pip2 install pyDes
Collecting pyDes
Using cached pyDes-2.0.1.tar.gz
Installing collected packages: pyDes
Successfully installed pyDes-2.0.1
Tip
The script's own error message recommends the flags
--allow-external pyDes --allow-unverified pyDes. Those flags were removed from pip years ago and are not needed anymore. Plainpip2 install pyDesworks on any currently maintained Python 2 environment.
3.4 Installation checklist
- [ ]
python2 --versionprintsPython 2.7.x. - [ ] You are on macOS (check with
uname -s→Darwin). - [ ]
WireLurkerDetectorOSX.pyis downloaded and readable. - [ ] (Decryptor only)
python2 -c "import pyDes"returns without error.
4. Using the Detector — WireLurkerDetectorOSX.py
4.1 Running a scan
Run the script from any directory. It takes no command-line arguments.
python2 WireLurkerDetectorOSX.py
The scan runs three passes, in this fixed order:
- Known malicious files. The script checks for the presence of 18 hardcoded absolute paths (e.g.
/Users/Shared/run.sh,/Library/LaunchDaemons/com.apple.machook_damon.plist). Any path that exists is printed as[!] Found malicious file: <path>. - Known suspicious files. A shorter list of 4 paths that can be associated with the WireLurker installer but are not by themselves conclusive (e.g.
/etc/manpath.d/,~/Library/Caches/com.maiyadi.appinstaller/). Matches print as[!] Found suspicious file: <path>. - Infected applications. The script walks
/Applicationsand~/Applicationsrecursively, opens theContents/Info.plistof every.appbundle, and applies the infection heuristics in §4.3.
4.2 Interpreting the exit status
| Exit code | Meaning |
|---|---|
0 |
No malicious files, suspicious files, or infected applications were detected. The system is considered clean by this tool. |
1 |
At least one indicator was found. The final block of output repeats the warning and points to the Palo Alto Networks research-center article. |
-1 |
The script was executed on a non-Darwin system and refused to run, or it could not be launched (e.g. wrong Python version, missing file). |
You can branch on the exit code in a shell pipeline:
python2 WireLurkerDetectorOSX.py
if [ $? -eq 0 ]; then
echo "Clean."
else
echo "Review output — indicators were found."
fi
4.3 The .app infection heuristic
Every .app bundle under /Applications or ~/Applications is inspected. A bundle is flagged as infected if any one of the three heuristics below is true.
| # | Heuristic | What it looks for |
|---|---|---|
| 1 | Hidden legitimate executable swap. | Reads Contents/Info.plist, resolves CFBundleExecutable, and checks whether both Contents/MacOS/<exec> and Contents/MacOS/<exec>_ have the hidden flag set (UF_HIDDEN on the filesystem, or ls -ldO … hidden fallback). |
| 2 | Hidden trojan start script. | Checks whether both Contents/Resources/start.sh and Contents/Resources/FontMap1.cfg are present and hidden. |
| 3 | Embedded installer + payload. | Checks whether both Contents/MacOS/appinstaller and Contents/Resources/infoplistab exist as files. |
If the Info.plist is unreadable or CFBundleExecutable is missing, the bundle is silently skipped. The script never modifies or quarantines anything — it only reports.
Tip
To see the full list of files the detector watches for, grep the source:
grep -E "^\s*'/(Users|Library|System|usr|etc)" WireLurkerDetectorOSX.py
4.4 Example — infection detected
If an infected bundle or known file is present, output looks like this:
WireLurker Detector (version 1.2.0)
Copyright (c) 2014, Palo Alto Networks, Inc.
[+] Scanning for known malicious files ...
[!] Found malicious file: /Library/LaunchDaemons/com.apple.machook_damon.plist
[!] Found malicious file: /usr/bin/globalupdate
[+] Scanning for known suspicious files ...
[-] Nothing is found.
[+] Scanning for infected applications ... (may take minutes)
[!] Found infected application: /Applications/SomeApp.app
[!] WARNING: Your OS X system is highly suspicious of being infected by the WireLurker.
[!] You may need to delete all malicious or suspicious files and/or applications above.
[!] For more information about the WireLurker, please refer:
[!] http://researchcenter.paloaltonetworks.com/2014/11/wirelurker-new-era-os-x-ios-malware/
Caution
The detector never removes anything. Before deleting a flagged file or application, capture it for forensics (
tar,dd, or preserve the original.appbundle) and verify the match by hand. Deleting without preservation destroys evidence that may be needed for further analysis.
5. Using the Decryptor — decryptor.py
5.1 Purpose
decryptor.py decrypts a single base64-encoded message produced by the version C variant of WireLurker when it talks to its C&C server. It is a research helper, not part of the detection loop. You only use it when you already have captured encrypted C&C traffic and want to read it.
5.2 Syntax
python2 decryptor.py <encrypted_message>
<encrypted_message>— A single base64-ish string captured from WireLurker C&C traffic. The first 10 characters are metadata that seed the session key; the remainder is the base64-encoded DES-ECB ciphertext.
5.3 How the key is derived
The script:
- Takes the first 10 characters of the input, interprets each as a decimal digit, and sums them.
- Formats that sum as a decimal string and appends the literal suffix
dksyelto get the DES key. - Decrypts the remaining characters as base64-decoded DES-ECB with PKCS#5 padding.
You do not need to know this to use the tool, but it explains why the first 10 characters of a captured packet are required.
5.4 Example
python2 decryptor.py 0123456789BASE64ENCODEDPAYLOAD=
The plaintext (if the input is a valid WireLurker-C message) is printed to stdout. Malformed input typically raises a Python traceback from pyDes or base64.
Note
The decryptor is specific to the 2014 "version C" strain. It will not decrypt traffic from unrelated malware, and it is not a general DES utility.
6. Common Tasks
6.1 Run on an offline or air-gapped Mac
Copy the single .py file onto removable media, mount it on the target Mac, and run it. The detector does not touch the network.
cp /Volumes/USB/WireLurkerDetectorOSX.py ~/Desktop/
python2 ~/Desktop/WireLurkerDetectorOSX.py
6.2 Capture scan output to a log file
python2 WireLurkerDetectorOSX.py | tee ~/Desktop/wirelurker-scan-$(date +%Y%m%d-%H%M%S).log
WireLurker Detector (version 1.2.0)
Copyright (c) 2014, Palo Alto Networks, Inc.
...
6.3 Scan multiple Macs with one command
Use SSH plus the raw GitHub URL:
ssh admin@mac-host \
'curl -s https://raw.githubusercontent.com/PaloAltoNetworks/WireLurkerDetector/master/WireLurkerDetectorOSX.py \
| /usr/bin/python2 -'
Warning
Piping a remote script into the interpreter trusts GitHub's TLS and the repo's integrity. For incident-response work, prefer to pin a known-good commit hash by downloading once, verifying its SHA-256, and then distributing the file.
6.4 Decrypt a list of captured messages in batch
while IFS= read -r msg; do
printf '%s => ' "$msg"
python2 decryptor.py "$msg"
done < captured_messages.txt
6.5 Remove WireLurker artifacts after a confirmed hit
The detector does not clean up. If the scan confirms infection, a reasonable cleanup sequence — performed by a human, with backups — is:
# 1. Preserve evidence first.
sudo tar czf ~/wirelurker-evidence.tar.gz \
/Library/LaunchDaemons/com.apple.machook_damon.plist \
/Users/Shared/run.sh 2>/dev/null
# 2. Unload LaunchDaemons before deleting plists.
sudo launchctl unload /Library/LaunchDaemons/com.apple.machook_damon.plist 2>/dev/null
# 3. Delete each flagged malicious file.
sudo rm -f /Library/LaunchDaemons/com.apple.machook_damon.plist
sudo rm -f /Users/Shared/run.sh
# ...and so on for every path the detector reported.
# 4. Re-run the detector and confirm a clean report.
python2 WireLurkerDetectorOSX.py
Caution
Do not run these commands blindly. Only delete the specific paths that the detector actually reported on this system, and only after you understand why each file was flagged.
7. Windows Variant
The repository does not ship a Windows detector binary. The file HOWTO-Windows.md in the repository describes the detection logic so that third parties can write their own tools.
The Palo Alto Networks-documented heuristic is:
- Scan every PE executable on the system.
- If the file contains the ZIP end-of-central-directory magic (
\x50\x4b\x05\x06) exactly four times, continue — otherwise skip. - If the file also contains both of the literal strings
Payload/apps.app/sfbase.dylibandPayload/apps.app/sfbase.plist, classify it as WireLurker.
The README explicitly points at two community-built Windows detectors. Those tools are not maintained by Palo Alto Networks and are not endorsed — treat them as reference implementations of the above logic.
Note
The repository's Windows guidance is a text-only specification. To detect WireLurker on Windows you either write a scanner following the logic above or use one of the community tools linked from the upstream README.
8. Troubleshooting
Every error below is drawn from actual community reports on the upstream issue tracker or from the script's own source.
Error: SyntaxError: Missing parentheses in call to 'print'
File "WireLurkerDetectorOSX.py", line 120
print 'WireLurker Detector (version %s)' % __version__
^
SyntaxError: Missing parentheses in call to 'print'
Cause. You ran the script with Python 3. WireLurker Detector is written in Python 2 and uses the Python-2 print statement. This exact failure is reported in community issues #25, #23, and #17.
Solution. Run with Python 2 explicitly:
python2 WireLurkerDetectorOSX.py
Prevention. Check the interpreter before invoking: python2 --version should print Python 2.7.x. If Python 2 is not installed, use a legacy macOS VM that still ships it or install it via Homebrew from an archival tap — recent Homebrew revisions dropped the python@2 formula.
Error: ERROR: The script should only be run in a Mac OS X system.
ERROR: The script should only be run in a Mac OS X system.
Cause. The detector checks platform.system() and refuses to run unless it returns Darwin. You invoked it on Linux, Windows (WSL included), or in a container that reports a non-Darwin uname.
Solution. Run on an actual macOS host. There is no --force flag; the platform guard is intentional because every hardcoded path in the script is macOS-specific.
Prevention. Gate your scripts with uname -s before invoking.
Error: ImportError: No module named pyDes (decryptor only)
ERROR: the script requires pyDes library installed! Please run this command to install it:
# pip install pyDes --allow-external pyDes --allow-unverified pyDes
Cause. decryptor.py imports pyDes. The module is not installed in your Python 2 environment.
Solution.
pip2 install pyDes
Prevention. Sanity-check the import in the interpreter you plan to use:
python2 -c "import pyDes; print(pyDes.__file__)"
Error: Usage: decryptor.py <encrypted_message>
Usage: decryptor.py <encrypted_message>
Cause. You invoked decryptor.py without exactly one argument.
Solution. Pass one positional argument — the captured base64 WireLurker-C message — as a single quoted string:
python2 decryptor.py 'CAPTURED_MESSAGE_HERE'
Prevention. Always quote the argument. Captured traffic often contains shell metacharacters.
Error: antivirus flags WireLurkerDetectorOSX.py itself as a trojan
Cause. Some endpoint scanners (historically Avast — see community issue #19) fire heuristics on the hardcoded list of WireLurker paths embedded in the source.
Solution. This is a false positive. The script does not download, write, or execute any of those paths — it only checks whether they already exist. Verify the file's checksum against the upstream repository, and add an allowlist entry in your AV for the script's location.
Prevention. When distributing the script internally, store the SHA-256 hash next to the file and compare on each deployment.
Error: curl: (60) SSL certificate problem
curl: (60) SSL certificate problem: unable to get local issuer certificate
Cause. The macOS system you're running on is old enough that its root CA bundle no longer trusts GitHub's current certificate chain. This exact symptom is reported in community issue #24.
Solution. Either update curl and the system root certificates, or download the script from a modern machine and transfer it via USB / SCP.
Prevention. For incident response on vintage Macs, prepare a signed, hash-verified copy of the detector on removable media in advance.
Error: application scan appears to hang
Cause. The third pass walks every directory tree inside /Applications and ~/Applications and opens an Info.plist for every .app bundle it encounters. On systems with large media-authoring suites this can take many minutes with no intermediate progress output.
Solution. Wait. If it runs for more than ~15 minutes, open another Terminal and check that the Python process is still advancing with sudo fs_usage -f filesys python2.
Prevention. Run the scan while you are doing something else; it is I/O-bound rather than interactive.
Error: UnicodeDecodeError reading a plist
Cause. An unusual Info.plist encoding in one of the .app bundles chokes the Python 2 plistlib.readPlist call.
Solution. The is_app_infected() function wraps the plist read in a try/except Exception: return False, so the script continues to the next bundle. The affected bundle is silently treated as "not infected". If you need certainty, open that plist by hand:
plutil -convert xml1 -o - "/Applications/Suspect.app/Contents/Info.plist"
Prevention. None available from the tool; it is a limitation of Python 2's plistlib.
Error: python: command not found
-bash: python: command not found
Cause. Modern macOS removes the bare python command. Only python3 and (if installed) python2 are present.
Solution. Invoke python2 explicitly everywhere:
python2 WireLurkerDetectorOSX.py
Prevention. Create a shell alias for incident-response work: alias ir-python='python2'.
Error: Permission denied reading /Library/LaunchDaemons/…
Cause. Some LaunchDaemon plists are readable only by root; additionally, System Integrity Protection (SIP) restricts read access to certain paths on newer macOS versions.
Solution. Run the detector under sudo:
sudo python2 WireLurkerDetectorOSX.py
Prevention. For thorough forensic scans, always invoke with sudo. The script does not require root, but it produces more complete results with it.
Error: the detector reports no infection on a host you believe is compromised
Cause. The hardcoded MALICIOUS_FILES / SUSPICIOUS_FILES lists are the exact paths observed in 2014. A different variant — or a modern macOS malware family that borrowed the WireLurker name — will not match.
Solution. Treat a clean result as "no 2014-era WireLurker indicators", not as "the host is malware-free". Follow up with a general-purpose macOS incident-response scan (KnockKnock, BlockBlock, or equivalent).
Prevention. Include the detector as one item in a wider incident-response checklist, never as the sole diagnostic.
Error: PermissionError walking ~/Applications
Cause. The current user does not own ~/Applications, or that directory does not exist and the script's os.walk on it returns no bundles silently.
Solution. No action needed — os.walk on a missing directory produces an empty iterator. Optionally pre-create the directory if you want to confirm the scan actually traversed it.
Prevention. Check ls -la ~/Applications before running the scan if your workflow depends on per-user application directories.
Error: Avast detects WireLurkerDetectorOSX.py as trojan (see #19)
See the earlier entry — false-positive on the hardcoded path list.
Error: launch daemon won't unload during cleanup
Could not find specified service
Cause. The plist was removed before launchctl unload was called, or the daemon is referenced by a different label.
Solution. Use launchctl list | grep com.apple.machook to find the actual loaded label, then launchctl unload -w /Library/LaunchDaemons/<file>.plist.
Prevention. Always launchctl unload before deleting the plist.
Error: Time Machine restores reintroduce infected files
Cause. Time Machine backups from before the cleanup still contain the malicious files; when a user restores from those backups the infection can reappear. This is discussed in community issue #18.
Solution. Exclude or purge the infected paths from Time Machine backups (System Settings → Time Machine → Options → add exclusions) before restoring, and re-scan any restored system immediately.
Prevention. Document cleanup dates so users can make informed restore decisions.
Error: decryptor.py prints a Python traceback instead of plaintext
Traceback (most recent call last):
File "decryptor.py", line 23, in <module>
plaintext = des_cryptor.decrypt(base64.b64decode(encrypted_data))
...
Cause. The input is not a valid WireLurker-C message (wrong first-10-character prefix, corrupted base64, or a message from a different malware family).
Solution. Double-check that you passed exactly the captured C&C payload, unchanged, as a single quoted argument.
Prevention. Capture C&C traffic with a tool that preserves byte-for-byte payloads (tcpdump -w, Wireshark raw export) and pass the string as-is.
Error: python2 missing on modern macOS
Cause. Apple removed the system Python 2 in macOS 12.3. Homebrew's python@2 is long-archived.
Solution. Use a macOS VM with an older OS, or install Python 2.7 from source:
curl -O https://www.python.org/ftp/python/2.7.18/Python-2.7.18.tgz
tar xzf Python-2.7.18.tgz
cd Python-2.7.18 && ./configure && make && sudo make install
Prevention. For any long-term IR workflow that depends on Python 2 tools, keep a pinned VM snapshot with python2 pre-installed.
9. FAQ
Q: Is this tool still useful in 2025?
Only for forensics, research, and historical analysis. It matches the exact 2014 WireLurker indicators. It will not detect newer macOS malware, and modern macOS versions have closed several of the infection vectors WireLurker used. If you are cleaning up a legacy machine or writing a thesis on the 2014 campaign, yes — otherwise, prefer a modern endpoint tool.
Q: Does it need sudo?
Not strictly. The script itself never calls sudo. Some of the paths it checks may be restricted to root on modern macOS; running with sudo guarantees that the presence-check reaches them. For best results during incident response, run with sudo.
Q: Will it remove anything it finds?
No. The detector is read-only. Even the function that calls ls -ldO for the hidden-file fallback only reads metadata. You must remove flagged artifacts yourself.
Q: Why does my antivirus flag the script?
The file literally contains strings like /Library/LaunchDaemons/com.apple.machook_damon.plist. Signature-based scanners see the strings in the WireLurker IOC list and fire. This is a known false positive — see issue #19. Whitelist the file by hash.
Q: Why does the decryptor need the first 10 characters of the message?
Those characters encode the session key. The decryptor sums them as integers, appends the literal string dksyel, and uses the result as the DES-ECB key. Without those 10 bytes the ciphertext cannot be keyed correctly.
Q: Can I port this to Python 3?
Community patches exist in forks. The core changes are print → print(...), plistlib.readPlist → plistlib.load(open(p, 'rb')), and byte-vs-string handling in the subprocess.Popen.stdout.read() comparison. The upstream repository remains the original Python 2 release.
Q: Does it work on Apple Silicon (M1/M2/M3)?
Yes, as long as you have a working Python 2 interpreter. The script uses only os, stat, platform, plistlib, subprocess, and sys — all architecture-independent.
Q: What happens on macOS with APFS versus HFS+?
Both are supported. The hidden-file check uses UF_HIDDEN via os.stat(f).st_flags, which works on both filesystems. On systems where UF_HIDDEN is not available, the script falls back to ls -ldO … | grep hidden, which also works.
Q: Why is the is_file_hidden() fallback looking at $5 from ls -ldO?
ls -ldO prints file flags in the fifth column on BSD/macOS. The fallback path exists because very old Python builds did not expose stat.UF_HIDDEN. You will almost never hit this branch in practice.
Q: Does it detect iOS infections?
No. The original WireLurker campaign also infected iOS devices via USB pairing, but this tool only inspects the host macOS filesystem. Detecting a compromised iOS device requires inspecting it directly (provisioning profiles, installed IPAs).
Q: Is there a GUI version?
The README links to third-party Windows detectors, some with GUIs. There is no official Palo Alto Networks GUI build for macOS.
Q: Why does the repository contain HOWTO-Windows.md instead of a Windows script?
The repository documents the Windows detection logic (HOWTO-Windows.md) rather than shipping a binary. Two community implementations are linked from the README.
Q: Where does the "suspicious" path ~/Library/Caches/com.maiyadi.appinstaller/ come from?
maiyadi is the Chinese app distributor whose compromised installer vector WireLurker originally rode on. The cache directory indicates that the installer ran at some point, though not necessarily that the device is infected.
Q: What license is this under?
An ISC-style permissive license (Copyright © 2014, Palo Alto Networks, Inc.). You may copy, modify, and redistribute with attribution. See the LICENSE file for the exact wording.
Q: How do I contribute a fix?
The repository accepts pull requests; the last functional change was in 2014 and later commits are metadata changes. Open an issue before investing time in a large change.
Q: What's the difference between "malicious" and "suspicious" files in the output?
Malicious files are specific known-bad paths that WireLurker drops. Suspicious files are directories or paths associated with the installer's ecosystem (e.g. the maiyadi appinstaller cache) — they indicate elevated risk but can exist on clean systems that had the installer software briefly.
Q: Does it write logs anywhere?
No. All output goes to stdout. Redirect with > or tee if you need a log (see §6.2).
10. Reference
10.1 Hardcoded malicious paths (source: WireLurkerDetectorOSX.py → MALICIOUS_FILES)
| # | Path |
|---|---|
| 1 | /Users/Shared/run.sh |
| 2 | /Library/LaunchDaemons/com.apple.machook_damon.plist |
| 3 | /Library/LaunchDaemons/com.apple.globalupdate.plist |
| 4 | /usr/bin/globalupdate |
| 5 | /usr/local/machook/ |
| 6 | /usr/bin/WatchProc |
| 7 | /usr/bin/itunesupdate |
| 8 | /Library/LaunchDaemons/com.apple.watchproc.plist |
| 9 | /Library/LaunchDaemons/com.apple.itunesupdate.plist |
| 10 | /System/Library/LaunchDaemons/com.apple.appstore.plughelper.plist |
| 11 | /System/Library/LaunchDaemons/com.apple.MailServiceAgentHelper.plist |
| 12 | /System/Library/LaunchDaemons/com.apple.systemkeychain-helper.plist |
| 13 | /System/Library/LaunchDaemons/com.apple.periodic-dd-mm-yy.plist |
| 14 | /usr/bin/com.apple.MailServiceAgentHelper |
| 15 | /usr/bin/com.apple.appstore.PluginHelper |
| 16 | /usr/bin/periodicdate |
| 17 | /usr/bin/systemkeychain-helper |
| 18 | /usr/bin/stty5.11.pl |
10.2 Hardcoded suspicious paths (source: SUSPICIOUS_FILES)
| # | Path |
|---|---|
| 1 | /etc/manpath.d/ |
| 2 | /usr/local/ipcc/ |
| 3 | ~/Library/Caches/com.maiyadi.appinstaller/ |
| 4 | ~/Library/Saved Application State/com.maiyadi.appinstaller.savedState/ |
~ expands via os.path.expanduser('~').
10.3 .app infection markers (source: is_app_infected())
| Marker | Files checked | Trigger |
|---|---|---|
| Hidden executable swap | Contents/MacOS/<CFBundleExecutable>, Contents/MacOS/<CFBundleExecutable>_ |
Both hidden |
| Hidden trojan loader | Contents/Resources/start.sh, Contents/Resources/FontMap1.cfg |
Both hidden |
| Embedded installer | Contents/MacOS/appinstaller, Contents/Resources/infoplistab |
Both exist as files |
10.4 Exit codes
| Code | Meaning |
|---|---|
0 |
Clean |
1 |
Indicators found |
-1 |
Wrong OS, or interpreter/import failure |
10.5 Files in the repository
| File | Purpose |
|---|---|
WireLurkerDetectorOSX.py |
The macOS detector script. |
decryptor.py |
DES-ECB decryptor for captured WireLurker-C C&C traffic. |
HOWTO-Windows.md |
Text-only specification of the Windows detection logic. |
README.md |
Upstream usage notes. |
LICENSE |
ISC-style license text. |
10.6 External references
- Palo Alto Networks research article: http://researchcenter.paloaltonetworks.com/2014/11/wirelurker-new-era-os-x-ios-malware/
- Windows variant write-up: http://researchcenter.paloaltonetworks.com/2014/11/wirelurker-windows/
- Community Windows cleaner: https://github.com/ltfish/WireLurkerCleaner
- Community Windows detector: https://github.com/kaustubhsant/WireLurkerDetector