Mechanism
ADS-B ‘out’ is a periodic, one-way broadcast in which an aircraft reports its own
state — identity, position, velocity — with no interrogation, no association, no
encryption and no authentication [costin2012ghost][strohmeier2013survey]. Worldwide
it rides the 1090 MHz Mode S Extended Squitter (1090ES); in the US, lower-altitude
general aviation additionally uses a separate 978 MHz UAT link [strohmeier2017perception].
On 1090 MHz the signal is pulse-position modulation at 1 Mbps, and an Extended
Squitter is a fixed 112-bit frame (an 8 µs preamble followed by 112 µs of data
bits) [sun2021riddle]. There is no frequency hopping and no channelisation: every
aircraft squitters on the same carrier, so a single ~2 MHz receiver sees the whole
picture, and the only contention is overlapping bursts. On 1090 MHz the bit period
is 1 µs (a pulse in the first half of the period is a 1, in the second half a 0),
giving the 1 Mbps rate; the 978 MHz UAT link instead uses CPFSK at 1.041667 Mbps with
a 272-bit long message [sun2021riddle].
The 112-bit frame begins with a 5-bit downlink format. ADS-B uses DF17 for transponder-equipped aircraft and DF18 for non-transponder / TIS-B transmitters; it then carries the 24-bit ICAO aircraft address and a 5-bit type code that selects the payload — aircraft identification (the 8-character callsign), airborne or surface position (latitude/longitude in Compact Position Reporting, CPR, encoding), or velocity [sun2021riddle]. A 24-bit parity field lets a receiver validate the frame. Crucially, none of the identifiers is authenticated: the ICAO address, callsign and CPR position are broadcast in the clear with no signature and no integrity over the source, so a receiver cannot tell a genuine aircraft from a forged one [costin2012ghost][strohmeier2013survey].
This control verifies only the receive-and-decode baseline — the passive eavesdropping that the literature established is trivially feasible with a cheap SDR [costin2012ghost]. That same absent authentication is what makes the active attack families possible: experimental work has demonstrated message injection (‘ghost aircraft’), track modification, jamming and flooding against ADS-B receivers [schafer2013experimental][strohmeier2017perception]. Those are legally sensitive transmit operations on protected aviation safety spectrum and are assessed under the Attack-layer control, not here; this PHY control stays receive-only.
Procedure
Receive-only throughout. Capturing and decoding ADS-B is passive and generally lawful, but transmitting on 1090/978 MHz is not — do not transmit at any step here.
-
Confirm the band is alive before committing a decoder. Tune an SDR to 1090 MHz in a waterfall viewer and watch for the short, bursty Extended-Squitter pulses (ADS-B sits above the noise floor, so they are visibly bursty):
gqrx # set the device to your RTL-SDR, tune 1090.000 MHz, sample rate ~2.4 MSPSExpected: intermittent narrow pulses popping up at the carrier as aircraft squitter. If you see nothing, check the antenna/filter chain (a 1090 MHz band-pass filter + LNA dramatically lifts weak traffic) before blaming the decoder.
-
Decode the 1090ES link with a primary decoder. dump1090-fa demodulates the PPM bursts, validates the parity and decodes DF17/DF18, with an interactive table:
dump1090-fa --device-type rtlsdr --gain -10 --interactiveExpected: a live table of aircraft keyed by ICAO hex address, with callsign, altitude, position (once a CPR even/odd pair is collected) and speed. A handful of rows means a few local aircraft; a busy sky fills the table.
--gain -10selects the tuner’s automatic gain. -
Serve the decoded feed for downstream tooling. For a permanent or busy receiver, run readsb and emit network output (Beast/raw/JSON) instead of (or as well as) the interactive view:
readsb --device-type rtlsdr --net --write-json /run/readsbExpected: readsb starts, tracks many aircraft at once, and serves a JSON
aircraft.json(consumed by a map such as tar1090) plus Beast/raw ports — the handoff point to the Application-layer air-picture and plausibility controls. -
(US only) Add the 978 MHz UAT link. The 1090 decoders do not cover UAT; tune a second SDR to 978 MHz and run dump978 alongside:
dump978-fa --sdr driver=rtlsdr | readsb --net --net-only --uat-in-port 30978Expected: UAT downlink frames from lower-altitude general aviation, merged into the same aircraft picture.
-
Verify decode correctness on individual frames with pyModeS — the decode you can reason about by hand. Feed a hex frame to the CLI:
modes decode 8D406B902015A678D4D220AA4BDAExpected:
df 17,icao 406B90,typecode 4(identification), callsignEZY85MH— confirming the demodulated bits decode to a sensible identity. This is the per-frame ground truth behind the live table. -
(Optional) Demodulate inside a flowgraph instead of a black-box decoder, when you want to see each DSP stage (preamble correlation, bit slicing):
uhd_modes.py # gr-air-modes receiver, or run its GNU Radio flowgraphExpected: the same DF17/DF18 decode, with the signal processing exposed for inspection or modification.
Field case
A reproducible bench check using pyModeS’s own published example frames (no air capture or transmitter required), confirming the decode chain end to end. Decode a matched CPR even/odd airborne-position pair plus an identification and a velocity frame:
modes decode 8D40058B58C901375147EFD09357,8D40058B58C904A87F402D3B8C59,8D406B902015A678D4D220AA4BDA
The two 8D40058B… frames are the even and odd halves of one CPR position for ICAO
40058B; together they resolve to a single latitude/longitude. The
8D406B902015A678D4D220AA4BDA frame is a DF17 type-code-4 identification for ICAO
406B90, decoding to callsign EZY85MH. A globally-referenced position decode for a
single even frame (no pair needed) confirms the CPR maths against a known receiver
location:
modes decode 8D40058B58C901375147EFD09357 --reference 49.0 6.0
These are the canonical pyModeS test vectors, so the expected outputs are stable: a
40058B position near the 49.0 N, 6.0 E reference and the 406B90 / EZY85MH
identity. This is the verifiable, reproducible core of the field case — the decode
chain confirmed against fixed, published frames, with no air capture or transmitter
required.
Illustrative walkthrough — substitute the values you capture: on a real over-the-air session you would replace these vectors with live frames from step 2/3 and record the receiver-side numbers for the local environment. No author-measured live ADS-B capture is recorded here; the representative over-the-air figures — distinct aircraft seen over a session, fraction of frames passing parity, maximum range with/without a 1090 MHz LNA+filter — are [FILL: measured receiver statistics], to be filled from an authorised on-site capture.
Remediation
ADS-B’s exposure is architectural — the link is plaintext and unauthenticated by design [costin2012ghost][strohmeier2013survey] — so “remediation” at this layer is about not over-trusting the feed rather than securing the radio.
-
Developer (avionics / receiver firmware): do not treat a decoded DF17/DF18 frame as a trusted assertion of position or identity. Parity (the 24-bit CRC) proves the frame arrived intact, not that it came from the aircraft it names [sun2021riddle]. Where feasible, design toward the authenticated/integrity-protected ADS-B extensions and broadcast-authentication schemes proposed in the literature rather than the bare link [strohmeier2017perception].
-
Integrator (tracking / display / fusion systems): never rely on ADS-B as a sole source of truth. Fuse it with independent sensors (primary/secondary radar, multilateration that times the same frame at several stations to fix an aircraft independently of what it claims) and run plausibility checks — impossible kinematics, positions inconsistent across receivers, ICAO addresses that should not be airborne [schafer2013experimental][strohmeier2017perception]. These detections are implemented at the Application layer; this PHY capture is their input.
-
Operator (researcher / SOC running a receiver): keep receive-only — capturing and decoding ADS-B is passive and generally lawful, but transmitting on 1090/978 MHz is protected aviation safety spectrum and must never be radiated; any spoofing/ injection assessment belongs to the Attack-layer control and is done only on authorised research equipment over a conducted (cabled) or shielded (Faraday) path, never on-air [strohmeier2017perception]. Log receiver statistics so an anomalous flood or a ghost track is visible against a known baseline.