You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A Python tool for interacting with Microsoft's MAPS (Microsoft Active Protection
Service) cloud. Sends file reputation queries using the same Bond binary protocol
as Windows Defender and parses the response into human-readable verdicts.
Built through reverse engineering of mpengine.dll, MpCommu.dll, MpSvc.dll,
and live wire capture (ETW) of real Defender traffic.
Version strings are packed as 64-bit hex:
(major << 48) | (minor << 32) | (build << 16) | revision
Version String
Hex Encoding
10.0.26100 (OS)
a0000000065f4
1.1.26010.1 (Engine)
10001659a0001
4.18.26010.5 (Platform)
40012659a0005
Bond Serialization
The request and response use Microsoft Bond CompactBinaryV1 format, wrapped in a
Bonded<T> marshal envelope:
43 42 01 00 CB marshal header ("CB" + version 1)
[varint] schema_name Schema name as length-prefixed string
BT_STOP_BASE Base class terminator
BT_STOP_BASE
[field data...] Actual struct fields
BT_STOP End of struct
Field headers use a single byte: (ordinal_delta << 5) | bond_type. Values are
type-specific (varints for integers, length-prefixed for strings, nested for
structs/lists).
UrlReport Full Request Schema (RE'd from mpengine.dll 0x105251b2 by a5f83eb agent)
Ordinal
Field
Type
Description
F3
UrlReportGuid
STRING
Mandatory — report correlation GUID
F6
UrlList
STRUCT
Mandatory — contains LIST<UrlElement>
F9
UrlContext
STRUCT
Optional — LIST<UrlContextElement> with key/value pairs
F12
SigSeq
STRING
Mandatory — sig sequence number (formatted via "%llu")
F15
SigSha
STRING
Mandatory — sig SHA hash
F18
ReportOnly
BOOL
Omitted when querying; only set to 1 for fire-and-forget reports
Key Findings from RE (a5f83eb agent):
UrlReport (ordinal 1542) must be encoded as LIST<STRUCT> (not BT_STRUCT or
LIST<LIST<STRUCT>>). Using the wrong encoding causes HTTP 500.
Engine only sets UrlElement.F20 (url). Order and Url_Scrubbed are never written.
SigSeq and SigSha are mandatory fields — always set by the engine.
ReportOnly is omitted (not set to false) when querying for reputation.
Cloud protection level must be > 5 for URL reputation queries to proceed.
The UrlReport object allocates 0x850 (2128) bytes; Bond payload at offset +0x830.
AMSI CoreReport Fields (RE'd from mpengine.dll by aae86e9 agent)
Ordinal
Field
Type
Schema Table
Description
1325
AmsiAppId
STRING
CoreReport
AMSI host application (e.g. powershell.exe)
1328
AmsiSessionId
UINT32
CoreReport
AMSI session correlation ID
1364
AmsiUacIdentifier
STRING
CoreReport
UAC identifier for AMSI
1370
AmsiContentName
STRING
CoreReport
Content name/path being scanned
1371
AmsiContentName_Scrubbed
STRING
CoreReport
Scrubbed content name
1415
AmsiRedirectChain
STRING
CoreReport
Web redirect chain data
390
AmsiContext
STRING
BehaviorEvent
AMSI context in behavior reports
393
AmsiAction
STRING
BehaviorEvent
AMSI action in behavior reports
50
Script
STRING
StartupListElement
Raw script content
51
Script_Scrubbed
STRING
StartupListElement
Scrubbed script content
Verdict Logic
CLEAN: Response has Revision + SampleRate but NO SignaturePatches or ThreatDetails
MALICIOUS: SignaturePatches present (FASTPATH delivery) OR ThreatDetails with threat name/ID
SAMPLE_REQUESTED: SampleRequests present (cloud wants the file)
Response Sizes
Scenario
Size
Content
Clean/unknown file
88 bytes
Revision=5, SampleRate=1
Known threat + threat_id + fresh GUID
488 bytes
385-byte FASTPATH signature blob
Known threat (cached GUID)
88 bytes
Already delivered to this GUID
FASTPATH Dynamic Signatures
When MAPS confirms a threat, it delivers a binary FASTPATH signature — a
miniature VDM (Virus Definition Module) containing everything the local engine
needs to detect the threat without further cloud lookups.
FASTPATH Blob Structure (VDM TLV Format)
The signature blob uses the same TLV (Type-Length-Value) format as VDM database
files: sig_type(1) + size_low(1) + size_high(2) + payload(size).
Example: EICAR test file (385 bytes, 5 TLV entries):
GUID deduplication: MAPS delivers FASTPATH only once per machine GUID + file
hash combination. Use a fresh --machine-guid to get a new delivery.
Compilation timestamp: The FASTPATH_DATA entry contains a FILETIME showing when
the signature was compiled — typically seconds before delivery (real-time generation).
Complete threat group: The blob is a self-contained VDM threat group with
THREAT_BEGIN → detection sigs → THREAT_END, identical to what's in mpavbase.vdm.
The 0xEC envelope (256 bytes) contains encrypted detection logic. The engine
decrypts this at runtime for behavioral/pattern matching. The cleartext entries
(THREAT_BEGIN, STATIC) provide hash-based detection and metadata.
FASTPATH Wire Format (RE'd from mpengine.dll by af843a1 agent)
The engine's FASTPATH blob handler (fcn.1036dd82) dispatches based on outer TLV type:
A random UUID that identifies the client to MAPS. On real Defender, generated once
via UuidCreate() and stored persistently. Our tool generates one on first run and
saves it to ~/.maps_scanner/machine_guid (or uses --machine-guid override).
The server accepts any valid UUID — no registration required.
Consumer vs Enterprise
Mode
Auth
Header
Consumer
None (no Authorization header)
X-MS-MAPS-CUSTOMERTYPE: Consumer
Enterprise
Authorization: Bearer <AAD token>
X-MS-MAPS-CUSTOMERTYPE: Enterprise
Enterprise mode requires an Azure AD token from client ID
cab96880-db5b-4e15-90a7-f3f1d62ffe39 (Microsoft's registered app for Defender
Graph API access). This is NOT needed for basic MAPS lookups.
SOAP Path (Legacy, Deprecated)
The SOAP endpoint (/WdCpSrvc.asmx) returns HTTP 404 — Microsoft has fully
migrated to the Bond REST protocol. The SOAP path used WS-Security UsernameToken
with hardcoded credentials:
MAPS supports full file upload for cloud sandbox analysis ("cloud detonation").
When the cloud needs a file for deeper analysis, it responds with a
Bond_SampleRequest containing an Azure Blob Storage upload URL.
Sample Upload Flow
1. Client sends SpynetReport with file hash
│
2. MAPS responds with SampleRequest (F9):
├── REQUEST_GUID: Unique request ID
├── SHA1: File SHA1 hash
├── BLOB_SAS_URI: Azure Blob upload URL with SAS token
│ e.g. https://ussus1eastprod.blob.core.windows.net/container/blob?SAS
├── TTL: Request expiration time
├── COMPRESSION: Compression method
└── USE_QUARANTINE: Use quarantine storage
│
3. Client uploads entire file to Azure Blob via HTTPS PUT
(handled by MpAzSubmit.dll on real Defender)
│
4. Cloud sandbox detonates file:
- Behavioral analysis (API calls, file/registry changes, network)
- Machine learning classification
- Unpacking / deobfuscation
│
5. Results delivered as FASTPATH signatures on next query
Sample Submission Consent
Controlled by SubmitSamplesConsent registry setting:
Value
Meaning
0
Always prompt user
1
Send safe samples automatically (default)
2
Never send
3
Send all samples automatically
Implementation
Fully implemented. The upload CLI command supports:
Automatic SAS URI request from MAPS cloud
Direct upload to a provided SAS URI (--sas-uri)
Optional gzip/deflate compression (--compression)
Auto-upload on scan via scan --auto-upload
# Upload a file (request SAS URI from MAPS, then upload)
./maps_scanner --no-verify upload suspicious.exe
# Upload directly to a known SAS URI
./maps_scanner --no-verify upload file.exe --sas-uri "https://..."# Scan + auto-upload if MAPS requests it
./maps_scanner --no-verify scan file.exe --auto-upload
See MAPS_SAMPLE_IO.md for comprehensive sample input/output for all file types and commands.
AMSI Script Submission Architecture (RE'd)
AMSI (Antimalware Scan Interface) content is submitted through the standard
SpynetReport pipeline, not as a separate schema. Script content is embedded
within the CoreReport using STREAM_ATTRIBUTE metadata.
Flow
AMSI Host App → amsistream (eSCT_AMSI) → VFZ Plugin + Stream Buffer
→ SetAmsiReportPath() attaches to SCAN_REPLY
→ Bond_CoreReport serialization (AMSI fields + Script content)
→ Bond_SpynetReport wrapper → MAPS cloud
→ Cloud may respond with Bond_SampleRequest
→ MemorySampleReader + CSampleSubmission
→ Chunked upload to Azure Blob via BlobSasUri
Script content goes in dedicated fields (likely in StringReport nested struct):
Script (ordinal 50 in StringReport) — Raw script content
Script_Scrubbed (ordinal 51) — Sanitized/scrubbed version
Sample Upload for AMSI Content
Uses MemorySampleReader (vs FileSampleReader for files), controlled by
AllowedAmsiAppIdSampleSubmissions config — whitelists which AMSI host apps
can trigger sample uploads.