Cross-Cutting — On-Device Machine Learning

SigTree ML Classification

Decision Tree Ensemble — 33,428 Trees JIT-Compiled to Native x86

0Decision Trees
3Signature Types
6Node Types
JITx86 Compilation

sigtree @ 0x109c80b0 • jit_emitter @ 0x100f226f • mpengine.dll

What SigTree Does

SIG_TREE is Windows Defender's on-device machine learning classification system. It implements a decision tree ensemble that evaluates boolean predicates over accumulated signature attributes (sigattr) to produce ML-based detections.

Unlike cloud-based ML (MAPS/SpyNet), SIG_TREE runs entirely locally using decision trees shipped in the VDM signature databases. This is a critical detection layer producing !MTB and !ml suffixed threat names.

SIG_TREE is NOT a separate pipeline stage. It runs as a supporting engine within the Static Engine Cascade (Stage 03) and during BM evaluation.

Detection Suffixes !MTB — Machine Learning / Tree-Based !ml — Machine Learning classification
Example Detections Trojan:Win32/Emotet.RPX!MTB Trojan:Win32/AgentTesla!ml
Key Insight Trees evaluate over the sigattr log — a running record of boolean feature attributes set by all prior pipeline stages

Architecture & Data Flow

From VDM signature database to ML detection verdict

1. VDM Parsing — Parse SIG_TREE TLV entries (0x40, 0x41, 0xB3)
5-byte header + 16-byte nodes → expanded to 32 bytes in memory
2. Feature Accumulation — Pipeline stages deposit sigattr events
Stage 3: PEHSTR/STATIC • Stage 5: PE emu • Stage 8: NScript JS • Stage 9: BRUTE • Stage 10: Lua
3. SigAttr Log — Circular head/tail log of boolean attributes
sigattr_head @ 0x1097d710 • sigattr_tail @ 0x1097d720 • 32 bytes per entry
4. JIT Compile & Evaluate — Tree nodes compiled to native x86 MOV instructions
jit_emitter @ 0x100f226f • JIT buffer at [esi+0x37d4] • lfence for Spectre mitigation
5. Detection — !MTB / !ml threat name + metadata
peattributes, imphash, clusterhash, sigattrevents, researchdata

Three Signature Types — 33,428 Trees

0 SIG_TREE (0x40) @ 0x10986C88

Standard decision trees. Fixed 16-byte nodes. Node type marker 0x30. Evaluates PE and file attributes.

0 SIG_TREE_EXT (0x41) @ 0x10987008

Extended trees with embedded inline strings (file paths, URLs). Variable-length nodes with 0x90 wildcard escapes.

0 SIG_TREE_BM (0xB3) @ 0x109871D4

Behavioral monitoring trees. Node type marker 0x40. UTF-16LE patterns for behavioral indicators.

// Confirmed from VDM dumps: 05 00 01 03 00 // 5 nodes, ver 1, type 3, flags 0 (SIG_TREE — Agent) 09 00 01 03 00 // 9 nodes, ver 1, type 3, flags 0 (SIG_TREE — Agent) 02 00 01 02 00 // 2 nodes, ver 1, type 2, flags 0 (SIG_TREE_BM — ModifiedAutoRunInf)

VDM Binary Format

5-byte TLV header + 16-byte fixed-length nodes, expanded to 32 bytes in memory

TLV Entry Header (5 bytes)

Offset Size Field ------ ---- ----- 0x00 2 node_count (uint16 LE) 0x02 1 version (0x01=std, 0x02=ext) 0x03 1 tree_type (0x03=SIG_TREE, 0x02=BM) 0x04 1 flags // total_size = 5 + (node_count * 16) // Example: 5 nodes = 5 + 80 = 85 bytes

16-Byte Node (On-Disk)

Offset Size Field ------ ---- ----- 0x00 2 flags / child_info 0x02 2 secondary data 0x04 1 attribute_index (sigattr ref) 0x05 1 node_type_marker (0x30/0x40) 0x06 1 mode/subtype 0x07 4 hash/CRC value 0x0B 5 secondary / padding

