1 /*
2  * main.c
3  *
4  * This file contains the main() function of the PkZip-cracker.
5  * It reads the ciphertext and plaintext files and makes calls to the
6  * actual cracking stages.
7  *
8  * (C) by Peter Conrad <conrad@unix-ag.uni-kl.de>
9  *
10  * $Id: main.c,v 1.15 2002/11/12 16:58:02 lucifer Exp $
11  *
12  * $Log: main.c,v $
13  * Revision 1.15  2002/11/12 16:58:02  lucifer
14  * Fixed typo
15  *
16  * Revision 1.14  2002/11/02 15:12:06  lucifer
17  * Integrated RElf's changes (with small mods) from fix2.zip
18  *
19  * Revision 1.14  2002/10/25 17:51:20  RElf
20  * Removed call to initStage3Tab()
21  *
22  * Revision 1.13  2002/01/30 14:35:44  lucifer
23  * Removed DEBUG_KEYS stuff
24  * Incorporated changes by RElf
25  *
26  * Revision 1.12  1999/01/20 20:21:44  lucifer
27  * string.h included
28  *
29  * Revision 1.11  1998/05/08 16:59:20  lucifer
30  * added DEBUG_KEYS stuff to check some improvements
31  *
32  * Revision 1.10.2.1  2002/01/22 20:08:46  lucifer
33  * Change by RElf:
~factory_entryboost::geometry::projections::detail::factory_entry34  * Implemented new options -a and -n
35  *
36  * Revision 1.10  1997/09/23 20:07:31  lucifer
37  * Removed declaration of strdup
38  *
39  * Revision 1.9  1997/09/23 17:33:22  lucifer
40  * Added option -i.
41  * Minor modification of output.
42  *
43  * Revision 1.8  1997/09/18 18:17:22  lucifer
44  * Added comment and patches for windows
45  *
46  * Revision 1.7  1996/08/21 18:14:34  conrad
47  * Some cleanups to suppress some warnings...
48  *
49  * Revision 1.6  1996/08/21 17:36:46  conrad
50  * Added options -C -P -d
51  *
52  * Revision 1.4  1996/08/13 13:17:02  conrad
53  * Parameter list changed to support -o, -c and -p instead of fixed scheme
54  * Modifications to support plaintext in the middle of the ciphertext with
55  * offset (-o). Incomplete, works only if offset+plainlength<MAXFILELEN
56  *
57  * Revision 1.3  1996/06/23 10:36:15  lucifer
58  * Modification for DJGPP: key2i is now allocated dynamically
59  * For improved efficiency we now remember the lowest number of key2i-
60  * values and start stage2 using those.
61  *
62  * Revision 1.2  1996/06/12  09:47:13  conrad
63  * Release version
64  *
65  * Revision 1.1  1996/06/10 17:50:20  conrad
66  * Initial revision
67  *
68  */
69 
70 static char RCSID[]="$Id: main.c,v 1.15 2002/11/12 16:58:02 lucifer Exp $";
71 
72 #include <time.h>
73 #include <stdio.h>
74 
75 #ifndef _WIN32
76 #include <unistd.h>
77 #else
78 #include <io.h>
79 #endif
80 
81 #include <sys/stat.h>
82 #include <fcntl.h>
83 #include <stdlib.h>
84 #include <string.h>
85 
86 #include "pkctypes.h"
87 #include "crc.h"
88 #include "mktmptbl.h"
89 #include "stage1.h"
90 #include "pkcrack.h"
91 #include "stage2.h"
92 #include "stage3.h"
93 #include "headers.h"
94 
95 extern int zipdecrypt( char *infile,char *outfile, int k0, int k1, int k2 );
96 
97 #ifndef O_BINARY
98 #define	O_BINARY	0
99 #endif
100 
101 #define	GOODNUM		1000
102 #define	VERYGOOD	100
103 
104 extern	byte	*extract(char*, char*, int caseflg);
105 
106 byte	*plaintext, *ciphertext;
107 uword	*key2i;
108 
109 static uword bestKey2i[GOODNUM];
110 
111 int	numKey2s=0;
112 
113 static int bestNum=GOODNUM;
114 
115 int	bestOffset;
116 
117 static void usage( char *myself )
118 {
119     fprintf( stderr, "Usage: %s -c <crypted_file> -p <plaintext_file> [other_options],\n", myself );
120     fprintf( stderr, "where [other_options] may be one or more of\n" );
121     fprintf( stderr, " -o <offset>\tfor an offset of the plaintext into the ciphertext,\n\t\t\t(may be negative)\n" );
122     fprintf( stderr, " -C <c-ZIP>\twhere c-ZIP is a ZIP-archive containing <crypted_file>\n" );
123     fprintf( stderr, " -P <p-ZIP>\twhere p-ZIP is a ZIP-archive containing <plaintext_file>\n" );
124     fprintf( stderr, " -d <d-file>\twhere d-file is the name of the decrypted archive which\n\t\twill be created by this program if the correct keys are found\n\t\t(can only be used in conjunction with the -C option)\n" );
125     fprintf( stderr, " -i\tswitch off case-insensitive filename matching in ZIP-archives\n" );
126     fprintf( stderr, " -a\tabort keys searching after first success\n" );
127     fprintf( stderr, " -n\tno progress indicator\n" );
128 }
129 
130 int main( int argc, char **argv )
131 {
132 int		crypt, plain, cryptlength, plainlength;
133 struct stat	filestat;
134 time_t		now;
135 int		i, offset=12, caseflg=0, sabort=0, noprogress=0;
136 char		*cryptname=NULL, *plainname=NULL;
137 char		*cFromZIP=NULL, *pFromZIP=NULL, *decryptName=NULL;
138 
139     for( i = 1; i < argc; i++ )
140     {
141 	if( !strcmp( "-o", argv[i] ) )
142 	{ /* offset */
143 	    offset += atoi( argv[++i] );
144 	}
145 	else if( !strcmp( "-c", argv[i] ) )
146 	{ /* ciphertext filename */
147 	    cryptname = argv[++i];
148 	}
149 	else if( !strcmp( "-p", argv[i] ) )
150 	{ /* plaintext filename */
151 	    plainname = argv[++i];
152 	}
153 	else if( !strcmp( "-C", argv[i] ) )
154 	{ /* ciphertext-ZIPfilename */
155 	    cFromZIP = argv[++i];
156 	}
157 	else if( !strcmp( "-P", argv[i] ) )
158 	{ /* plaintext-ZIPfilename */
159 	    pFromZIP = argv[++i];
160 	}
161 	else if( !strcmp( "-d", argv[i] ) )
162 	{ /* name of decrypted ZIP-archive */
163 	    decryptName = argv[++i];
164 	}
165 	else if( !strcmp( "-i", argv[i] ) )
166 	{ /* case-insensitive filename */
167 	    caseflg = FLG_CASE_SENSITIVE;
168         }
169         else if( !strcmp( "-a", argv[i] ) )
170 	{ /* abort searching on success */
171 	    sabort = 1;
172         }
173         else if( !strcmp( "-n", argv[i] ) )
174 	{ /* no progress indicator */
175 	    noprogress = 1;
176         }
177     }
178     if( !cryptname || !plainname )
179     {
180 	usage( argv[0] );
181 	exit(1);
182     }
183     if( decryptName && !cFromZIP )
184     {
185 	usage( argv[0] );
186 	exit(1);
187     }
188 
189     key2i = malloc( sizeof(uword)*KEY2SPACE );
190     if( !key2i )
191     {
192 	fprintf( stderr, "Sorry, not enough memory available.\n" );
193 	exit(1);
194     }
195 
196     if( !cFromZIP )
197     {
198 	crypt = open( cryptname, O_RDONLY | O_BINARY );
199 	if( crypt == -1 )
200 	{
201 	    fprintf( stderr, "Cryptfile %s not found!\n", argv[1] );
202 	    exit(1);
203 	}
204 	fstat( crypt, &filestat );
205 	cryptlength = filestat.st_size;
206 	ciphertext = malloc( cryptlength );
207     }
208     else
209     {
210 	ciphertext = extract( cFromZIP, cryptname, caseflg );
211 	if( !ciphertext )
212 	    exit(1);
213 	cryptlength = lh.csize;
214     }
215 
216     if( !pFromZIP )
217     {
218 	plain = open( plainname, O_RDONLY | O_BINARY );
219 	if( plain == -1 )
220 	{
221 	    fprintf( stderr, "Plaintextfile %s not found!\n", argv[2] );
222 	    exit(1);
223 	}
224 	fstat( plain, &filestat );
225 	plainlength = filestat.st_size;
226 	plaintext = malloc( plainlength + offset );
227     }
228     else
229     {
230 	plaintext = extract( pFromZIP, plainname, caseflg );
231 	if( !plaintext )
232 	    exit(1);
233 	plainlength = lh.csize;
234 	plaintext -= offset;
235     }
236 
237     if( plainlength > cryptlength-offset )
238     {
239 	fprintf( stderr, "Warning! Plaintext is longer than Ciphertext!\n" );
240     }
241     if( plainlength < 13 )
242     {
243 	fprintf( stderr, "Plaintext must be at least 13 bytes! Aborting.\n" );
244 	exit(1);
245     }
246 
247     cryptlength = plainlength + offset;
248     if( !ciphertext || !plaintext )
249     {
250 	fprintf( stderr, "Not enough memory!\n" );
251 	exit(1);
252     }
253     if( !cFromZIP && read( crypt, ciphertext, cryptlength ) !=  cryptlength )
254     {
255 	fprintf( stderr, "Couldn't read ciphertext!\n" );
256 	exit(1);
257     }
258     if( !pFromZIP && read( plain, &plaintext[offset], plainlength ) != plainlength )
259     {
260 	fprintf( stderr, "Couldn't read plaintext!\n" );
261 	exit(1);
262     }
263     if( !pFromZIP )
264 	close( plain );
265     if( !cFromZIP )
266 	close( crypt );
267 
268     now = time(NULL);
269     fprintf( stderr, "Files read. Starting stage 1 on %s", ctime(&now) );
270 
271     preCompTemp();
272     mkCrcTab();
273     initMulTab();
274 
275     generate1stSetOfKey2s( cryptlength-1 );
276     fprintf( stderr, "Now we're trying to reduce these...\n" );
277     fflush( stderr );
278     for( i = cryptlength-1; i >= offset+13 && numKey2s > 0 && bestNum > VERYGOOD; i-- )
279     {
280         if(!noprogress)
281         {
282             fprintf( stderr, "Reducing number of keys... %3.1f%%\r", 100.*(cryptlength-i)/(cryptlength-offset-13) );
283 /*            fflush( stderr ); */
284         }
285 	reduceKey2s( i );
286 	if( numKey2s < bestNum )
287 	{
288 	    memcpy( bestKey2i, key2i, sizeof(uword)*numKey2s );
289 	    bestNum = numKey2s;
290 	    bestOffset = i-1;
291 	    fprintf( stderr, "Lowest number: %d values at offset %d\n", bestNum, bestOffset );
292 	    fflush( stderr );
293 	}
294     }
295 
296     if( bestNum < GOODNUM )
297     {
298 	memcpy( key2i, bestKey2i, sizeof(uword)*bestNum );
299 	numKey2s = bestNum;
300     }
301     else
302 	bestOffset = i;
303 
304     printf( "Done. Left with %d possible Values. bestOffset is %d.\n", numKey2s, bestOffset );
305     fflush( stdout );
306 
307     now = time(NULL);
308     fprintf( stderr, "Stage 1 completed. Starting stage 2 on %s", ctime(&now) );
309 
310     for( i = 0; i < numKey2s; i++ )
311     {
312         if(!noprogress)
313         {
314             fprintf( stderr, "Searching... %3.1f%%\r",100.*i/numKey2s);
315 /*            fflush( stderr ); */
316         }
317         buildKey2Lists( key2i[i], cryptlength-bestOffset, offset );
318         if( sabort && got_keys ) break;
319     }
320 
321 
322     now = time(NULL);
323     fprintf( stderr, "Stage 2 completed. Starting %s on %s",
324 		decryptName?"zipdecrypt":"password search", ctime(&now) );
325 
326     if( !got_keys )
327 	printf( "No solutions found. You must have chosen the wrong plaintext.\n" );
328     else if( !decryptName )
329 	findPwd( loesung0, loesung1, loesung2 );
330     else
331 	zipdecrypt( cFromZIP, decryptName, loesung0, loesung1, loesung2 );
332 
333     now = time(NULL);
334     fprintf( stderr, "Finished on %s", ctime(&now) );
335 
336     return(0);
337 }
338