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;
}
|