In-Memory Expansion (32 bytes)

// At 0x1012b05d: sar eax, 5 // divide by 32 // Tree data loader @ 0x1012b02a: node_count = (end_ptr - start_ptr) >> 5 // Expansion adds: // - Resolved child pointers // - Pre-computed eval state // - Alignment padding

Variable-Length Nodes (EXT)

SIG_TREE_EXT entries contain embedded inline strings with wildcard patterns:

c:\windows\system32\*.dll c:\windows\temp\*.exe http://*.hotmail.ru/flashcard/*.iso // 0x90 wildcard escape byte: 0x90 0x02 0x08 // 8-char min match 0x90 0x02 0x10 // 16-char min match 0x90 0x00 // end-of-pattern

Tree Node Semantics

Binary decision tree with 6 node types — string table at 0x10987530

6 Node Types

attribute 0x10987530 — Leaf: checks a specific sigattr feature
matched 0x1098753c — Terminal: indicates a match result
p1 0x1098754c — Predicate 1: first boolean child (true)
p2 0x10987550 — Predicate 2: second boolean child (true)
np1 0x10987558 — Negated Predicate 1 (false branch)
np2 0x10987548 — Negated Predicate 2 (false branch)

Decision Tree Structure

// Binary decision tree example: [attribute: js_hasBigString?] / \ [p1: yes] [np1: no] | | [attribute: highEntropy?] [matched: clean] / \ [p2: yes] [np2: no] | | [matched: [matched: Trojan] clean]
child_type byte at offset 0x18
0 = Null/empty (leaf/terminal)
1 = Inline string data
2 = Vector/buffer reference
3 = Sub-tree reference (recursive)

JIT Compilation to Native x86

Trees are NOT interpreted — they are JIT-compiled into executable MOV instruction buffers

JIT Emitter @ 0x100f226f

// JIT Buffer Location: base = [esi + 0x37d4] // buffer base offset = [esi + 0x37dc] // write pos write_ptr = base + offset // 4-way switch on operand type: case 0: 0xC6 // MOV byte [addr], imm8 // 3 bytes total case 1: 0xC766 // MOV word [addr], imm16 // 5 bytes total case 2: 0xC7 // MOV dword [addr], imm32 // 6 bytes total case 3: 0xC7x2 // Two MOV dword instrs // 13 bytes total

Evaluation Pipeline

1. Load tree from node array (32-byte stride)
2. JIT compile tree nodes into MOV instructions
3. Execute native code against sigattr log
4. Result matched = true/false per tree
Genuine JIT Compilation x86 MOV immediate instructions written directly into executable buffer and executed natively
Spectre Mitigation lfence at 0x1073fe5f before pointer dereference

Signature Attribute (SigAttr) Log

The feature vector SIG_TREE evaluates over — circular head/tail log of boolean attributes

Log Structure

struct SigAttrLog { flags: u32, // +0x30: bit 2 = available log_data: *LogData, // +0x44 } struct LogData { head_log: Vec<Entry>, // +0x08: recent tail_log: Vec<Entry>, // +0x0C: older } struct SigAttrEntry { // 32 bytes per entry (shl edi, 5) // Boolean attribute state }

Lua API Access

sigattr_head @ 0x1073dfe0 — Head log entries
sigattr_tail @ 0x1073acb0 — Tail log entries
this_sigattrlog @ 0x1008bc52 — Current log

Result Metadata Parser

sigattr_events_parser @ 0x10564d00 parses semicolon-delimited key=value strings:

peattributes= PE header attributes
sigattrevents= Sigattr event list
imphash= Import hash
clusterhash= Cluster hash
researchdata= Research / telemetry data
LoopILHash= IL loop hash
PDBProject= PDB project path

Feature Sources

SIG_TREE evaluates over features collected from multiple pipeline stages

BRUTE Features (Stage 9)

BRUTE:PDF:Feature:* @ 0x10A54CC8
BRUTE:VBS:Feature:* @ 0x10A54D08
BRUTE:JS:Feature:* @ 0x10A54D1C

NScript JS Features (Stage 8)

21 boolean features extracted during JS deobfuscation:
js_hasBigString, js_hasEval,
js_hasBase64, js_hasNetworkCalls,
js_hasObfuscatedNames, ...

PE Attributes (Stage 3/5)

PE header metadata from static analysis and emulation
Reported via peattributes= in result structure
HSTR:, SIGATTR:, KCRCE: from static cascade

Lua Script Attributes (Stage 10)

Arbitrary attributes via mp.setattribute()
Feed directly into sigattr log
Enable complex multi-stage feature chains
All features converge in the sigattr log The circular head/tail log accumulates boolean attributes from every pipeline stage, giving SIG_TREE a holistic view of the file under analysis

Scoring & Detection Arbitration

Weighted scoring over sigattr slots with priority-based detection selection

Weighted Scoring (FUN_1007ced5)

// Per-node weight from sig_flags bytes 2-3 // 26,165 unique weight values observed slot = base + attr_idx * 0x90 - 0x2C4 slot[1] += weight if slot[0] < slot[1]: slot[0] = slot[1] // high-water // Threshold gates: if weight > 0x10: best score tracking if weight > 0x13 && cat==0x06: escalation // Per-tree totals: ~1,075 to ~64,256

PE Boolean Attributes

// Table @ 0x00982F30 (~300 flags) lastscn_writable 0x00 no_relocs 0x03 packed 0x11 isdll 0x16 entrybyte55 0x1E PUSH EBP issuspicious 0x28 W+X section 0x67 executable_image 0x7A nx_bit_set 0x8D aslr_bit_set 0x9D

Priority Arbitration (FUN_1018d68b)

Level 1 (Highest): Named threat
e.g. Trojan:Win32/Foo.A!MTB — first match wins, short-circuits
Level 2: Generic heuristic
e.g. HLL/Generic — lower priority, suppressible
Infrastructure: InfrastructureShared
Classifiers only — not user-visible threat names

7 Tree Types

0 UNKNOWN 196 trees 1 LEAF 1,264 trees 2 EXT 14,731 trees (BM) 3 BM 8,607 trees 4 PEST 358 trees (PE static) 5 NID 6,961 trees 6 MACRO 1,311 trees

Key Functions & Addresses

14 core functions from reverse engineering mpengine.dll

Core Functions

SIG_TREE_Init 0x104c05a0
NodeExpansion 0x104bd759 — 16B VDM → 36B
Finalization 0x104bdc13 — sort + group
NodeDispatcher 0x1007ccdd — marker 0x30
SlotComparison 0x1007ced5 — weighted score
DetectionArbitrator 0x1018d68b — L1 > L2
jit_emitter 0x100f226f (216 bytes)

VDM Statistics

0Total Nodes
0Inline Strings
0Unique Weights

Object Offsets

+0x2240 Tree data pointer +0x32c Active tree vector +0x37d4 JIT buffer base pointer +0x37dc JIT buffer write offset +0x82ee4 Sigattr events array +0x836e4 Sigattr event count

SigTree ML: Summary

0Decision Trees
0Total Nodes
0Inline Strings
0Unique Weights

On-Device ML Classification

Decision tree ensemble evaluates boolean predicates over accumulated sigattr features. Produces !MTB and !ml suffixed detections entirely locally.

JIT-Compiled for Speed

Trees are JIT-compiled to native x86 MOV instructions at 0x100f226f for maximum evaluation throughput. Not interpreted.

Cross-Stage Feature Aggregation

The sigattr circular log accumulates boolean features from Stages 3, 5, 8, 9, and 10 — giving trees a holistic view of the file.

Critical Detection Layer

A substantial portion of modern Defender detections are !MTB verdicts. Without SIG_TREE, many threats go undetected.

All addresses from RE of mpengine.dll v1.1.24120.x — 33,428 tree entries across 3 signature types