Skip to content

Comments

bug: Parser infers FAT_CIGAM means FAT struct is little-endian, FAT struct should always be big-endian#13

Open
davidmagnotti wants to merge 1 commit intopstirparo:mainfrom
davidmagnotti:main
Open

bug: Parser infers FAT_CIGAM means FAT struct is little-endian, FAT struct should always be big-endian#13
davidmagnotti wants to merge 1 commit intopstirparo:mainfrom
davidmagnotti:main

Conversation

@davidmagnotti
Copy link

@davidmagnotti davidmagnotti commented Aug 4, 2025

The parser currently assumes FAT_CIGAM magic infers little-endianness for FAT structures, causing a crash with a specially formatted MachO file. According to Apple's OS X documentation, FAT structures are always big endian: "Regardless of the content this data structure describes, all its fields are stored in big-endian byte order." (https://developer.apple.com/documentation/kernel/fat_arch).

This script generates a problematic MachO file which demonstrates the crash:

#!/usr/bin/env python3
import struct

# Create minimal Mach-O
def make_macho():
    return struct.pack("<IIIIIIII", 0xFEEDFACF, 0x100000C, 0, 2, 0, 0, 0, 0) + b'\x00' * 24

data = bytearray()

# FAT header (FAT_CIGAM, 1 arch)
data.extend(struct.pack(">II", 0xBEBAFECA, 1))

# FAT arch entry (ARM64, offset=28, size=32)
data.extend(struct.pack(">IIIII", 0x100000C, 0, 28, 32, 0))

# Add Mach-O at offset 28
data.extend(make_macho())

# Write test file
with open("cigam_test.macho", "wb") as f:
    f.write(data)

print(f"Created cigam_test.macho ({len(data)} bytes)")

Output:

>python genfile.py
Created cigam_test.macho (84 bytes)

>python machofile.py -f cigam_test.macho -a
Traceback (most recent call last):
  File "C:\Users\damag\OneDrive\Desktop\machofile.py", line 3414, in <module>
    main()
  File "C:\Users\damag\OneDrive\Desktop\machofile.py", line 3088, in main
    macho = UniversalMachO(file_path=file_path)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\damag\OneDrive\Desktop\machofile.py", line 574, in __init__
    self._parse_fat_binary()
  File "C:\Users\damag\OneDrive\Desktop\machofile.py", line 608, in _parse_fat_binary
    cputype, cpusubtype, offset, size, align = struct.unpack("<5I", fat_arch_data)
                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
struct.error: unpack requires a buffer of 20 bytes

With the fix applied:

>python fixed_machofile.py -f cigam_test.macho -a

[Universal Binary - Architectures: arm64]

[General File Info - arm64]
        Filename:    cigam_test.macho
        Filesize:    32
        MD5:         8e6bfc2af98b1e2994ad08bf16505c93
        SHA1:        0e75689240a69dd78aec028e4938f51683cf05e6
        SHA256:      79e4214b770ec982f202b553b1f70eaa9f1888135d7d4a341d378153fe193e6d

[Mach-O Header - arm64]
        magic:       MH_MAGIC_64 (64-bit), 0xFEEDFACF
        cputype:     ARM 64-bit
        cpusubtype:  ARM_ALL
        filetype:    EXECUTE
        ncmds:       0
        sizeofcmds:  0
        flags:       0

[Load Cmd table - arm64]
        No load commands found

[Load Commands - arm64]
        No load commands found

[File Segments - arm64]
        No segments found

[Dylib Commands - arm64]
        No dylib commands found

[Dylib Names - arm64]
        No dylib names found

[UUID - arm64]
        No uuid found

[Entry Point - arm64]
        No entry point found

[Version Information - arm64]
        No version information found

[Code Signature - arm64]
        signed:      False
        signing_status:Unsigned
        certificates_info:
            count:       0
            certificates:
        entitlements_info:
            count:       0
            entitlements:

[Imported Functions - arm64]
        <unknown>:

[Exported Symbols - arm64]
        <unknown>:

[Similarity Hashes - arm64]
        dylib_hash:  d41d8cd98f00b204e9800998ecf8427e
        import_hash: d41d8cd98f00b204e9800998ecf8427e
        export_hash: d41d8cd98f00b204e9800998ecf8427e

The fix removes the current swap_bytes parsing logic and always reads FAT structures as big-endian.

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