Enable NexMon Monitor Mode & Packet Injection on Android (Broadcom chips)

Overview

Most modern Android phones embed a Broadcom/Cypress Wi-Fi chipset that ships without 802.11 monitor mode or frame-injection capabilities. The open-source NexMon framework patches the proprietary firmware to add those features and exposes them through a shared library (libnexmon.so) and a CLI helper (nexutil). By pre-loading that library into the stock Wi-Fi driver, a rooted device can capture raw 802.11 traffic and inject arbitrary frames – eliminating the need for an external USB adapter.

This page documents a fast workflow that takes a fully-patched Samsung Galaxy S10 (BCM4375B1) as an example, using:

  • NexMon Magisk module containing the patched firmware + libnexmon.so
  • Hijacker Android application to automate monitor-mode toggling
  • Optional Kali NetHunter chroot to run classic wireless tools (aircrack-ng, wifite, mdk4 …) directly against the internal interface

The same technique applies to any handset that has a publicly available NexMon patch (Pixel 1, Nexus 6P, Galaxy S7/S8, etc.).


Prerequisites

  • Android handset with a supported Broadcom/Cypress chipset (e.g. BCM4358/59/43596/4375B1)
  • Root with Magisk ≥ 24
  • BusyBox (most ROMs/NetHunter already include it)
  • NexMon Magisk ZIP or self-compiled patch providing:
  • /system/lib*/libnexmon.so
  • /system/xbin/nexutil
  • Hijacker ≥ 1.7 (arm/arm64) – https://github.com/chrisk44/Hijacker
  • (Optional) Kali NetHunter or any Linux chroot where you intend to run wireless tools

Pre-flight checks: verify firmware, driver and SELinux first

Before debugging Hijacker or aircrack-ng, confirm what the phone actually loaded:

su
getenforce
nexutil -V
getprop | grep -E 'vendor.wlan|wlan\.driver|wlan\.firmware|wifi\.interface'
  • On bcm4375b1, the upstream NexMon tree currently ships monitor/injection patches for 18.38.18 (Galaxy S10) and 18.41.8.9 (Galaxy S20). If your ROM has already moved to a newer firmware such as 18.41.113 or 18.41.117, reusing the old patch often leads to a misleading state where nexutil appears to succeed but iw wlan0 info still shows managed mode or capture tools see zero frames.
  • Upstream now also contains raw bcm4375b1 firmware directories for 18.41.113 and 18.41.117, but the public monitor/injection patch directories still stop at 18.38.18 and 18.41.8.9. Having the newer blob in firmwares/ does not mean there is already a matching Android monitor/injection patch in patches/.
  • On the older S10/S20 workflow, getenforce usually needs to be Permissive (or the SELinux policy must be patched) or nexutil / libnexmon.so ioctls may be blocked before they reach the Broadcom driver.
  • If you only want to validate the patch quickly, upstream NexMon also supports the minimal monitor-mode toggle nexutil -m2; there is no need to create a separate wlan0mon interface.

Flashing the NexMon patch (Magisk)

  1. Download the ZIP for your exact device/firmware (example: nexmon-s10.zip).
  2. Open Magisk -> Modules -> Install from storage -> select the ZIP and reboot. The module copies libnexmon.so into /data/adb/modules/<module>/lib*/ and ensures SELinux labels are correct.
  3. Verify installation:
    ls -lZ $(find / -name libnexmon.so 2>/dev/null)
    sha1sum $(which nexutil)
    

Configuring Hijacker

Hijacker can toggle monitor mode automatically before running airodump, wifite, etc. In Settings -> Advanced add the following entries (edit the library path if your module differs):

Note: Hijacker is discontinued upstream, but it is still useful as a GUI wrapper on already-supported devices. For newer Android builds, manual nexutil commands are usually easier to troubleshoot than the GUI.

Prefix:
LD_PRELOAD=/data/user/0/com.hijacker/files/lib/libnexmon.so

Enable monitor mode:
svc wifi disable; sleep 2; ifconfig wlan0 up; nexutil -s0x613 -i -v2

Disable monitor mode:
nexutil -m0; svc wifi enable

Enable “Start monitor mode on airodump start” so every Hijacker scan happens in native monitor mode (wlan0 instead of wlan0mon).

If Hijacker shows errors at launch, create the required directory on shared storage and reopen the app:

mkdir -p /storage/emulated/0/Hijacker

What do those nexutil flags mean?

  • -s0x613 Write firmware variable 0x613 (FCAP_FRAME_INJECTION) → 1 (enable TX of arbitrary frames).
  • -i Put interface in monitor mode (radiotap header will be prepended).
  • -v2 Set verbose level; 2 prints confirmation and firmware version.
  • -m0 Restore managed mode (used in the disable command).

After running Enable monitor mode you should see the interface in monitor state and be able to capture raw frames with:

airodump-ng --band abg wlan0

Quick validation before opening wifite / hcxdumptool

On newer LineageOS / NetHunter builds, test the plumbing manually first so you can distinguish a GUI problem from a real firmware/driver mismatch:

