rea-reverse

Identify a File Type Without an Extension: Magic Bytes List and Tools

Published by rea-reverseUpdated 7 min read
On this page

Short answer: look at the first few bytes, not the extension. On Linux or macOS, file mystery names the format, and xxd -l 16 mystery shows the raw header. On Windows, Format-Hex -Path mystery -Count 16 shows it in PowerShell. Match the bytes against the table below. If they start with PK, you have a ZIP container, and the file names inside it (not the first bytes) tell you whether it is an APK, a NuGet package, a JAR or an Office document. Then open it with the tool built for that format. The table at the end lists the tool for each format.

No terminal at hand? Drop the file into the file type identifier on this site. It runs in your browser without uploading anything, shows the matched bytes with their offset, names the format inside a ZIP from its entry names, and adds a binwalk-style scan for embedded headers, an entropy graph and a hex view.

Samples used: eight files I made myself or took from open-source releases, all renamed to mystery-a … mystery-h so that no extension gives anything away: a C program compiled with clang on macOS, busybox from the OpenWrt 25.12.5 root filesystem, Newtonsoft.Json.dll and the .nupkg it ships in (from nuget.org, MIT license), a one-function WebAssembly module built with wat2wasm, a gzipped text file, the OpenWrt SquashFS image, and the package’s PNG icon.

Treat an unknown file as untrusted: identify it statically, and don’t run it or open it in an app that executes macros.

Read the bytes. Find the format.Silent walkthrough with English captions.

Why the first bytes beat the extension

Most binary formats begin with a fixed signature, the “magic number”, so that loaders and parsers can reject the wrong input quickly. The Linux kernel checks for \x7fELF, Windows checks for MZ, a browser’s WebAssembly engine checks for \0asm. The extension is only a naming convention: anyone can rename a file, and many formats (APK, JAR, DOCX, NUPKG) share one container.

Signatures have limits too. Text formats such as JSON, HAR files and source maps have no magic; you recognize them by parsing. Some magic values collide: CA FE BA BE starts both a universal Mach-O binary and a Java .class file. And a signature only says what the file claims to be. A truncated or corrupted file can start correctly and still fail to parse.

Step 1: Look at the header

$ file mystery-*
mystery-a: Mach-O 64-bit executable arm64
mystery-b: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-mips-sf.so.1, no section header
mystery-c: PE32 executable (DLL) (console) Intel 80386 Mono/.Net assembly, for MS Windows
mystery-d: Zip archive data, at least v2.0 to extract, compression method=deflate
mystery-e: WebAssembly (wasm) binary module version 0x1 (MVP)
mystery-f: gzip compressed data, was "note.txt", ... from Unix, truncated
mystery-g: Squashfs filesystem, little endian, version 4.0, xz compressed, 4626494 bytes, 1214 inodes, ...
mystery-h: PNG image data, 512 x 512, 8-bit/color RGBA, non-interlaced

That is file 5.41 as shipped with macOS. It reads the header through a large signature database and often adds details: the CPU, the .NET marker, image dimensions. Don’t take every word literally, though. It called the gzip file “truncated”, yet gzip -tv mystery-f reported OK. The bytes themselves are the ground truth:

$ xxd -l 16 mystery-c
00000000: 4d5a 9000 0300 0000 0400 0000 ffff 0000  MZ..............
$ xxd -l 16 mystery-e
00000000: 0061 736d 0100 0000 0107 0160 027f 7f01  .asm.......`....
$ xxd -l 16 mystery-g
00000000: 6873 7173 be04 0000 286c 426a 0000 0400  hsqs....(lBj....

On Windows without xxd, PowerShell has a built-in cmdlet. Microsoft’s Format-Hex documentation uses exactly this case, a PDF renamed to an unknown extension, as its example:

Format-Hex -Path .\mystery-c -Count 16

-Count and -Offset need PowerShell 6.2 or later. I did not run this one (no Windows machine for this article), so check the column layout against the documentation.

Step 2: Match the signature

These are the values from my samples plus a few common neighbors. Every row with a sample name was checked with xxd on that file.

First bytes (hex) ASCII Format Sample
7F 45 4C 46 .ELF ELF: Linux, Android .so, most firmware binaries mystery-b
4D 5A MZ PE/COFF: Windows EXE, DLL, .NET assembly (the offset of the PE\0\0 header is stored at 0x3C) mystery-c
CF FA ED FE / CE FA ED FE Mach-O 64-bit / 32-bit, little-endian mystery-a
CA FE BA BE Universal Mach-O or Java class
50 4B 03 04 PK.. ZIP and everything built on it mystery-d
00 61 73 6D .asm WebAssembly module (next 4 bytes: version) mystery-e
1F 8B gzip mystery-f
FD 37 7A 58 5A 00 .7zXZ. xz (made with xz)
68 73 71 73 hsqs SquashFS, little-endian (sqsh is big-endian) mystery-g
27 05 19 56 U-Boot legacy uImage (firmware kernels) OpenWrt .bin
89 50 4E 47 0D 0A 1A 0A .PNG.... PNG mystery-h
62 70 6C 69 73 74 30 30 bplist00 Apple binary property list
25 50 44 46 %PDF PDF (Microsoft’s Format-Hex example)

A signature that sits at offset 0 is the easy case. Firmware puts several formats back to back, so a SquashFS can begin megabytes into a file. For that, use a scanner that searches the whole file, which the Binwalk 3 guide covers.

Step 3: Split the ZIP family

PK\x03\x04 only means “ZIP”. To find out which ZIP, list the entries:

$ unzip -l mystery-d | head
     1104  03-08-2023 07:01   LICENSE.md
     2413  03-08-2023 07:06   Newtonsoft.Json.nuspec
     8956  03-08-2023 07:01   packageIcon.png
      653  03-08-2023 07:06   [Content_Types].xml
   580880  03-08-2023 07:09   lib/net20/Newtonsoft.Json.dll

A .nuspec plus lib/<framework>/ folders means a NuGet package. The marker files for the common cases:

Inside the ZIP It is
AndroidManifest.xml, classes.dex, resources.arsc Android APK
base/manifest/AndroidManifest.xml, BundleConfig.pb Android App Bundle (AAB)
Payload/<Name>.app/ iOS IPA
META-INF/MANIFEST.MF with .class files Java JAR
*.nuspec, lib/<tfm>/ NuGet package
[Content_Types].xml with word/, xl/ or ppt/ Office DOCX, XLSX, PPTX
AppxManifest.xml MSIX / AppX

Tools differ in how far they go here. inspect-artifact in REA 6.7.0 (a third-party open-source analysis tool) checks the ZIP signature from the bytes, then takes the subtype from the extension: .apk, .ipa, .msix/.msixbundle, .appx/.appxbundle, otherwise plain zip. I ran it on mystery-d and got root_format: "zip", with the eight DLLs inside classified as pe from their own bytes. Then I copied the same NuGet package to renamed.apk, and it reported root_format: "apk". Same bytes, different answer, so list the entries yourself before you trust a ZIP subtype.

This site’s APK & AAB analyzer looks at the contents instead. Given the NuGet package, it opened the ZIP and reported “No AndroidManifest.xml was found.”. It decides between APK and AAB by whether AndroidManifest.xml or base/manifest/AndroidManifest.xml is present, not by the file name.

On the other samples, REA’s inspect-artifact returned mach-o, elf and pe for mystery-a to -c (suggesting inspect_managed_artifact first for the .NET DLL) and refused the WebAssembly, gzip, SquashFS and PNG files with “Cannot open artifact: unsupported binary format.” It is an archive and app-package inventory, not a general identifier, which is why file and xxd come first.

Step 4: Open it with the right tool

Once you know the format, this is where to go. The browser tools parse files locally in a Web Worker and do not upload them. On 2026-10-14 I ran my samples through the analyzer code of the binary, .NET, WASM, APK and ASAR tools (results below); the other rows list the tool and command for that format.

Format Browser tool on this site REA 6.7.0 Guide
ELF, PE, Mach-O Native binary overview inspect-artifact, then analyze with Ghidra ELF, PE and Mach-O viewer
.NET assembly (PE with CLI header) .NET metadata and IL viewer inspect-managed-artifact Check a .NET DLL’s target framework
APK / AAB (ZIP) APK & AAB analyzer inspect-android-package Unpack an APK or AAB
WebAssembly WASM to WAT none Inspect WebAssembly
Electron app.asar ASAR viewer inspect-artifact (needs the .asar name) Unpack an ASAR file
HAR (JSON) or Fiddler SAZ (ZIP) HAR analyzer inspect-web-network-capture HAR file analyzer guide
JavaScript source map (JSON) Source map tool trace-web-source-location Recover source from a bundle
Firmware (uImage, SquashFS, …) none inspect-firmware-regions, extract-firmware (Linux only) Extract SquashFS from firmware
EVM contract bytecode (hex text) EVM selector extractor inspect-evm-interface Read unverified contract bytecode: proxy or token?

Some results from those runs:

  • Binary overview accepts any file and decides by magic. It opened busybox (ELF32, MIPS, big-endian, stripped) and refused the SquashFS image and the WASM module with “unknown magic”.
  • .NET viewer read Newtonsoft.Json.dll as PE32 with ILONLY and STRONGNAMESIGNED flags and metadata v4.0.30319, and rejected the Mach-O file with “Not a PE file (no MZ/PE header).”.
  • WASM to WAT parsed mystery-e as version 1 with one exported function, add, of type (i32, i32) -> (i32).
  • ASAR viewer rejected the NuGet ZIP with “Not an ASAR archive”. ASAR has no fixed magic; the tool checks that the first 16 bytes form its size and header pickles.

The file pickers on the .NET, WASM, ASAR and APK pages filter by extension (.dll,.exe, .wasm, .asar, .apk,.aab). If your file has no extension, drag it onto the page instead; the tools check the content, not the name.

FAQ

Can a file have a valid signature and still be something else? Yes. Polyglot files are valid in two formats at once, and ZIP data appended to another file is common. The signature at offset 0 tells you how the file will be loaded, not everything it contains.

How do I identify a text file with no extension? Text has no magic. Check whether the file is valid JSON (HAR files and source maps are JSON), look for a shebang (#!), or let file guess from the content.