Last active
July 20, 2017 19:43
-
-
Save balintkissdev/e6b3a00c5a9051591f0bb3f6081d0413 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * DOS executable header reader | |
| * | |
| * This programs reads the binary header of a DOS executable file and prints its contents. | |
| * | |
| * Header specification sources: | |
| * http://www.fysnet.net/exehdr.htm | |
| * http://www.delorie.com/djgpp/doc/exe/ | |
| * | |
| * 2016- 2017 Balint Kiss | |
| */ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #ifndef uint16_t | |
| #define uint16_t unsigned short | |
| #endif | |
| #define readUint16(field, fp) \ | |
| fread(field, 2, 1, fp) | |
| // TODO: Relocation items and rest of the header | |
| /** | |
| * Header of DOS executable. | |
| */ | |
| typedef struct DOSExeHeader | |
| { | |
| /** | |
| * ID signature (usually 'MZ', otherwise 0x5a4d) | |
| */ | |
| uint16_t id_signature; /* 0x00 */ | |
| /** | |
| * Number of bytes in last block | |
| */ | |
| uint16_t last_block_bytes_count; /* 0x02 */ | |
| /** | |
| * Number of 512-byte blocks in file | |
| */ | |
| uint16_t file_block_count; /* 0x04 */ | |
| /** | |
| * Number of relocation entries | |
| */ | |
| uint16_t relocation_entry_count; /* 0x06 */ | |
| /** | |
| * Number of paragraphs in header | |
| */ | |
| uint16_t header_paragraphs_count; /* 0x08 */ | |
| /** | |
| * Minimum required memory in paragraphs | |
| */ | |
| uint16_t min_required_memory; /* 0x0A */ | |
| /** | |
| * Maximum required memory in paragraphs | |
| */ | |
| uint16_t max_required_memory; /* 0x0C */ | |
| /** | |
| * Stack segment offset | |
| */ | |
| uint16_t stack_segment_offset; /* 0x0E */ | |
| /** | |
| * Initial value of Stack Pointer (SP) register | |
| */ | |
| uint16_t initial_sp_register_value; /* 0x10 */ | |
| /** | |
| * File checksum | |
| */ | |
| uint16_t checksum; /* 0x12 */ | |
| /** | |
| * Initial value of Instruction Pointer (IP) register | |
| */ | |
| uint16_t initial_ip_register_value; /* 0x14 */ | |
| /** | |
| * Initial value of Code Segment (CS) register | |
| */ | |
| uint16_t initial_cs_register_value; /* 0x16 */ | |
| /** | |
| * Offset of the first relocation table | |
| */ | |
| uint16_t relocation_table_offset; /* 0x18 */ | |
| /** | |
| * Overlay number (mostly this is zero, meaning that this is the main program) | |
| */ | |
| uint16_t overlay_number; /* 0x1A */ | |
| } DOSExeHeader; | |
| /** | |
| * Read DOS header from the binary file. | |
| * | |
| * @param[in,out] header Header structure to fill up | |
| * @param[in] filename Name of the binary file to read DOS header from | |
| */ | |
| void readHeader(DOSExeHeader *const header, const char *filename); | |
| /** | |
| * Print the contents of the DOS header. | |
| * | |
| * @param[in] header Header structure to display | |
| */ | |
| void printHeader(const DOSExeHeader *const header); | |
| int main(int argc, char const *argv[]) | |
| { | |
| if (argc < 2) | |
| { | |
| printf("Usage: %s <name of your DOS executable>\n", argv[0]); | |
| return 1; | |
| } | |
| DOSExeHeader header; | |
| readHeader(&header, argv[1]); | |
| printHeader(&header); | |
| return 0; | |
| } | |
| void readHeader(DOSExeHeader *const header, const char *filename) | |
| { | |
| FILE *fp = fopen(filename, "rb"); | |
| if (!fp) | |
| { | |
| fprintf(stderr, "Error: Unable to read file.\n"); | |
| exit(1); | |
| } | |
| readUint16(&header->id_signature, fp); | |
| readUint16(&header->last_block_bytes_count, fp); | |
| readUint16(&header->file_block_count, fp); | |
| readUint16(&header->relocation_entry_count, fp); | |
| readUint16(&header->header_paragraphs_count, fp); | |
| readUint16(&header->min_required_memory, fp); | |
| readUint16(&header->max_required_memory, fp); | |
| readUint16(&header->stack_segment_offset, fp); | |
| readUint16(&header->initial_sp_register_value, fp); | |
| readUint16(&header->checksum, fp); | |
| readUint16(&header->initial_ip_register_value, fp); | |
| readUint16(&header->initial_cs_register_value, fp); | |
| readUint16(&header->relocation_table_offset, fp); | |
| readUint16(&header->overlay_number, fp); | |
| fclose(fp); | |
| } | |
| void printHeader(const DOSExeHeader *const header) | |
| { | |
| printf("ID signature (usually 'MZ', otherwise 0x5a4d): 0x%04x\n", /* TODO: Print as string */ | |
| header->id_signature, | |
| header->id_signature); | |
| printf("Number of bytes in last block: %d\n", header->last_block_bytes_count); | |
| printf("Number of 512-byte blocks in file: %d\n", header->file_block_count); | |
| printf("Number of relocation entries: %d\n", header->relocation_entry_count); | |
| printf("Number of paragraphs in header: %d\n", header->header_paragraphs_count); | |
| printf("Minimum required memory in paragraphs: %d\n", header->min_required_memory); | |
| printf("Maximum required memory in paragraphs: %d\n", header->max_required_memory); | |
| printf("Stack segment offset: 0x%08x\n", header->stack_segment_offset); | |
| printf("Initial value of Stack Pointer (SP) register: 0x%08x\n", header->initial_sp_register_value); | |
| printf("File checksum: 0x%08x\n", header->checksum); | |
| printf("Initial value of Instruction Pointer (IP) register: 0x%08x\n", header->initial_ip_register_value); | |
| printf("Initial value of Code Segment (CS) register: 0x%08x\n", header->initial_cs_register_value); | |
| printf("Offset of the first relocation table: 0x%08x\n", header->relocation_table_offset); | |
| printf("Overlay number (mostly this is zero, meaning that this is the main program): %d\n", header->overlay_number); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment