/* APN ELF file Checksum generator * For hacking the Chrysler/Dodge/Jeep Alpine navigation systems. * Works with REC, RB1 and REJ units. May work with any Alpine system using ELF files for the firmware. Notes: Initial version 0.1 10/1/2006 - Vindes Tried to keep the code a simple as possible for platform and language portability. */ #include #include main (argc, argv) int argc; char ** argv; { FILE * apnfile; /* ELF header stuff - words and half words */ unsigned int phdr_start, shdr_start; unsigned short ph_num, sh_size, sh_num; /* program header variables. Program headers are 32 bytes each */ unsigned int p_type; /* entry type */ unsigned int p_offset; /* file offset - start of section in file */ unsigned int p_vaddr; /* virtual address - where it goes in memory - ignore if 0 */ unsigned int p_paddr; /* physical address - always zero for NAV */ unsigned int p_filesz; /* file size - size on disc */ unsigned int p_memsz; /* memory size - size in memory, may be larger than on disc */ unsigned int p_flags; /* entry flags */ unsigned int p_align; /* memory/file alignment */ /* misc variables */ unsigned int chksum_table_start, offset, size, checksum, addon, file_chksum; int section, wordcount, bytecount, shift; unsigned char *progsegment; /* Take filename from first command line arg */ apnfile = fopen (argv[1], "r"); /* seek 28 bytes in to find offset for program headers and section headers */ fseek (apnfile, 28, SEEK_SET); fread (&phdr_start, sizeof(phdr_start), 1, apnfile); fread (&shdr_start, sizeof(shdr_start), 1, apnfile); /* seek 44 bytes in for number of program headers, num sec. hdrs and size of sec hdrs */ fseek (apnfile, 44, SEEK_SET); fread (&ph_num, sizeof(ph_num), 1, apnfile); fread (&sh_size, sizeof(sh_size), 1, apnfile); fread (&sh_num, sizeof(sh_num), 1, apnfile); /* Alpine special junk section is past end of section headers. So add # headers * size of headers to starting offset of section headers. Checksum table is 76 bytes past that. */ chksum_table_start = shdr_start + sh_size*sh_num + 76; /* Header for output table */ printf ("Section\tChecksum\tFile says\n"); /* Loop through program sections, generating checksums */ for (section=0; section <= ph_num; section++) { /* Load program header for current section. Each program header is 32 bytes */ fseek (apnfile, phdr_start + section*32, SEEK_SET); fread (&p_type, 4, 1, apnfile); fread (&p_offset, 4, 1, apnfile); fread (&p_vaddr, 4, 1, apnfile); fread (&p_paddr, 4, 1, apnfile); fread (&p_filesz, 4, 1, apnfile); fread (&p_memsz, 4, 1, apnfile); fread (&p_flags, 4, 1, apnfile); /* seek to, and load segment into memory for checksum calculation - if it's a loadable segment */ if ((p_vaddr > 0)) { fseek (apnfile, p_offset, SEEK_SET); /* seek to location of segment */ progsegment = malloc(p_filesz); /* allocate bytes to read into */ fread (progsegment, 1, p_filesz, apnfile); /* read into progsegment */ checksum=0; /* Calculate the checksum of the segment */ for (bytecount=0; bytecount < p_filesz; bytecount++) { shift = (bytecount&3)*8; /* doing it byte by byte, shifting each byte appropriately */ addon = progsegment[bytecount]; addon<<=shift; checksum=checksum + addon; } /* free up the space we allocated */ free (progsegment); /* Load the checksum stored in the file */ fseek (apnfile, chksum_table_start + section*4, SEEK_SET); fread (&file_chksum, 4, 1, apnfile); printf ("%2.2i\t0x%8.8x\t0x%8.8x\t", section, checksum, file_chksum); if (checksum == file_chksum) { printf("match\n"); } else { printf("DIFFERENT\n"); } } } }