#4868·hashcat

gzip wordlists fail to open on macOS: ext_zlib.c requires gzopen64, which Apple's libz does not export

Author: Spoonman1091Created Sep 15, 2026Updated Sep 15, 2026
Labelsbug

Describe the bug

Since zlib moved to runtime loading in src/ext_zlib.c, gzip-compressed wordlists and hashlists cannot be opened on macOS. ZLIB_SYMS marks gzopen64, gzseek64 and gztell64 as required symbols, and Apple's system libz exports none of them.

The comment above the table explains the intent: zlib's header renames gzopen to gzopen64 through a macro when the build enables the large file API, and dlsym cannot follow a macro, so the suffixed names are written out literally.

That reasoning holds on glibc but not on Darwin. off_t on macOS is already 64 bit, so zlib's configure never enables _LARGEFILE64_SOURCE and the library emits no *64 aliases at all. /usr/lib/libz.1.dylib exports gzopen, gzseek and gztell and nothing named gzopen64. Requiring the suffixed spelling refuses a library that is fully capable of what hashcat asks of it.

The suggested remedy in the error message (brew install zlib) does not help. Homebrew builds the same upstream source with stock configure on the same platform, so its libz has the same export set.

This would not show up in CI, since every glibc box has the LFS aliases.

To Reproduce

On macOS, with any gzip wordlist:

hashcat -m 2100 left.hashes.txt wordlist.txt.gz
hashcat (v7.1.2-676-ge6a7f642c) starting

METAL API (Metal 373.7)
=======================
* Device #01: Apple M2 Max, skipped

OpenCL API (OpenCL 1.2 (Jul 31 2026 20:36:30)) - Platform #1 [Apple]
====================================================================
* Device #02: Apple M2 Max, GPU, 79562/79626 MB (7464 MB allocatable), 38MCU

wordlist.txt.gz: gzip support is unavailable: gzopen64 is missing from the shared library. To fix this, install zlib, for example with: brew install zlib

The export set can be confirmed without building anything:

python3 -c "
import ctypes
l = ctypes.CDLL('libz.1.dylib')
print({s: hasattr(l, s) for s in ('gzopen','gzopen64','gzseek64','gztell64')})
"
{'gzopen': True, 'gzopen64': False, 'gzseek64': False, 'gztell64': False}

Expected behavior

A gzip wordlist opens on macOS against the system libz, as it did when zlib was vendored and statically linked.

Suggested fix

Try the suffixed names first, then fall back to the plain ones, gated to platforms where off_t is known to be 64 bit. The gate is not cosmetic: on a 32 bit build without _FILE_OFFSET_BITS=64 the unsuffixed entry points take and return a 32 bit offset, and reaching one through a prototype declaring long long would put the wrong width on the wire. Darwin has no such configuration left, so __APPLE__ is a safe gate.

A patch doing this is attached. It makes the three symbols optional only where the fallback is compiled in, adds a second symbol table using the existing HC_DYNLIB_SYM_AS macro, and consults it only when one of the suffixed names is absent. On glibc nothing changes: the suffixed names stay required and are still preferred.

Verified by linking the real ext_zlib.c and dynloader.c against stub libraries with controlled export sets:

libz export set fallback compiled out fallback compiled in
Darwin-like (plain only) fails: gzopen64 is missing ... loads, slot resolves gzopen
glibc-like (both spellings) loads via gzopen64 loads via gzopen64
neither spelling fails fails, names gzopen

Row 1 reproduces the reported failure; row 2 confirms glibc behaviour is unchanged.

Hardware

  • Apple M2 Max
  • Metal 373.7 / OpenCL 1.2 (Apple)

Version

  • hashcat v7.1.2-676-ge6a7f642c
  • macOS 26.6.2 (25G83), arm64

Additional context

Unaffected on the v7.1.2 release, where zlib is still vendored and statically linked. The regression is limited to builds carrying the runtime-loaded src/ext_zlib.c.

hashcat-macos-zlib-lfs.patch