Skip to content

Instantly share code, notes, and snippets.

@balintkissdev
Last active July 20, 2017 19:43
Show Gist options
  • Select an option

  • Save balintkissdev/e6b3a00c5a9051591f0bb3f6081d0413 to your computer and use it in GitHub Desktop.

Select an option

Save balintkissdev/e6b3a00c5a9051591f0bb3f6081d0413 to your computer and use it in GitHub Desktop.
/**
* 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