From f2df25ca202300fe04672703ea7fb30d8431b302 Mon Sep 17 00:00:00 2001
From: Dirk Engling <erdgeist@erdgeist.org>
Date: Sun, 12 Jan 2014 22:07:32 +0100
Subject: Make extract code for old phone books much more generic and detect
 necessary values automatically

---
 src/extractblocks_new.c | 121 ++++++++++++++++++++++++++++++++----------------
 1 file changed, 80 insertions(+), 41 deletions(-)

diff --git a/src/extractblocks_new.c b/src/extractblocks_new.c
index 94ab0b7..53c16f2 100644
--- a/src/extractblocks_new.c
+++ b/src/extractblocks_new.c
@@ -5,76 +5,115 @@
 #include <stdint.h>
 #include <unistd.h>
 
+/* lha header:
+
+00 Header length
+01 Header checksum [02-length]
+02 0x2d  ('-')
+03 0x6c  ('l')
+04 0x68  ('h')
+05 0x??  ('0' or '5') unsure
+06 0x2d  ('-')
+07 0x??  LSB of compressed size
+08 0x??  ..
+09 0x00  ..
+10 0x00  MSB of compressed size, i.e. 0
+..
+21       Length of path name
+
+
+*/
+
+static uint8_t mantra_in[] = { 0x68, 0x00, 0x2d, 0x6c };
+
 int main( int args, char **argv )
 {
-  int      filenum = 0;
-  size_t   offset = 0, oldoffset = -1;
-  uint8_t *mappedfile;
+  int      filenum = 0, run = 1;
+  size_t   offset = 0, oldoffset = -1, enc_len = 32;
+  uint8_t  mantra[4], id0, id5, *mappedfile;
   MAP      map;
 
-  uint8_t mantra0 = 0x1b, mantra1 = 0x35, mantra2 = 0x2d, mantra3 = 0x6c; /* clean*/
-//  unsigned char mantra0 = 0x08, mantra1 = 0x57, mantra2 = 0x64, mantra3 = 0x69; /* 98 H */
-//  unsigned char mantra0 = 0x13, mantra1 = 0xe4, mantra2 = 0x55, mantra3 = 0x05; /* 99 F */
-//  unsigned char mantra0 = 0x12, mantra1 = 0x08, mantra2 = 0x23, mantra3 = 0x01; /* 99 H */
+  /* For streets we do have a enc_len of 34 */
+  while( run ) {
+    switch( getopt( args, argv, ":e:" ) ) {
+      case -1 : run = 0; break;
+      case 'e':
+        enc_len = atol( optarg );
+        break;
+      default:
+        fputs( "Syntax: %s [-e encrypted_length (default: 32, for streets 34 or 0)] path-to-teiln.dat", stderr ); exit( 1 );
+        break;
+    }
+  }
+  run = 1;
 
-  if( args != 2 )
-    { fputs( "Missing filenames.", stderr ); exit( 1 ); }
+  if( optind == args  )
+    { fputs( "Missing filename.", stderr ); exit( 1 ); }
 
-  map = map_file( argv[1], 1 );
+  map = map_file( argv[optind], 1 );
   mappedfile = map->addr;
 
-  mantra0 ^= mappedfile[0];
-  mantra1 ^= mappedfile[5];
-  mantra2 ^= mappedfile[2];
-  mantra3 ^= mappedfile[3];
+  mantra[0] = mantra_in[0] ^ mappedfile[4];
+  mantra[1] = mantra_in[1] ^ mappedfile[9];
+  mantra[2] = mantra_in[2] ^ mappedfile[2];
+  mantra[3] = mantra_in[3] ^ mappedfile[3];
+
+  id0 = mappedfile[0];
+  id5 = mappedfile[5];
 
-  while( 1 )
+  while( run )
   {
     while( ( offset < map->size ) && (
-           ( mappedfile[ offset + 0 ] != ( 0x1b^ mantra0 )) ||
-           ( mappedfile[ offset + 2 ] != ( '-' ^ mantra2 )) ||
-           ( mappedfile[ offset + 3 ] != ( 'l' ^ mantra3 )) ||
-           ( mappedfile[ offset + 4 ] != ( 'h' ^ mantra0 )) ||
-           ( mappedfile[ offset + 5 ] != ( '5' ^ mantra1 )) ||
-           ( mappedfile[ offset + 6 ] != ( '-' ^ mantra2 ))
+           ( mappedfile[ offset + 0 ] != id0                         ) ||
+           ( mappedfile[ offset + 2 ] != ( '-'          ^ mantra[2] )) ||
+           ( mappedfile[ offset + 3 ] != ( 'l'          ^ mantra[3] )) ||
+           ( mappedfile[ offset + 4 ] != ( 'h'          ^ mantra[0] )) ||
+           ( mappedfile[ offset + 5 ] != id5                         ) ||
+           ( mappedfile[ offset + 6 ] != ( '-'          ^ mantra[2] ))
           ) ) offset++;
 
-    printf( "Found an appropriate offset at: %zd\n", oldoffset );
+    printf( "Found an appropriate offset at: %zd\n", offset );
 
     if( offset == map->size )
-    {
-        unmap_file( &map );
-        exit(0);
-    }
+        run = 0;
 
     if( oldoffset != -1 )
     {
-        uint8_t cs = 0, *mf = mappedfile + oldoffset, df[32];
-        char filename[20];
+        uint8_t *mf = mappedfile + oldoffset, df[128];
+        size_t filename_len, header_len;
+        char filename_template[32], filename[32];
         int i;
 
-        for( i=0; i<8; ++i)
-        {
-           df[4*i+0] = mf[4*i+0] ^ mantra0;
-           df[4*i+1] = mf[4*i+1] ^ mantra1;
-           df[4*i+2] = mf[4*i+2] ^ mantra2;
-           df[4*i+3] = mf[4*i+3] ^ mantra3;
-        }
+        /* De-"crypt" obfuscation to our header copy */
+        for( i=0; i<enc_len; ++i)
+           df[i] = mf[i] ^ mantra[i%4];
+
+        /* Get values from LHA header */
+        header_len = df[0];
+        filename_len = df[21];
+
+        /* Copy rest of header, so we can checksum */
+        for( i=enc_len; i<header_len+2; ++i)
+           df[i] = mf[i];
 
-        snprintf( filename, sizeof( filename ), "%05d.lha", filenum++ );
-        memcpy( ((uint8_t*)df) + 22, filename, 5);
+        /* Make up new sequental file name */
+        snprintf( filename_template, sizeof(filename_template), "%%0%dd.lha", (int)filename_len );
+        snprintf( filename, sizeof( filename ), filename_template, filenum++ );
+        memcpy( ((uint8_t*)df) + 22, filename, filename_len);
 
-        for( i=2; i<29; ++i) cs += ((uint8_t*)df)[i];
-        ((uint8_t*)df)[1] = cs;
+        /* Recalculate checksum with new file name */
+        df[1] = 0; for( i=2; i<header_len+2; ++i) df[1] += df[i];
 
+        /* Open file and dump our de-"crypted" header and then rest of file */
         i = open( filename, O_CREAT | O_TRUNC | O_WRONLY, 0644 );
-        write( i, df, 32 );
-        write( i, mf + 32, offset - oldoffset - 32 );
+        write( i, df, enc_len );
+        write( i, mf + enc_len, offset - oldoffset - enc_len );
         close( i );
     }
     oldoffset = offset;
     offset++;
   }
 
+  unmap_file( &map );
   return 0;
 }
-- 
cgit v1.2.3