diff --git a/README.md b/README.md index 0904560..f06cb5a 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,9 @@ make remove #remove from /bin/ - Images: BMP, PNG, JPEG, QOI, GIF, TIFF, WEBP - Audio: WAV, MP3, OGG, QOA, AIFF, MIDI, FLAC - Video: MP4, AVI -- Multimedia: PDF, Blender, glTF, MD2 +- Multimedia: PDF, XCF, Blender, glTF, MD2 - Fonts: WOFF, WOFF2, OpenType -- Executables: ELF, EXE, WebAssembly, JAR, Luac +- Executables: ELF, EXE, WebAssembly, Luac - Archives: Tar, ZIP, GZIP, XZ, LZIP, 7-Zip, RAR, BZip, CPIO, PAK, .deb, .rpm - Binary Data: qcow, ISO - Other: XML, Shebang scripts, SSH keys, Shortcuts diff --git a/src/ext.h b/src/ext.h new file mode 100644 index 0000000..51ca787 --- /dev/null +++ b/src/ext.h @@ -0,0 +1 @@ +#include "ext/elf.h" diff --git a/src/ext/elf.h b/src/ext/elf.h new file mode 100644 index 0000000..1edc2b5 --- /dev/null +++ b/src/ext/elf.h @@ -0,0 +1,108 @@ +typedef struct + { + unsigned char magic[4]; // 7F E L F + unsigned char bitclass; + unsigned char endian; + unsigned char elfversion; // Must be 1 + unsigned char abi; + unsigned char abiversion; // ignore + unsigned char padding[7]; + uint16_t type; + uint16_t machine; + uint32_t version; + // ... there's more we don't really care about in this context + } + elf_header_t; + +enum { + ELF_BITCLASS_NONE, + ELF_BITCLASS_32, + ELF_BITCLASS_64, + ELF_BITCLASS_OOB +}; +enum { + ELF_ENDIAN_NONE, + ELF_ENDIAN_LITTLE, + ELF_ENDIAN_BIG, + ELF_ENDIAN_OOB +}; +enum { + ELF_ABI_NONE, + ELF_ABI_SYSV, + ELF_ABI_HPUX, + ELF_ABI_NETBSD, + ELF_ABI_LINUX, + ELF_ABI_SOLARIS, + ELF_ABI_IRIX, + ELF_ABI_FREEBSD, + ELF_ABI_TRU64, + ELF_ABI_ARM, + ELF_ABI_STANDALONE, + ELF_ABI_OOB +}; +enum { + ELF_TYPE_NONE, + ELF_TYPE_RELOCATABLE, + ELF_TYPE_EXECUTABLE, + ELF_TYPE_DYNAMIC, + ELF_TYPE_CORE, + ELF_TYPE_OOB, +}; +enum { + ELF_MACH_NONE, + ELF_MACH_X86 = 0x03, + ELF_MACH_IA64 = 0x32, + ELF_MACH_AMDX86 = 0x3E, + ELF_MACH_ARM = 0x28, + ELF_MACH_AARM = 0xB7, + ELF_MACH_RISCV = 0xF3, + ELF_MACH_Z80 = 0xDC +}; + +char elf_endians[][8] = { + "Invalid", "Little", "Big" }; + +char elf_bitclasses[][8] = { + "Invalid", "32", "64" }; + +char elf_types[][16] = { + "Other", "Relocatable", "Executable", "Dynamic Object", "Core File" }; + +char elf_abis[][16] = { + "Generic", "SYS-V", "HPUX", "NetBSD", "Linux", "Solaris", "Irix", "FreeBSD", "Tru64", "ARM", "Standalone" }; + +char elf_machs[0xFF][16] = { + [ELF_MACH_NONE] = "None", + [ELF_MACH_X86] = "x86", + [ELF_MACH_IA64] = "IA-64 (Itanium)", + [ELF_MACH_AMDX86] = "x86 (AMD)", + [ELF_MACH_ARM] = "ARM", + [ELF_MACH_AARM] = "ARM (AArch64)", + [ELF_MACH_RISCV] = "RISC-V", + [ELF_MACH_Z80] = "Zilog Z80", +}; + +void elf_printer (void *filetype, char *in) { + static char buffer[128]; + elf_header_t * header = (elf_header_t *) in; + filetype_t * self = (filetype_t *) filetype; + + if ( header->abi >= ELF_ABI_OOB ) { header->abi = 0; } + if ( header->bitclass >= ELF_BITCLASS_OOB ) { header->bitclass = 0; } + if ( header->endian >= ELF_ENDIAN_OOB ) { header->endian = 0; } + if ( header->abi >= ELF_ABI_OOB ) { header->abi = 0; } + if ( header->type >= ELF_TYPE_OOB ) { header->type = 0; } + if ( header->machine >= 0xFF ) { header->type = 0; } // Prevent overflow + if ( elf_machs[header->machine][0] == 0 ) { header->type = 0; } // Prevent nulls + + char * abi = elf_abis[header->abi]; + char * bitclass = elf_bitclasses[header->bitclass]; + char * endian = elf_endians[header->endian]; + char * type = elf_types[header->type]; + char * mach = elf_machs[header->machine]; + + snprintf(buffer, sizeof(buffer), + "ELF %.16s-bit %.16s endian %.16s, %.16s %.16s", + bitclass, endian, type, mach, abi + ); self->info = buffer; +} diff --git a/src/magic.c b/src/magic.c index 15984c4..69b5f7d 100644 --- a/src/magic.c +++ b/src/magic.c @@ -24,6 +24,9 @@ int parse_magic(char *in) { if ( status == 0 ) { type = test; break; } } + if ( type != NULL && type->printer != NULL ) + { type->printer(type, (char *)buffer); } + fclose(target); return 0; } diff --git a/src/magic.h b/src/magic.h index c181418..6856973 100644 --- a/src/magic.h +++ b/src/magic.h @@ -1,10 +1,8 @@ #ifndef MAGIC_H #define MAGIC_H -#include -#include // Allows overriding the default printer function for certain types -typedef void *type_parser(void *type, char *in); +typedef void type_parser(void *type, char *in); void parser_default(void *type, char *in); int parse_magic(char *in); long parse_size(char *in); @@ -12,10 +10,15 @@ long get_size(FILE *f); int parse_scale(long in); typedef struct - { char * name; char * magic; char * ext; int off; int len; type_parser *printer; } + { char * name; char * magic; char * ext; int off; int len; type_parser *printer; char * info; } filetype_t; + // the type_parser printer is used to set *info for file formats with important subtypes. + // they are passed in the first 32 bytes of the input file, + // which can be changed later if some formats (such as MacOS dmg files) + // require more data (and bounds checking logic) extern filetype_t * type; +#include "ext.h" // https://en.wikipedia.org/wiki/List_of_file_formats #define magic_table_size ( sizeof(magic_table) / sizeof(magic_table[0]) ) @@ -35,8 +38,6 @@ filetype_t magic_table [] = { { .name = "Windows Shell Link", .magic = "\x4C\x00\x00\x00\x01\x14\x02\x00\x00\x00\x00\x00\xC0\x00\x00\x00\x00\x00\x00\x46", .len = 20, .ext = "lnk" }, // Raster Image Formats -// { .name = "PNG Image", -// .magic = "\x89\x50\x4E\x47\x0D\x0A\x1A\xA0", .len = 8, .ext = "png" }, { .name = "PNG Image", .magic = "\x89\x50\x4E\x47", .len = 4, .ext = "png" }, { .name = "JPEG Image", @@ -101,8 +102,9 @@ filetype_t magic_table [] = { .magic = "FLhd", .len = 4, .ext = "flp" }, { .name = "Quake 2 Model", .magic = "IDP2\x08\x00\x00\x00", .len = 8, .ext = ".md2" }, + { .name = "GIMP Project", + .magic = "gimp xcf ", .len = 9, .ext = "xcf" }, // Executable Formats - // TODO: ELF Format Printer, checks header for subtype information { .name = "MachO Binary (32-bit x86)", .magic = "\xCE\xFA\xED\xFE\x07\x00\x00\x00", .len = 8, .ext = NULL }, { .name = "MachO Binary (64-bit x86)", @@ -110,7 +112,7 @@ filetype_t magic_table [] = { { .name = "MachO Binary (64-bit ARM)", .magic = "\xCF\xFA\xED\xFE\x0C\x00\x00\x00", .len = 8, .ext = NULL }, { .name = "ELF Binary", - .magic = "\x7F" "ELF", .len = 4, .ext = "bin" }, + .magic = "\x7F" "ELF", .len = 4, .ext = "bin", .printer = elf_printer }, { .name = "Portable Executable Binary", .magic = "\x4D\x5A", .len = 2, .ext = "exe" }, { .name = "WebAssembly Binary", diff --git a/src/main.c b/src/main.c index 73840af..847cbb4 100644 --- a/src/main.c +++ b/src/main.c @@ -1,3 +1,6 @@ +#include +#include +#include #include "magic.h" #include "magic.c" #include "license.h" @@ -25,6 +28,7 @@ int main(int argc, char* argv[]) { outname = (char *)(argv[1] + arglen - maxlen ); outname[0] = '.'; outname[1] = '.'; outname[2] = '.'; } if ( type == NULL ) { printf("%s: Unknown file type\n", outname); } + else if ( type->info != NULL ) { printf("%s:%s\n", outname, type->info); } else { printf("%s: %s\n", outname, type->name); } // Scale the filesize then print char prefix[] = " KMGTP";