Cybersecurity

How do I create a custom file type detection database?

Learn how to build and maintain a custom file type detection database for identifying files with non-standard signatures or proprietary formats.

By Inventive HQ Team

A custom file type detection database is a set of your own signature rules — magic numbers, byte offsets, size limits and footer patterns — that teaches file-identification tools to recognise proprietary or non-standard formats that the standard libmagic database does not know. You build it by collecting sample files, finding the distinctive bytes they all share (usually a "magic number" at offset 0), and encoding those patterns in a format your tooling can read — a JSON/config database of your own, a set of YARA rules, or extra rules compiled into libmagic. Detection then works on the file's actual bytes rather than its (easily forged) extension, so an unlabelled .dat can be classified automatically during breach investigations, data-loss monitoring, and forensic triage.

That is the summary an AI overview will give you. What it can't give you is the part that makes the database actually reliable: how magic-number matching works under the hood, why offset and structure validation matter as much as the first four bytes, and how to keep false positives from drowning your alerts. The rest of this guide is that part.

How magic-number detection actually works

Before you build a database, it helps to see the pipeline a tool like file runs for every file. It reads a fixed window of bytes from the front (and sometimes the back), compares them at specific offsets against a table of known signatures, and returns the first confident match — the file's true type, independent of its name.

File type detection pipeline Raw bytes are read from a file, the header bytes at a known offset are matched against a signature database, and the identified file type is returned. A marker travels along the pipeline. Bytes in, file type out Raw file 89 50 4E 47 0D 0A 1A 0A Match at offset read N bytes, compare to DB Identified PNG image The extension is never read. Only the bytes decide the type.

The signature at the heart of this is short and stable. Here are the ones you will meet most often — the reference points against which you will design your own custom entries:

FormatMagic number (hex)ASCIIOffsetFooter / trailer
PNG89 50 4E 47 0D 0A 1A 0A.PNG....049 45 4E 44 AE 42 60 82 (IEND)
JPEGFF D8 FF0FF D9
GIF47 49 46 38 39 61GIF89a000 3B
PDF25 50 44 46 2D%PDF-025 25 45 4F 46 (%%EOF)
ZIP / DOCX / JAR50 4B 03 04PK..050 4B 05 06 (EOCD)
Windows EXE / DLL4D 5AMZ0
ELF (Linux binary)7F 45 4C 46.ELF0
GZIP1F 8B0
RAR (v5)52 61 72 21 1A 07 01 00Rar!...0
7-Zip37 7A BC AF 27 1C7z...0

