========================================================================== Vendor diagnostic, factory-test and provisioning tools in ``bin``/``xbin`` ========================================================================== ``artifacts/vendor_a/bin`` and ``artifacts/system_a/system/bin`` together hold several hundred native executables that had never been individually looked at in this project — only the ``.so`` HAL libraries and a handful of named tools had been. This page separates generic AOSP/toybox binaries from Qualcomm-vendor-specific ones with an actual per-file count, then disassembles the subset that could plausibly matter to a device with an unlocked/test-key-signed bootloader: diagnostic-port command surfaces, factory-test entry points, and provisioning tools that write into TZ-backed key storage. Everything below is read statically from the shipped binaries in ``artifacts/vendor_a`` and ``artifacts/system_a``. No code was executed, no device was connected, and no ``/dev/diag`` traffic was captured. Inventory methodology and counts ================================= ``artifacts/vendor_a/bin`` has **333** directory entries; ``artifacts/system_a/system/bin`` has **423**. Neither number is "native executables" — most entries in both directories are 7z-extracted **symlinks**, and 7z represents a symlink not as a filesystem link but as a plain regular file whose entire content is the literal link target text (confirmed by hand: ``artifacts/vendor_a/bin/cat`` is a 13-byte regular file containing exactly the 13 ASCII bytes ``toybox_vendor``, not an ELF header and not a real symlink inode). That extraction quirk is what makes a raw ``ls`` count meaningless and is the first thing the classification below controls for. Counting by content (not by name) across both directories: .. code-block:: text artifacts/vendor_a/bin (333 entries) 172 -> symlink-placeholder, target "toybox_vendor" (AOSP toybox multicall) 6 -> symlink-placeholder, target "toolbox" (legacy AOSP multicall) 23 -> real files, but shell scripts, not ELF (init.{qcom,qti,mdm,...}.sh, init.{keybox,erase_keybox,rpmb}.sh, qca6234-service.sh, checkpoint_gc) 2 -> directories misfiled alongside binaries (hw/, qmi-framework-tests/) 130 -> real ELF 64-bit AArch64 executables <- the actual RE surface artifacts/system_a/system/bin (423 entries) ~233 -> symlink-placeholders/one-line wrapper scripts (toybox x188, toolbox x6, iptables/netutils-wrapper x10, mke2fs x3, fsck.f2fs x3, apex linker/linker64 x5, ziptool x2, bzip2 x2, init, app_process64, hwservicemanager, ethtool, and five "cmd \"$@\"" one-liners for window/settings/ package/input/appops) 159 -> real ELF 64-bit AArch64 executables ~31 -> real shell scripts (recovery/init helpers, all stock AOSP) The **130 real ELF executables in vendor_a/bin** were then grepped by name for the standard Qualcomm/BSP vocabulary (``diag``, ``ftm``, ``qmi``, ``rpc``, ``cnss``, ``wcn``, ``ims``, ``qti``/``qcom``, ``sensor``, ``mdm``/``modem``, ``persist``, ``rmnet``, ``factory``, ``qsee``, ``tz``, ``hdcp``, ``keybox``, ``wigig``/``11ad``, ``wfd``) and by manual eyeballing of everything the grep missed. Of the 130: - **8 are stock AOSP/public tools**, confirmed by ``strings``/imports rather than name alone: ``awk`` and ``sh`` (AOSP's standalone one-true-awk and ``mksh`` builds — separate binaries from, not symlinks to, ``toybox_vendor``), ``toolbox`` and ``toybox_vendor`` themselves, ``dumpsys`` and ``logwrapper`` (plain AOSP framework/init helpers), and ``boringssl_self_test32`` / ``boringssl_self_test64`` (the public AOSP BoringSSL FIPS self-test binary, imports only ``libcrypto``/standard libc symbols, no vendor libraries). - **122 are vendor/Qualcomm-specific** by name and (for every one actually opened below) confirmed by their imported libraries and embedded strings — they link against ``libdiag.so``, ``libqmi_cci.so``, ``libnl.so`` + ``libwigig_ftm_flows.so``, ``libkeymasterprovision.so``, ``libhdcp1prov.so``/``libhdcp2p2prov.so``, QSEECom APIs, or similar Qualcomm-only libraries that don't exist on a generic AOSP device. ``artifacts/system_a/system/bin`` (the Android-15-vintage GSI-like ``system`` half of this device's :doc:`onyx-platform` A/B split) turned up **essentially nothing** in the same keyword pass beyond generic AOSP components that merely contain a matching substring — ``iptables``/``ip6tables`` (netfilter, public), ``sensorservice``, ``telecom``, ``debuggerd``, ``charger``, ``recovery-persist`` — all stock AOSP binaries with public, documented behaviour. No Qualcomm-vendor-named native binary exists in ``system/bin`` on this device; the entire vendor-diagnostic/factory-test/provisioning surface lives in ``vendor_a/bin``, consistent with the vendor/system version split described in :doc:`onyx-platform`. Of the 122 vendor-specific ``vendor_a/bin`` executables, **29** were opened and read (``file`` + size + imported-symbol list + full ``strings`` dump, cross-checked against their exact ``.rodata`` string offsets where a claim below depends on it): .. code-block:: text ftmtest ftm_flows_test myftm mm-audio-ftm diag_mdlog diag_klog diag_socket_log diag_uart_log diag_callback_sample diag_dci_sample test_diag ssr_diag fmfactorytest fmfactorytestserver fmconfig vendor_cmd_tool irsc_util KmInstallKeybox StoreKeybox hdcp1prov hdcp2p2prov qseecomd qseecom_sample_client secure_ui_sample_client vendor.qti.hardware.soter@1.0-provision qwes_cli athdiag cnss_diag sscrpcd ssgtzd dpmQmiMgr feature_enabler_client Five of those (``fmfactorytest``, ``fmfactorytestserver``, ``ftmtest``, ``KmInstallKeybox``, ``hdcp1prov``) were taken to full AArch64 disassembly with ``llvm-objdump -d`` plus manual ADRP/ADD string-literal resolution, because their strings suggested something worth confirming in code rather than trusting the string dump alone. Those five are the findings below. The remaining ~93 vendor-named binaries (``qrtr-ns``/``qrtr-cfg``/``qrtr-lookup``, ``pd-mapper``, ``netmgrd``, ``ipacm``/``ipacm-diag``, ``wpa_cli``, ``hostapd_cli``, ``loc_launcher``/``lowi-server``/``xtra-daemon``/ ``xtwifi-client``, ``wigighalsvc``/``wigig_wiburn``/``wigignpt``, ``wfdvndservice``/``wfdhdcphalservice``/``wifidisplayhalservice``, ``thermal-engine``, ``msm_irqbalance``, ``power_off_alarm``, ``poweropt-service``, ``rmt_storage``, ``subsystem_ramdump``, ``ssr_setup``, ``time_daemon``, ``tloc_daemon``, ``npu_launcher``, ``nn_device_test``, ``nativechitest``/``nativehaltest``, ``chifeature2test``/``chiofflinepostproctest``, and the ``ims*``/``imsrcsd`` family, among others) are Qualcomm reference-platform daemons and test harnesses for radio/IPA/location/thermal/display subsystems whose names, sizes and spot-checked library dependencies are consistent with their apparent public purpose (QMI/QRTR IPC plumbing, IMS/RCS daemons, WLAN location, thermal mitigation, NPU inference test harness, camera HAL conformance test binaries). They were not individually disassembled — there is no indication in their names or on-disk footprint that they differ from well-documented Qualcomm BSP components; individual entries for all 93 are omitted below rather than padding this page with unverified assumptions. Findings ======== FM radio factory test ----------------------- ``fmfactorytest`` (16,024 bytes) is a tiny CLI client; ``fmfactorytestserver`` (24,608 bytes) is the daemon it talks to over ``/dev/socket/fm_factory_socket_server`` (string at file offset ``0x9cc`` in ``fmfactorytest``'s ``.rodata``). Full disassembly of ``fmfactorytest``'s single ``.text`` blob (file offset ``0x1000``–``0x15dc``, no function symbols — the binary exports/imports only PLT stubs) shows: .. code-block:: text 0x1098 add x1, x1, #0xa2b ; "enable" (argv[1] compared via strcmp) 0x10b4 add x1, x1, #0x8f0 ; "disable" 0x1198 add x1, x1, #0x92d ; "tune" 0x120c add x1, x1, #0xa32 ; "seeknext" argv[1] must be exactly one of those four verbs. If the client can't ``connect()`` to the factory socket (``0x1150``–``0x1164``), it does not just fail — it **forks and, in the child, calls ``system()`` naming the server binary itself**: .. code-block:: text 0x1268 bl fork 0x126c cbz w0, 0x12d0 ; child branch ... 0x12d0 adrp x0, 0x0 0x12d4 add x0, x0, #0x96b ; "fmfactorytestserver" 0x12d8 bl system 0x12dc mov w20, w0 0x12e0 b 0x1188 ; back to log + continue the parent retries ``connect()`` up to 10 times with a ~15.7 ms (``0x3d40`` = 15680) ``usleep()`` between attempts (``0x1278``–``0x12c0``) before giving up. So invoking ``fmfactorytest`` with any recognised verb is sufficient, on its own, to spawn ``fmfactorytestserver`` via a bare ``system("fmfactorytestserver")`` call if it isn't already running — no absolute path, relying entirely on ``$PATH``. This is unremarkable as a *factory* tool (inferred: likely invoked by test harnesses that already control the environment, not confirmed). But it is a concrete, address-verified example of this device's diagnostic tooling using ``fork()`` + ``system()`` with a bare (non-absolute) command name, which is exactly the pattern that matters if ``$PATH``/environment trust ever becomes attacker-influenced in some other context on this device. The server side, once connected, accepts the same four verbs as colon-prefixed command strings, and drives them straight into the V4L2 kernel radio driver. ``strings`` on ``fmfactorytestserver`` shows ``/dev/radio0`` (offset ``0x11fd``) opened, and disassembly around the two ``ioctl()`` call sites at file offsets ``0x2388`` and ``0x23b8`` shows the request code built as: .. code-block:: text 0x236c mov w1, #0x561c 0x2380 movk w1, #0xc008, lsl #16 ; w1 = 0xc008561c 0x2384 str x8, [sp, #0x30] ; {control_id, value} = {0x08000003, 0x0e} 0x2388 bl ioctl ``0xc008561c`` decodes as the standard V4L2 ``_IOWR('V', 28, ...)`` — ``VIDIOC_S_CTRL`` (an 8-byte ``struct v4l2_control{__u32 id; __s32 value;}``, matching the ``0x08`` size field) — i.e. this is a plain V4L2 tuner/radio control-set ioctl, not anything proprietary. The FM factory-test path is, in the call sites traced here, a userspace shim over the standard Linux V4L2 radio API, with no proprietary or hidden logic found. WLAN "FTM" tools ------------------ ``ftmtest`` (34,344 bytes) and ``ftm_flows_test`` (28,568 bytes) sit right next to the Qualcomm-diag family's ``ftmdaemon``/``ftm_flows_test`` naming convention (where "FTM" = *Factory Test Mode*, the RF calibration mode most Qualcomm phones can be booted into), but are unrelated to it. Their imports (``nl_socket_*``, ``nla_*``, ``genl_*`` from ``libnl.so``; ``aoa_init``/``aoa_process`` from a private ``libaoa.so``; ``wigig_ftm_flows_*`` from ``libwigig_ftm_flows.so``) and usage strings (``"ftm [ []]: perform single-shot FTM measurement"``, ``"aoa ...: perform AOA measurement"``) show these are **WLAN location test tools**: they drive the 802.11mc **Fine Timing Measurement** protocol and **Angle-of-Arrival** ranging over ``nl80211`` vendor commands, for indoor-positioning RF calibration — an entirely different "FTM" than the Qualcomm diag/factory-test one. Naming collision, confirmed in code, not a shared code path. ``ftmtest``'s command dispatch (no function symbols; offsets below are file offsets within its single ``.text``) does four back-to-back ``strcmp()`` calls against the second command-line argument: .. code-block:: text 0x52d0 add x1, x1, #0x831 ; "capa" -> cbz -> 0x536c (table slot +0x00) 0x52ec add x1, x1, #0x742 ; "ftm" -> cbz -> 0x5358 (table slot +0x20) 0x5300 add x1, x1, #0x7fe ; "aoa" -> cbz -> 0x5360 (table slot +0x40) 0x5314 add x1, x1, #0x8c7 ; "ftmaoa" -> cbz -> 0x5368 (table slot +0x60) 0x5328 ... ; none matched -> "unknown command: %s", exit each match selects one of four 0x20-byte-stride entries in a static table (base ``x7000+0xd0``), and the actual handler is reached through an indirect call, ``blr x20`` at file offset ``0x53c4``, after a small range check (``0x5394``–``0x53b0``) that looks like an LLVM CFI jump-table guard rather than application logic (it pairs with the ``__cfi_slowpath``/``__cfi_check`` imports present throughout this binary — the whole ``vendor_a`` build appears to be CFI-instrumented, consistent with :doc:`security`'s description of this device's hardening baseline). ``capa``/``ftm``/``aoa``/``ftmaoa`` dispatch to "show location capabilities", single-shot FTM ranging, AOA measurement, and combined FTM+AOA respectively — all consistent with the usage strings and with nothing that looks like a hidden fifth command. Attestation-keybox provisioning tool (``KmInstallKeybox``) ------------------------------------------------------------- ``KmInstallKeybox`` (67,944 bytes) links ``libkeymasterprovision.so``, ``libqtikeymaster4.so``, ``libcrypto.so`` (X509/EVP calls) and ``libqmi_cci.so``, and exports the mangled C++ symbol ``keymasterdevice::KeymasterKeyProvision::KeyMasterInstallKeybox(km_install_keybox_t*)``. Per its own embedded usage text (which the disassembly below confirms is exactly, and only, printed by the argument-count-mismatch path — this is documentation, not enforced logic in this binary): .. code-block:: text KmInstallKeybox will install the attestationkeys (both RSA and ECC) along with all the device identifiers (brand, device, product, serial#, IMEI, MEID (if available), model and manufacturer). [...] Once 'Provisioning Success' state is set in KM TA / Strongbox, attestation keys / Device ID's cannot be re-provisioned **RMA Use Case ** For RMA use case, OEM's can set the following devcfg parameter in 'keymaster_oem_config.xml' Please ensure to sign this debug devcfg with the serial# of the device as this will enable re-provisioning of keys and if used incorrectly can open up the device to be re-provisioned. usage: LD_LIBRARY_PATH=/vendor/lib64/hw KmInstallKeybox Keybox_file Device_ID provision_device_ids(true/false) Strongbox_Keybox_file Strongbox_Device_ID strongbox_provision_device_ids(true/false) Disassembly confirms this text (three separate literals at file offsets ``0x37c3``, ``0x332a``, ``0x3e2e`` in ``.rodata`` — scattered inside a much larger, heterogeneous rodata blob, with roughly 3.3 KB of interleaved, unrelated Keymaster strings between them (``KM_TAG_*`` names, error messages like "SW enforced failed", "Meid: ", "SerialNum: ", etc.), not one contiguous help banner) is only reachable from the argc-mismatch path, printed via three back-to-back calls at file offsets ``0xaae0``, ``0xaaf0`` and ``0xab00`` into an internal ``puts``-style wrapper at ``0x5388``, immediately followed by ``mov w0, #-0x1; bl exit`` at ``0xab10``–``0xab14``. This is Qualcomm's own documentation of a device-identity re-provisioning mechanism, gated (per that same text) by a signed devcfg property rather than by anything in this userspace binary — the signature check, if enforced, lives in the Keymaster TA, which this static pass did not reach (see *Honest limits*). It is reported here because it is a factory/RMA-only capability to re-provision attestation identity and key material, shipped, unremoved, in a consumer retail image, and worth knowing about for anyone reasoning about this device's attestation trust boundary — not because a working bypass was demonstrated. ``StoreKeybox`` (33,432 bytes, UBSan-instrumented, plain ``ifstream``-based) is the sibling tool that reads a keybox file from disk; it was string- and import-level examined but not disassembled — its behaviour (open file, parse, store) is unremarkable relative to ``KmInstallKeybox`` and adds nothing this page didn't already cover. HDCP1 key-provisioning tool (``hdcp1prov``) ----------------------------------------------- ``hdcp1prov`` (11,648 bytes) is small enough to disassemble in full. It links only ``libhdcp1prov.so``, ``libdiag.so`` and ``liblog.so``, and exports nothing beyond the CRT stubs — all logic funnels through two imports, ``HDCP1_key_provision`` and ``HDCP1_key_verify``. Reading ``main`` (file offset ``0x106c``–``0x130c``): .. code-block:: text 0x1088 ldr x0, [x19, #0x8] ; argv[1] 0x1090 add x1, x1, #0x839 ; "-verify" 0x1094 bl strcmp 0x1098 cbz w0, 0x10c4 ; argv[1]=="-verify" (and argc==2) -> verify path ... 0x119c bl HDCP1_key_verify ; called with w0=1 (a fixed "type") ; --- provisioning path (argv[1] != "-verify") --- 0x1114 ldr x0, [x19, w25, uxtw #3] 0x1118 bl atoi ; "type" = atoi(argv[last]) 0x111c sub w8, w0, #0x1 0x1124 cmp w8, #0x3 0x1128 b.hs 0x127c ; reject unless type in {1,2,3,4} ... 0x1144 ldr x0, [x19, #0x8] ; argv[1] = KEY_FILE 0x1150 bl fopen ; mode string at offset 0x837 ("r") 0x1170 bl fread_unlocked ; up to 1000 bytes into a static buffer ... 0x11f0 ldr x0, [x19, #0x10] ; argv[2] = DPS_FILE 0x11fc bl fopen ; mode string at offset 0x781 ("rb") 0x1214 bl fread_unlocked ; exactly 16 bytes (a "DPS" seed) 0x1218 cmp x0, #0x10 0x121c b.ne 0x12fc ; must read exactly 16 bytes 0x1238 bl HDCP1_key_provision ; (keybuf<=1000B, type 1..4, dps[16], 16) There is no signature check, no hash comparison, no authentication of either input file anywhere in this binary — it reads whatever bytes are at the given paths (up to 1000 bytes of key material, exactly 16 bytes of "DPS", and an attacker/operator-chosen small integer selecting one of four HDCP1 key "types") and hands them straight to ``HDCP1_key_provision()`` in ``libhdcp1prov.so``. Whatever cryptographic gate exists between that library call and actually writing HDCP1 device keys into secure storage is inside ``libhdcp1prov.so`` and/or the TrustZone/QSEE side it may call into (unconfirmed) — static analysis did not follow that library (see *Honest limits*). ``hdcp2p2prov`` (11,640 bytes) is the HDCP2.2 sibling with the identical structure (``HDCP2P2_key_provision``/``HDCP2P2_key_verify``); it was string- and import-level examined but not separately disassembled since the pattern is the same. Honest limits ============== - **The security-relevant gating for both the keybox-reprovisioning path and the HDCP key-provisioning path was not located.** For ``KmInstallKeybox``, the "sign the devcfg with the device serial#" check its own help text describes is not implemented in this binary (it just prints the help text) — it must live in the Keymaster TA (``libqtikeymaster4.so`` / the in-TZ keymaster trustlet), which is a stripped shared library, and further in a secure-world trustlet image, neither of which was disassembled here. For ``hdcp1prov``/``hdcp2p2prov``, the equivalent question — whether ``HDCP1_key_provision()`` inside ``libhdcp1prov.so`` performs any authentication before writing to secure storage, or whether that responsibility is pushed even further down into TZ — was not answered; ``libhdcp1prov.so`` was not disassembled. - **Whether any of these binaries is actually reachable by an unprivileged or even an ``adb shell`` caller on this device was not determined.** No SELinux policy (``vendor/etc/selinux``) or executable permission bits were cross-checked; several of these look, from their names and "for RMA use" documentation, like factory-line-only tools that would normally be gated by SELinux domain transitions and/or physical factory-jig-only invocation, not general userspace reachability. This page establishes *what the binaries do if invoked*, not *who can invoke them*. - **93 of the 122 vendor-specific ``vendor_a/bin`` executables were classified by name/library/size only, not opened.** The 29 that were opened (listed above) are the ones whose names indicate diagnostic, factory-test, or key-provisioning functionality; nothing found suggests the unopened remainder contains something those 29 don't already represent, but that is an inference from naming convention, not a verified claim about each of those 93 files. - No live device was used anywhere in this investigation; every claim above is read directly from the static ELF images. Provenance ========== :Source: ``artifacts/vendor_a/bin/{fmfactorytest,fmfactorytestserver,ftmtest, ftm_flows_test,myftm,mm-audio-ftm,diag_mdlog,diag_klog,diag_socket_log, diag_uart_log,diag_callback_sample,diag_dci_sample,test_diag,ssr_diag, fmconfig,vendor_cmd_tool,irsc_util,KmInstallKeybox,StoreKeybox,hdcp1prov, hdcp2p2prov,qseecomd,qseecom_sample_client,secure_ui_sample_client, vendor.qti.hardware.soter@1.0-provision,qwes_cli,athdiag,cnss_diag, sscrpcd,ssgtzd,dpmQmiMgr,feature_enabler_client}`` and the full ``artifacts/vendor_a/bin`` (333 entries) / ``artifacts/system_a/system/bin`` (423 entries) directory listings, all extracted read-only with ``7z`` from ``artifacts/super/vendor_a.img`` and ``artifacts/super/system_a.img`` respectively (ext2/ext4 images extracted with ``7z x``). :Method: Directory classification done by reading raw file content/size (not trusting ``ls``) to separate 7z's symlink-as-text-file artifacts from real ELF binaries, then keyword-grepping and manually eyeballing the remainder. Per-binary triage used ``file``, byte-size, and a macOS-``strings`` (``strings -n 6``) dump of each candidate. The five deep-dived binaries were fully disassembled with the pixi ``llvm-objdump -d --no-show-raw-insn`` (AArch64, resolves imported-symbol names at PLT stubs directly since these are small non-stripped-import executables with intact ``.dynsym``/section headers, unlike the large stripped ``.so`` files documented elsewhere in this project). Every ``.rodata`` string cited by file offset was independently confirmed with a short Python script reading the raw bytes at that offset out of the binary — not read off the ``strings`` dump positionally, since ``strings`` does not report offsets by default. The project's existing ``artifacts/re_static/{sodis,elfdis}.py`` capstone helpers were evaluated but not used for the final excerpts above (they are built for stripped, section-header-light ``.so`` files; these binaries have full section headers and dynamic symbol tables, so vanilla ``llvm-objdump -d`` resolves PLT call targets more directly). :Cross-refs: :doc:`security` (QSEECOM/TrustZone bridge, attestation keybox and HDCP/ Widevine provisioning this page's ``KmInstallKeybox``/``hdcp1prov``/ ``hdcp2p2prov`` findings sit underneath), :doc:`onyx-platform` (the vendor/system version split that puts the entire vendor-diagnostic surface found here on the ``vendor_a`` side and none of it on ``system_a``), :doc:`platform-boot` (SELinux domain context these binaries would run under, not independently verified here).