summaryrefslogtreecommitdiff
path: root/src/extractblocks_new.c
blob: 580d3adddaaedee15130d48d82abdb3d9e257bf9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include <fcntl.h>
#include "mystdlib.h"
#include <stdlib.h>
#include <string.h>
#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, 0x35, 0x2d, 0x6c };

int main( int args, char **argv )
{
  int      filenum = 0, run = 1;
  size_t   offset = 0, oldoffset = -1, enc_len = 32;
  uint8_t  mantra[4], id0, id5, *mappedfile;
  MAP      map;

  /* 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( optind == args  )
    { fputs( "Missing filename.", stderr ); exit( 1 ); }

  map = map_file( argv[optind], 1 );
  mappedfile = map->addr;

  mantra[0] = mantra_in[0] ^ mappedfile[4];
  mantra[1] = mantra_in[1] ^ mappedfile[5];
  mantra[2] = mantra_in[2] ^ mappedfile[2];
  mantra[3] = mantra_in[3] ^ mappedfile[3];

  id0 = mappedfile[0];
  id5 = mappedfile[5];

  while( run )
  {
    while( ( offset < map->size ) && (
           ( 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", offset );

    if( offset == map->size )
        run = 0;

    if( oldoffset != -1 )
    {
        uint8_t *mf = mappedfile + oldoffset, df[128];
        size_t filename_len, header_len;
        char filename_template[32], filename[32];
        int i;

        /* 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] + 2;
        filename_len = df[21];

        /* Copy rest of header, so we can checksum */
        for( i=enc_len; i<header_len; ++i)
           df[i] = mf[i];

        /* 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);

        /* Recalculate checksum with new file name */
        df[1] = 0; for( i=2; i<header_len; ++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 );
        if( enc_len > header_len ) {
            write( i, df, enc_len );
            write( i, mf + enc_len, offset - oldoffset - enc_len );
        } else {
            write( i, df, header_len );
            write( i, mf + header_len, offset - oldoffset - header_len );
        }
        close( i );
    }
    oldoffset = offset;
    offset++;
  }

  unmap_file( &map );
  return 0;
}