Lloyd Logs

Logging the things I am interested in && learning


RE - Fingerprint Sensor Driver

Chasing support for the Synaptics SYNA8002 / SYNA8006 fingerprint reader on Linux turned into a crash course in kernel driver prototyping and Windows driver reverse engineering. The DLL at the heart of the investigation is synaWudfBioSpi.dll, a Windows UMDF biometric driver installed via an INF that matches ACPI IDs SYNA8002 / SYNA8006.

Goal: Understand how Windows speaks SPI to the sensor well enough to reproduce the minimum viable protocol on Linux.

What this log covers

  • Structure of the Windows driver stack
  • Extracting high-signal breadcrumbs from strings and symbols
  • Navigating Ghidra when the listing initially looks “empty”
  • Separating import thunks from real call sites
  • Mapping out where the crypto and key handling logic likely resides

Building a Linux SPI proto driver

To experiment quickly, a simple kernel module was built as a raw SPI pipe, letting userspace poke the fingerprint sensor directly before investing in fprint / libfprint glue.

The driver:

  • Binds via an ACPI match table to SYNA8002
  • Exposes /dev/syna8002 as a character device
  • Caches the last userspace write as the TX buffer
  • On read, performs one spi_sync() transfer with the cached TX buffer (if any) and a fixed 512-byte RX buffer

Workflow:

  1. Write a command blob.
  2. Read back the device’s reply.
  3. Iterate on the protocol until it starts making sense.

Understanding the Windows UMDF driver layout

Files from the Windows driver package paint this stack:

  • UMDF service: synaWudfBioSpi.dll (SPI implementation)
  • WBDI / WinBio adapter: synaBscAdapter.dll
  • Loader indirection (Win10): synaDriverLoader.dll
  • Security components: SGX / TEE-related binaries for sensitive operations

Symbol names show a class-like layout:

  • CBiometricDeviceSPI::OnPrepareHardware
  • CBiometricDeviceSPI::OnReleaseHardware
  • CBiometricDeviceSPI::Read
  • CBiometricDeviceSPI::Write
  • CBiometricDeviceSPI::WriteRead
  • CBiometricDeviceSPI::OnInterruptIsr
  • CBiometricDeviceSPI::OnInterruptWorkItem

Together these imply a conventional lifecycle: initialise hardware, configure interrupts, then shuttle IOCTL/read/write requests.


Getting signal from strings and paths

strings synaWudfBioSpi.dll delivered actionable hints before any deep disassembly:

  • CBiometricDeviceSPI::* names create a mental map of capabilities.
  • synaWudfBioSpi.pdb confirms it was built with symbols.
  • Source path fragments (palSpiProtocol.c, palWinSpiDriver.c) suggest a Platform Abstraction Layer (PAL) where shared SPI logic lives, wrapped by platform-specific glue.

The working hypothesis: find the PAL entry points, and the SPI/crypto protocol will start revealing itself.


When Ghidra looks “empty”

The DLL is a normal x86-64 PE (PE32+) binary, not obviously packed. If Ghidra feels empty, it often means:

  • You’re staring at type definitions, not instantiated objects.
  • You’re looking at import thunks, not call sites.
  • You’re not traversing XREFs from the Imports tree into real code.

Once the navigation clicks (Symbol Tree → Imports → function → XREFs), meaningful analysis follows quickly.


Import thunks vs. real call sites

Windows imports yield three distinct views inside Ghidra:

  1. Thunk functions that simply JMP to the resolved DLL export.
  2. IAT pointers (Import Address Table) storing those resolved addresses.
  3. Actual call sites elsewhere in the binary that prepare parameters and jump through the thunk.

Example thunk:

BCryptImportKeyPair → JMP [->BCRYPT.DLL::BCryptImportKeyPair]

Seeing the thunk only proves the DLL calls Windows crypto. The interesting investigation happens at each XREF, where parameters—and therefore key buffers—are assembled.

Locating the ECC key import path

Following cross references to BCryptImportKeyPair leads to a call site that clearly imports an ECC private key:

LEA  R8, [u_ECCPRIVATEBLOB] ; pszBlobType = "ECCPRIVATEBLOB"
...
CALL BCryptImportKeyPair

Key observations:

  • The blob type string is not the key material.
  • Key bytes are passed via the pbInput stack parameter (Microsoft signature offset Stack[0x28]).
  • cbInput carries the blob length.

Tracing backwards shows the pbInput pointer originates from a buffer saved into locals such as local_60 / local_98, allocated and populated earlier. No static .rdata blob holds the key. Instead a helper function constructs the blob on the fly.


FUN_1800ebb70 as the crypto pivot

The helper in question, FUN_1800ebb70, appears throughout ECC import/export paths.

Parameters:

  • param_1: integer selector (values like 0x139, 0x13a hint at format variants)
  • param_2 / param_3 / param_4: pointers to buffers or context structures

Behaviour inferred so far:

  • Populates ECC blob headers.
  • Writes key material into the workspace buffer.
  • Hands the finished blob to BCryptImportKeyPair.

Adjacent helpers worth annotating next:

  • FUN_1800eba80
  • FUN_1800ebc30
  • FUN_1800ded30
  • FUN_1800decf0

What “reverse the crypto” really means

The objective is not to break ECC. It’s to mirror the data flow that Windows uses:

  1. Identify the primitives and APIs: ECC key import/generation, shared secret agreement, KDF, signing/verification.
  2. Understand the inputs: sensor identifiers, pairing blobs, registry-stored secrets.
  3. Replicate the derivation, blob formatting, and crypto steps on Linux.

Visualising the pipeline helps:

Device / sensor identity
        +
Stored secrets
Derived ECC key blob
Encrypted protocol session

Next targets

  • Annotate the crypto spine: fully decompile FUN_1800ebb70 and its adjacent helpers; rename locals/structs to capture the blob layout (headers, curve ID, private scalar length, etc.).
  • Track secret sources: find where registry entries, files, or ACPI-provided identifiers feed into the blob constructors.
  • Compare with SGX/TEE binaries: check whether synaTEE.signed.dll mirrors the same logic, especially if the true secret material resides inside the TEE.

Each of these should bring the Linux prototype closer to reproducing the Windows SPI and crypto handshake with confidence.