Two things about this table drive every design decision below. First, several formats share a magic number: .docx, .jar, .apk, and a plain .zip all start with 50 4B 03 04 because they are all ZIP containers — so the first four bytes narrow the type but rarely nail it. Second, the offset is not always 0 (TAR's ustar signature sits at offset 257), which is exactly why a real database records where to look, not just what to look for. Your custom format entries need the same discipline.

Try it on a real file before you build anything — paste bytes into the checker below and watch which signature wins:

Loading interactive tool...

Why Create a Custom File Type Detection Database

Organizations often work with proprietary, custom, or non-standard file formats that the standard file magic number libraries don't recognize. A financial institution might have a custom trading data format. A media company might use specialized video containers. A healthcare provider might have custom patient record formats. An industrial company might have proprietary sensor data formats.

When these custom formats appear in unexpected locations, during breach investigations, or in suspicious contexts, being able to identify and analyze them is crucial. A custom file type detection database allows your organization to automatically identify these files during security analysis, forensic investigation, and data classification.

This guide walks you through creating and maintaining a custom file type detection database that integrates with your existing security tools and forensic workflows.

Understanding File Type Detection Fundamentals

Magic Numbers and File Signatures

Every file type has identifying characteristics. Most files start with a magic number—the first few bytes that uniquely identify the file type.

Standard magic numbers:

PDF:        25 50 44 46        "%PDF"
PNG:        89 50 4E 47        "‰PNG"
JPEG:       FF D8 FF           (plus more bytes)
ZIP:        50 4B 03 04        "PK.."
EXE:        4D 5A              "MZ"
GIF:        47 49 46 38        "GIF8"

For custom formats, you need to identify the unique magic number that marks files of that type.

File Structures and Footers

Beyond magic numbers, files have internal structures and often have footer signatures marking the end:

  • JPEG: Starts with FF D8 FF, ends with FF D9
  • ZIP: Starts with 50 4B, contains central directory, ends with 50 4B 05 06 (end of central directory)
  • PDF: Starts with %PDF, ends with %%EOF

A robust file type detector uses both start and end signatures plus internal structure validation.

Step 1: Identify Your Custom File Types

Inventory Custom Formats

First, document all custom file formats your organization uses:

  1. List all proprietary formats: What file types does your organization create?
  2. Collect samples: Gather example files of each type
  3. Document format specifications: Do you have format documentation? If not, you'll need to reverse-engineer it
  4. Determine file extensions: What extensions are typically used? (.dat, .custom, .prop, etc.)
  5. Document usage: What applications create/use these formats? On which systems?

Example: Custom Trading Data Format

An investment firm uses a custom format .TRD (Trading Data):

  • Contains encrypted trading records
  • Created by proprietary trading platform
  • Stored in /data/trades/ directory
  • Files are 4KB-100MB typically
  • No public documentation available
  • Occasionally found in unintended locations when investigating breaches

Step 2: Reverse-Engineer File Signatures

If you don't have format documentation, analyze example files to identify signatures.

Hexadecimal Analysis

Use a hex editor to examine file contents:

hexdump -C example.trd | head -30

Output might show:

00000000: 5452 4441 0100 2054 2020 2020 2020 2020  TRDA.. T
00000010: 2020 2020 0000 0100 0000 0000 0000 00c0  ............
00000020: 0100 0000 0100 0000 ffff ffff 0000 0000  ................

Analysis:

  • 54 52 44 41 = "TRDA" - This looks like a magic number
  • 01 00 20 followed by ASCII spaces suggests a version number
  • Repeated patterns suggest structured data

Statistical Analysis

Examine multiple files to identify consistent patterns:

for file in *.trd; do
  echo "=== $file ==="
  hexdump -C "$file" | head -5
done

Compare the first 100 bytes of multiple files:

  • Are the first bytes always the same?
  • Is there variation in what order?
  • Are there timestamp or version fields?
Advertisement

File Structure Mapping

Once you identify the start signature, map the file structure:

Byte 0-3:     Magic number (TRDA)
Byte 4-5:     Version number
Byte 6-135:   Header (130 bytes)
  6-10:       Timestamp
  11-50:      Trading account ID
  51-135:     Reserved/padding
Byte 136-end: Encrypted data block
  Last 32 bytes: Checksum/signature

Step 3: Create the Database Format

Choose how to store your custom file type definitions. Several approaches are available:

Option 1: Regex-Based Configuration File

Create a configuration file with regular expressions for each format:

File: custom-formats.conf

# Custom Trading Data Format
[TRD]
name=Trading Data Format
magic=54524441                 # TRDA
magic_offset=0
extension=.trd
min_size=4096
max_size=104857600            # 100MB
version_offset=4
version_length=2
description=Investment firm trading data records
severity=high                 # Data classification
action=quarantine             # On discovery action

Option 2: JSON Database

{
  "custom_formats": [
    {
      "id": "trd_trading_data",
      "name": "Trading Data Format",
      "magic": {
        "hex": "54524441",
        "offset": 0,
        "ascii": "TRDA"
      },
      "extension": ".trd",
      "file_size": {
        "min": 4096,
        "max": 104857600
      },
      "structure": {
        "version_offset": 4,
        "version_length": 2,
        "footer_magic": "ffffffff",
        "footer_offset": -32
      },
      "classification": {
        "data_type": "financial",
        "sensitivity": "highly-confidential",
        "severity": "high"
      },
      "detection_rules": [
        "magic_match",
        "size_range_match",
        "structure_validation"
      ]
    }
  ]
}

Option 3: Custom Database Tool

Create a specialized tool (Python, Go, etc.) that manages the database:

from dataclasses import dataclass
from typing import Optional

@dataclass
class FileTypeSignature:
    format_id: str
    name: str
    magic_hex: str          # Magic number in hex
    magic_offset: int       # Where magic appears
    file_extension: str
    min_size: int           # Minimum file size
    max_size: int           # Maximum file size
    footer_hex: Optional[str]  # End signature
    severity: str           # Data sensitivity level

    def matches(self, file_data: bytes) -> bool:
        """Check if file matches this signature"""
        magic_bytes = bytes.fromhex(self.magic_hex)
        start = self.magic_offset
        end = start + len(magic_bytes)

        if end > len(file_data):
            return False

        return file_data[start:end] == magic_bytes

# Create database
database = {
    "trd": FileTypeSignature(
        format_id="trd_trading_data",
        name="Trading Data Format",
        magic_hex="54524441",
        magic_offset=0,
        file_extension=".trd",
        min_size=4096,
        max_size=104857600,
        footer_hex="ffffffff",
        severity="high"
    )
}

Step 4: Validation and Testing

Create test samples to validate your detection database:

Unit Testing

def test_trading_data_detection():
    database = load_custom_database()

    # Test 1: Valid TRD file
    with open("valid_example.trd", "rb") as f:
        data = f.read()

    trd_sig = database["trd"]
    assert trd_sig.matches(data), "Failed to detect valid TRD file"

    # Test 2: Non-TRD file
    with open("document.pdf", "rb") as f:
        data = f.read()

    assert not trd_sig.matches(data), "False positive: detected PDF as TRD"

    # Test 3: Corrupted TRD
    corrupted = b"XXDA" + valid_data[4:]
    assert not trd_sig.matches(corrupted), "Accepted corrupted data"

if __name__ == "__main__":
    test_trading_data_detection()
    print("All tests passed!")

False Positive Testing

Test for false positives by scanning diverse files:

# Scan all system files looking for false positives
find /usr -type f -exec ./custom_detector {} \; 2>/dev/null | grep "TRD" | head -20

# Manually verify any false positives found
hexdump -C /usr/bin/suspected_false_positive | head -10

Step 5: Integration with Security Tools

File Analysis Workflows

Integrate your custom database with forensic and security tools:

Foremost/Scalpel Integration:

Modify the Scalpel configuration file to include custom signatures:

# Scalpel.conf - added to custom formats section
trd	y	4G	54524441	ffffff		ffffffff

The format is:

  • Extension name (trd)
  • Enabled (y/n)
  • Max file size (4G)
  • Magic bytes (54524441)
  • Ignore bytes (ffffff = don't care)
  • Footer bytes (ffffffff)

Binwalk Plugin:

Create a custom Binwalk module for your format:

# custom_trd_module.py
import binwalk

class TRDModule(binwalk.Module):
    def init(self):
        self.description = "Trading Data Format"

    def scan(self, stream, callback):
        stream.seek(0)
        while True:
            magic = stream.read(4)
            if not magic:
                break

            if magic == b'TRDA':
                callback(
                    size=stream.tell(),
                    description="Trading Data Format",
                    valid=True
                )

SIEM and Log Analysis

Add detection to your SIEM (Splunk, ELK, Sumo Logic) for real-time monitoring:

Splunk Search:

source="/var/log/file_access/*"
| transaction file_extension
| where file_extension=".trd"
  AND source NOT IN ("/data/trades/*")
  AND user NOT IN ("trading_app", "finance_team")
| table timestamp, user, file_path, file_size

This alerts when TRD files appear in unexpected locations.

Step 6: Maintenance and Updates

Version Control

Track changes to your database:

git init custom_file_database
git add custom-formats.json
git commit -m "Initial version with TRD format"

# Later update
# ... modify custom-formats.json ...
git commit -m "Add healthcare format HCR with updated magic bytes"

Documentation

Maintain clear documentation:

# Custom File Type Database

## TRD - Trading Data Format
- **Created**: January 2024
- **Last Updated**: October 2024
- **Owned By**: Trading Platform Team
- **Magic Number**: 54 52 44 41 (TRDA)
- **Version History**:
  - v1.0: Initial definition (Jan 2024)
  - v1.1: Added footer validation (Oct 2024)
- **Detection Status**: Production
- **Notes**: Can be encrypted; applies to files created after 2020

Regular Audits

Periodically review and update:

  1. Quarterly: Test detection accuracy against new file samples
  2. Annually: Review format specifications for changes
  3. Per incident: Update database when new formats discovered during investigations

Example: Complete Custom Format Definition

Here's a complete example for a custom healthcare patient record format:

{
  "format_id": "hcr_patient_record",
  "name": "Healthcare Patient Record",
  "organization": "MedCare Hospital",
  "created_date": "2023-06-15",
  "last_updated": "2024-10-31",

  "detection": {
    "magic_number": {
      "hex": "48435245",
      "offset": 0,
      "ascii": "HCRE"
    },
    "file_extension": ".hcr",
    "mime_type": "application/x-hcre",
    "size_range": {
      "minimum": 1024,
      "maximum": 52428800
    },
    "structure": {
      "header_size": 256,
      "version_offset": 4,
      "version_length": 2,
      "record_count_offset": 8,
      "checksum_offset": 240,
      "footer_magic": "454452"
    }
  },

  "classification": {
    "data_sensitivity": "PHI",
    "regulatory_framework": "HIPAA",
    "handling_instructions": "Encrypt in transit, encrypt at rest",
    "notification_required": true
  },

  "detection_rules": {
    "required": ["magic_match", "structure_validation"],
    "optional": ["checksum_validation"],
    "when_found": {
      "expected_locations": ["/data/patients/*", "/backups/patients/*"],
      "alert_if": "found_outside_expected_locations",
      "severity": "critical"
    }
  }
}

Advanced Techniques

Yara Rules for Complex Detection

For more sophisticated detection, use Yara rules:

rule custom_trd_format {
    strings:
        $magic = "TRDA" at 0
        $version = {01 00 20}
        $footer = {FF FF FF FF}

    condition:
        $magic and $version and $footer
}

rule encrypted_trd {
    strings:
        $magic = "TRDA"
        $encryption_marker = "ENC"

    condition:
        $magic at 0 and $encryption_marker at 50
}

Machine Learning Approach

For very complex formats, use ML to learn signatures:

import numpy as np
from sklearn.ensemble import IsolationForest

# Extract features from known TRD files
features = []
for trd_file in known_trd_files:
    with open(trd_file, 'rb') as f:
        data = f.read(1000)
    features.append(np.frombuffer(data, dtype=np.uint8))

# Train model
model = IsolationForest(contamination=0.1)
model.fit(features)

# Test on unknown file
with open("suspect_file", "rb") as f:
    test_data = np.frombuffer(f.read(1000), dtype=np.uint8)

if model.predict([test_data])[0] == 1:
    print("File matches TRD pattern")

Conclusion

Creating a custom file type detection database enables your organization to identify proprietary and non-standard file formats automatically. By systematically identifying magic numbers, validating file structures, and integrating with your existing security infrastructure, you can:

  • Detect data exfiltration of custom formats
  • Identify unauthorized file types in unexpected locations
  • Automate forensic analysis of custom formats
  • Build institutional knowledge of your organization's data types
  • Respond more effectively to security incidents

The effort to create and maintain a custom database pays dividends through improved threat detection, faster incident response, and better data governance. Combined with proper access controls and monitoring, a comprehensive file type detection strategy becomes a powerful tool for protecting your organization's most sensitive data.

Frequently Asked Questions

What is a custom file type detection database?

A custom file type detection database is a set of your own signature rules — magic numbers, byte offsets, size ranges, and footer patterns — that lets tools like file, YARA, or a forensic scanner recognise proprietary or non-standard formats the standard libmagic database has never heard of. Each entry maps a distinctive byte pattern (for example the ASCII string "TRDA" at offset 0) to a named format, so an unlabelled .dat file can be identified automatically during data classification, breach investigation, or exfiltration monitoring.

What is a magic number in a file?

A magic number (also called a file signature) is a fixed sequence of bytes at a known position — almost always the first few bytes — that identifies a file's true format regardless of its extension. PNG files begin with 89 50 4E 47, PDFs with 25 50 44 46 ("%PDF"), ZIP archives with 50 4B 03 04 ("PK"), and JPEGs with FF D8 FF. Detection tools read those bytes and look them up rather than trusting the filename, because an attacker can rename evil.exe to invoice.pdf but cannot easily change the bytes an application needs to open the file.

How does the Linux file command detect file types?

The file command is powered by libmagic, which reads the first bytes of a file and tests them against a compiled magic database (magic.mgc, built from human-readable magic pattern files). Each rule specifies an offset, a data type, a value to compare against, and the text or MIME type to print on a match. Rules can chain: a top-level match on 50 4B 03 04 says "ZIP container", then continuation lines inspect deeper offsets to distinguish a .docx, .jar, or .apk. You extend it by adding your own magic rules and compiling them with file -C.

How do I find the magic number of an unknown file?

Open several sample files in a hex viewer — hexdump -C file.dat | head or xxd file.dat | head — and compare the first 16 to 64 bytes across all of them. Bytes that stay identical across every sample are your candidate signature; bytes that change are version fields, timestamps, or payload. Confirm the pattern is distinctive (unlikely to appear at offset 0 in unrelated files) before adding it to your database, and test it against a large corpus of other files to measure false positives.

What is the difference between a magic number and a file extension?

A file extension (.pdf, .jpg) is just part of the filename — metadata the user or program chose, trivially changed and completely absent on many Unix files. A magic number lives inside the file's bytes and reflects what the data actually is, because the application that reads the format depends on it. Security and forensic tools identify files by magic number, not extension, precisely because extensions lie. A mismatch between the two (a .jpg whose bytes start with 4D 5A, "MZ", a Windows executable) is itself a strong indicator of something suspicious.

Can magic numbers be faked or spoofed?

Yes, partially. An attacker can prepend a valid magic number to a malicious payload — a polyglot file that is simultaneously a valid GIF and a valid archive, for example — so magic-number matching alone is not proof of a file's real nature. That is why a robust custom database validates more than the first bytes: it checks footer signatures, internal structure, size ranges, and where reasonable a checksum or hash. Combine signature detection with content inspection and behaviour analysis rather than trusting the header in isolation.

What is a footer signature and why does it matter?

A footer (or trailer) signature is a fixed byte pattern that marks the end of a file — JPEG ends with FF D9, ZIP's end-of-central-directory record starts with 50 4B 05 06, and PDF ends with %%EOF. Footers matter for two reasons: they let a detector confirm a file is complete and not truncated, and they are essential for file carving, where forensic tools recover deleted files from raw disk images by locating a header signature and reading until the matching footer.

How do I add a custom signature to YARA or Scalpel?

In YARA you write a rule with a strings section (for example $magic = "TRDA" at 0) and a condition that combines your patterns, then run yara myrules.yar target/ to scan. In Scalpel or Foremost you add a line to the configuration file giving the extension, whether it is enabled, a maximum size, the header bytes in hex, and optionally the footer bytes, so the carver can recover that format from disk images. Both let your custom database plug directly into existing forensic workflows.

file analysisfile signaturescustom databaseforensicsdata classification
Advertisement