su
svc wifi disable
sleep 2
ifconfig wlan0 up
nexutil -m2
LD_PRELOAD=/path/to/libfakeioctl.so tcpdump -i wlan0 -c 20
# Optional: force a chanspec if only one band/channel appears
nexutil -k6/20
nexutil -k36/80
  • nexutil -m2 is the fastest passive-monitor sanity check.
  • -k sets the chanspec; string forms such as 6/20 or 36/80 are accepted by nexutil.
  • On some recent S10 NetHunter builds, Hijacker initially keeps scanning on the last band/channel Android was using. If 5 GHz results look incomplete, restart the scan or pin the chanspec manually with nexutil -k....

Manual one-liner (without Hijacker)

# Enable monitor + injection
svc wifi disable && sleep 2 && ifconfig wlan0 up && nexutil -s0x613 -i -v2

# Disable and return to normal Wi-Fi
nexutil -m0 && svc wifi enable

If you only need passive sniffing, omit the -s0x613 flag.

LD_PRELOAD naming gotcha (libnexmon.so vs libfakeioctl.so)

The upstream NexMon documentation uses LD_PRELOAD=libfakeioctl.so because many tools (tcpdump, airodump-ng, aireplay-ng) expect a radiotap-capable monitor interface. On several Android/Magisk bundles, the preload helper exposed to user space is instead named libnexmon.so, which is why Hijacker examples usually reference that file.

If a tool behaves differently depending on the preloaded library, try both names before assuming the patch is broken:

LD_PRELOAD=/path/to/libnexmon.so airodump-ng wlan0
LD_PRELOAD=/path/to/libfakeioctl.so tcpdump -i wlan0

Also remember that NexMon keeps using wlan0 directly; many Android builds will not create a separate wlan0mon interface even when monitor mode is active.


Using libnexmon inside Kali NetHunter / chroot

Stock user-space tools in Kali do not know about NexMon, but you can force them to use it via LD_PRELOAD:

  1. Copy the pre-built shared object into the chroot:
    cp /sdcard/Download/kalilibnexmon.so <chroot>/lib/
    
  2. Enable monitor mode from the Android host (command above or through Hijacker).
  3. Launch any wireless tool inside Kali with the preload:
    sudo su
    export LD_PRELOAD=/lib/kalilibnexmon.so
    wifite -i wlan0        # or aircrack-ng, mdk4 …
    
  4. When finished, disable monitor mode as usual on Android.

Because the firmware already handles radiotap injection, user-space tools behave just like on an external Atheros adapter.

When the ROM is newer than the published patch

If nexutil -V reports a newer bcm4375b1 firmware than the patch you flashed, the problem is usually firmware-porting, not Hijacker itself.

  • Current public Android workflows are still centred around the older 18.38.18 (S10) and 18.41.8.9 (S20) patch sets.
  • The upstream tree now includes raw firmware blobs / definitions for 18_41_113_sta and 18_41_117_sta, but the public patches/bcm4375b1/ directory still only contains 18_38_18_sta and 18_41_8_9_sta. Newer blobs alone are not enough.
  • For newer Samsung builds (18.41.113, 18.41.117, etc.), the practical approach is to copy the closest working patch directory (usually patches/bcm4375b1/18_41_8_9_sta) and rebase patch / wrapper addresses with BinDiff or IDA.
  • The files that normally need attention are version.mk, patch.ld, include/local_wrapper.h, src/local_wrapper.c, src/ioctl.c, src/monitormode.c, src/injection.c, and the related wrapper/version sources.
  • On Android 12+ / One UI 4+ era ROMs, a driver/firmware ABI change can still break monitor mode even when Wi-Fi comes up and nexutil -V shows the expected version. Treat nexutil -V as a necessary check, not as proof that capture/injection really works.
  • Community work for 18.41.117 exists upstream, but treat it as device- and ROM-specific until you validate packet capture and frame injection on your exact build.

Typical Attacks Possible

Once monitor + TX is active you can: * Capture WPA(2/3-SAE) handshakes or PMKID with wifite, hcxdumptool, airodump-ng. * Inject deauthentication / disassociation frames to force clients to reconnect. * Craft arbitrary management/data frames with mdk4, aireplay-ng, Scapy, etc. * Build rogue APs or perform KARMA/MANA attacks directly from the phone.

Performance on the Galaxy S10 is comparable to external USB NICs (~20 dBm TX, 2-3 M pps RX).


Troubleshooting

  • Device or resource busy – make sure Android Wi-Fi service is disabled (svc wifi disable) before enabling monitor mode.
  • nexutil: ioctl(PRIV_MAGIC) failed – the library is not pre-loaded; double-check LD_PRELOAD path.
  • nexutil -m2 / nexutil -i returns success but iw wlan0 info still says managed – this often means a firmware/driver mismatch (for example, flashing an 18.41.8.9 patch onto a phone now running 18.41.113+).
  • airodump-ng/tcpdump starts cleanly but captures zero frames – besides channel mismatch, this is another common symptom of the wrong patched firmware for the running ROM.
  • Patched firmware seems installed but nothing changes – verify the real firmware search path on your ROM (/vendor/etc/wifi, /vendor/firmware, and /system/etc/firmware are all seen in the wild). Flashing the right blob into the wrong location leaves you with stock behaviour plus confusing nexutil output.
  • Frame injection works but no packets captured – some ROMs hard-block channels; try setting the chanspec explicitly with nexutil -k6/20, nexutil -k36/80, etc. before falling back to iwconfig wlan0 channel <n>.
  • SELinux blocking library – set device to Permissive or fix module context: chcon u:object_r:system_lib_file:s0 libnexmon.so.

References