Skip to content

fix(scripts): make shell scripts run on macOS system bash 3.2 - #30

Open
alienwings wants to merge 1 commit into
SimoneAvogadro:masterfrom
alienwings:fix/macos-bash32-portability
Open

fix(scripts): make shell scripts run on macOS system bash 3.2#30
alienwings wants to merge 1 commit into
SimoneAvogadro:masterfrom
alienwings:fix/macos-bash32-portability

Conversation

@alienwings

Copy link
Copy Markdown

Summary

Three portability bugs that make the scripts unusable out of the box on macOS.

1 & 2 — bash 4 constructs (both scripts crash immediately)

macOS ships bash 3.2.57 as /bin/bash, so:

File Construct Error
fingerprint.sh:37 ${INPUT,,} (lowercase expansion) line 37: ${INPUT,,}: bad substitution
find-api-calls.sh:91 declare -A H=(...) line 91: retrofit: unbound variable

Replaced with a tr pipeline and plain counters respectively.

3 — strings reading from stdin (Apple cctools)

fingerprint.sh ran the DEX type-name scan as:

unzip -p -- "$apk" "$dex" | strings -n 8 | grep -oE 'L[a-z]...'

Apple's strings skips the printable-run filter entirely when reading from stdin and emits raw bytes instead. Verified against the same file:

strings -n 8 classes.dex          -> Ljava/lang/String; ...   (correct)
cat classes.dex | strings -n 8    -> raw binary              (wrong)

The scan was therefore fed megabytes of binary noise. Handing strings a real file fixes it, and also cuts the run on a 346 MB / 53-dex APK from 35.6s to 12.8s.

Verification

Tested on macOS (Darwin 25.6.0, arm64) against both interpreters:

/bin/bash 3.2.57  -n  -> both scripts pass
bash 5.3.15       -n  -> both scripts pass

fingerprint.sh      before: bad substitution  after: exit 0, 273 native libs listed
find-api-calls.sh   before: unbound variable  after: correct counts on a fixture

Not included in this PR

While testing I noticed fingerprint.sh's obfuscation heuristic is structurally
inert for APK input. It runs grep -oE '^[a-z]{1,2}/' "$LISTING", which counts
ZIP entry paths — but an APK's root entries are assets/ lib/ res/ r/ ...
(resource paths, not Java packages), so it scores ~1 and always reports LOW.
It behaves as designed for JAR/AAR, where entries really are a/b/C.class.
Left alone here because fixing it needs a design decision (scan the dex string
pool, or gate the heuristic to JAR/AAR input).

🤖 Generated with Claude Code

Two constructs in the scripts require bash 4, which macOS does not ship —
/bin/bash is still 3.2.57 there, so both scripts died immediately:

- fingerprint.sh:37 used ${INPUT,,}, the lowercase expansion (bash 4+).
  Failed with: line 37: ${INPUT,,}: bad substitution
  Replaced with a portable `tr` pipeline.

- find-api-calls.sh:91 used `declare -A` for a 9-key counter map.
  Failed with: line 91: retrofit: unbound variable
  Replaced with plain counters.

Separately, fingerprint.sh fed the DEX scan through
`unzip -p -- "$apk" "$dex" | strings -n 8`. Apple's cctools strings
skips the printable-run filter entirely when reading from stdin and
emits raw bytes instead, so the scan was fed megabytes of binary noise
rather than type descriptors. Handing strings a real file fixes it, and
also cuts the run on a 346 MB / 53-dex APK from 35.6s to 12.8s.

Verified on macOS against both interpreters:

  /bin/bash (3.2.57)  -n  -> both scripts pass
  bash 5.3.15         -n  -> both scripts pass

  fingerprint.sh   before: `bad substitution`   after: exit 0, 273 native libs listed
  find-api-calls.sh before: `unbound variable`  after: correct counts on a fixture

Co-Authored-By: Claude Code <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant