Identify a File Type Without an Extension: Magic Bytes List and Tools
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.
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.dllas PE32 withILONLYandSTRONGNAMESIGNEDflags and metadatav4.0.30319, and rejected the Mach-O file with “Not a PE file (no MZ/PE header).”. - WASM to WAT parsed
mystery-eas 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.